You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cloudstack.apache.org by se...@apache.org on 2014/03/24 16:00:22 UTC
git commit: updated refs/heads/4.4 to a5510a0
Repository: cloudstack
Updated Branches:
refs/heads/4.4 18934345a -> a5510a0a0
cloudstack api post and ssl fix
Signed-off-by: Sebastien Goasguen <ru...@gmail.com>
Project: http://git-wip-us.apache.org/repos/asf/cloudstack/repo
Commit: http://git-wip-us.apache.org/repos/asf/cloudstack/commit/a5510a0a
Tree: http://git-wip-us.apache.org/repos/asf/cloudstack/tree/a5510a0a
Diff: http://git-wip-us.apache.org/repos/asf/cloudstack/diff/a5510a0a
Branch: refs/heads/4.4
Commit: a5510a0a0aadf711b88ab5687484b1096c91e084
Parents: 1893434
Author: Dmitry Batkovich <ba...@gmail.com>
Authored: Mon Mar 24 18:46:45 2014 +0400
Committer: Sebastien Goasguen <ru...@gmail.com>
Committed: Mon Mar 24 16:00:13 2014 +0100
----------------------------------------------------------------------
.../src/com/cloud/bridge/util/JsonAccessor.java | 248 -------------------
.../com/cloud/bridge/util/JsonElementUtil.java | 45 ++++
.../cloud/stack/CloudStackClientException.java | 21 ++
.../src/com/cloud/stack/CloudStackCommand.java | 149 -----------
.../com/cloud/stack/CloudStackQueryBuilder.java | 118 +++++++++
.../cloud/gate/util/JsonAccessorTestCase.java | 69 ------
.../gate/util/JsonElementUtilTestCase.java | 48 ++++
7 files changed, 232 insertions(+), 466 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/a5510a0a/awsapi/src/com/cloud/bridge/util/JsonAccessor.java
----------------------------------------------------------------------
diff --git a/awsapi/src/com/cloud/bridge/util/JsonAccessor.java b/awsapi/src/com/cloud/bridge/util/JsonAccessor.java
deleted file mode 100644
index 2a94dea..0000000
--- a/awsapi/src/com/cloud/bridge/util/JsonAccessor.java
+++ /dev/null
@@ -1,248 +0,0 @@
-// Licensed to the Apache Software Foundation (ASF) under one
-// or more contributor license agreements. See the NOTICE file
-// distributed with this work for additional information
-// regarding copyright ownership. The ASF licenses this file
-// to you under the Apache License, Version 2.0 (the
-// "License"); you may not use this file except in compliance
-// with the License. You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing,
-// software distributed under the License is distributed on an
-// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-// KIND, either express or implied. See the License for the
-// specific language governing permissions and limitations
-// under the License.
-package com.cloud.bridge.util;
-
-import java.math.BigDecimal;
-import java.math.BigInteger;
-import java.util.ArrayList;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-import com.google.gson.JsonArray;
-import com.google.gson.JsonElement;
-import com.google.gson.JsonObject;
-import com.google.gson.JsonPrimitive;
-
-import com.cloud.bridge.service.exception.InternalErrorException;
-
-/**
- * JsonAccessor provides the functionality to allow navigating JSON object graph using simple expressions,
- * for example, following property access expressions are all valid ones
- *
- * rootobj.level1obj[1].property
- * this[0].level1obj[1].property
- *
- */
-public class JsonAccessor {
- private JsonElement _json;
-
- Pattern _arrayAccessorMatcher = Pattern.compile("(.*)\\[(\\d+)\\]");
-
- public JsonAccessor(JsonElement json) {
- assert (json != null);
- _json = json;
- }
-
- public BigDecimal getAsBigDecimal(String propPath) {
- JsonElement jsonElement = eval(propPath);
- return jsonElement.getAsBigDecimal();
- }
-
- public BigInteger getAsBigInteger(String propPath) {
- JsonElement jsonElement = eval(propPath);
- return jsonElement.getAsBigInteger();
- }
-
- public boolean getAsBoolean(String propPath) {
- JsonElement jsonElement = eval(propPath);
- return jsonElement.getAsBoolean();
- }
-
- public byte getAsByte(String propPath) {
- JsonElement jsonElement = eval(propPath);
- return jsonElement.getAsByte();
- }
-
- public char getAsCharacter(String propPath) {
- JsonElement jsonElement = eval(propPath);
- return jsonElement.getAsCharacter();
- }
-
- public double getAsDouble(String propPath) {
- JsonElement jsonElement = eval(propPath);
- return jsonElement.getAsDouble();
- }
-
- public float getAsFloat(String propPath) {
- JsonElement jsonElement = eval(propPath);
- return jsonElement.getAsFloat();
- }
-
- public int getAsInt(String propPath) {
- JsonElement jsonElement = eval(propPath);
- return jsonElement.getAsInt();
- }
-
- public long getAsLong(String propPath) {
- JsonElement jsonElement = eval(propPath);
- return jsonElement.getAsLong();
- }
-
- public Number getAsNumber(String propPath) {
- JsonElement jsonElement = eval(propPath);
- return jsonElement.getAsNumber();
- }
-
- public short getAsShort(String propPath) {
- JsonElement jsonElement = eval(propPath);
- return jsonElement.getAsShort();
- }
-
- public String getAsString(String propPath) {
- JsonElement jsonElement = eval(propPath);
- return jsonElement.getAsString();
- }
-
- public boolean isBoolean(String propPath) {
- JsonElement jsonElement = eval(propPath);
- if (jsonElement instanceof JsonPrimitive)
- return ((JsonPrimitive)jsonElement).isBoolean();
-
- return false;
- }
-
- public boolean isNumber(String propPath) {
- JsonElement jsonElement = eval(propPath);
-
- if (jsonElement instanceof JsonPrimitive)
- return ((JsonPrimitive)jsonElement).isNumber();
- return false;
- }
-
- public boolean isString(String propPath) {
- JsonElement jsonElement = eval(propPath);
-
- if (jsonElement instanceof JsonPrimitive)
- return ((JsonPrimitive)jsonElement).isString();
- return false;
- }
-
- /*
- * Return
- * -1 : property expression can not be resolved
- * 0 : match to a null JSON object
- * 1+ : matched, for array element, the count of the elements inside the array
- */
- public int getMatchCount(String propPath) {
- JsonElement jsonElement = tryEval(propPath);
- if (jsonElement == null)
- return -1;
-
- if (jsonElement.isJsonNull())
- return 0;
-
- if (jsonElement.isJsonArray())
- return ((JsonArray)jsonElement).size();
-
- return 1;
- }
-
- public JsonElement eval(String propPath) {
- JsonElement jsonElement = tryEval(propPath);
- if (jsonElement == null)
- throw new InternalErrorException("Property " + propPath + " is resolved to null JSON element on object: " + _json.toString());
-
- return jsonElement;
- }
-
- public JsonElement tryEval(String propPath) {
- assert (propPath != null);
- String[] tokens = propPath.split("\\.");
-
- ArrayList<Resolver> resolverChain = new ArrayList<Resolver>();
- for (String token : tokens) {
- Matcher matcher = _arrayAccessorMatcher.matcher(token);
- if (matcher.find()) {
- String propStr = matcher.group(1);
- String indexStr = matcher.group(2);
-
- resolverChain.add(new ArrayPropertyResolver(propStr, Integer.parseInt(indexStr)));
- } else {
- resolverChain.add(new PropertyResolver(token));
- }
- }
-
- JsonElement jsonElementToResolveAt = _json;
- for (Resolver resolver : resolverChain) {
- jsonElementToResolveAt = resolver.resolve(jsonElementToResolveAt);
-
- if (jsonElementToResolveAt == null)
- break;
- }
-
- return jsonElementToResolveAt;
- }
-
- //
- // Property resolvers
- //
- private static interface Resolver {
- public JsonElement resolve(JsonElement jsonElementToResolveAt);
- }
-
- private static class PropertyResolver implements Resolver {
- protected String _propName;
-
- public PropertyResolver(String propName) {
- _propName = propName;
- }
-
- public JsonElement resolve(JsonElement jsonElementToResolveAt) {
- if ("this".equals(_propName))
- return jsonElementToResolveAt;
-
- if (jsonElementToResolveAt.isJsonObject())
- return ((JsonObject)jsonElementToResolveAt).get(_propName);
-
- if (jsonElementToResolveAt.isJsonNull())
- throw new NullPointerException(String.format("Property %s points to a null element on object: %s", _propName, jsonElementToResolveAt.toString()));
-
- throw new InternalErrorException("Unable to evaluate JSON accessor property: " + _propName + ", on object: " + jsonElementToResolveAt.toString());
- }
- }
-
- private static class ArrayPropertyResolver extends PropertyResolver {
- protected int _index;
-
- public ArrayPropertyResolver(String propName, int index) {
- super(propName);
- _index = index;
- }
-
- public JsonElement resolve(JsonElement jsonElementToResolveAt) {
- if (!"this".equals(_propName)) {
- if (jsonElementToResolveAt.isJsonObject()) {
- jsonElementToResolveAt = ((JsonObject)jsonElementToResolveAt).get(_propName);
- } else {
- if (jsonElementToResolveAt.isJsonNull())
- throw new NullPointerException(String.format("Property %s points to a null element on object: %s", _propName, jsonElementToResolveAt.toString()));
-
- throw new InternalErrorException("Unable to evaluate JSON accessor property: " + _propName + ", on object: " + jsonElementToResolveAt.toString());
- }
- }
-
- if (jsonElementToResolveAt instanceof JsonArray) {
- return ((JsonArray)jsonElementToResolveAt).get(_index);
- }
-
- if (jsonElementToResolveAt.isJsonNull())
- throw new NullPointerException(String.format("Property %s points to a null element on object: %s", _propName, jsonElementToResolveAt.toString()));
-
- throw new InternalErrorException("Unable to evaluate JSON accessor property: " + _propName + ", on object: " + jsonElementToResolveAt.toString());
- }
- }
-}
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/a5510a0a/awsapi/src/com/cloud/bridge/util/JsonElementUtil.java
----------------------------------------------------------------------
diff --git a/awsapi/src/com/cloud/bridge/util/JsonElementUtil.java b/awsapi/src/com/cloud/bridge/util/JsonElementUtil.java
new file mode 100644
index 0000000..2d8afb5
--- /dev/null
+++ b/awsapi/src/com/cloud/bridge/util/JsonElementUtil.java
@@ -0,0 +1,45 @@
+package com.cloud.bridge.util;
+
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonPrimitive;
+
+/**
+ * @author Dmitry Batkovich
+ *
+ * For more complex cases (JsonArrays or other) it can be rewrite to matcher pattern
+ */
+public final class JsonElementUtil {
+
+ private JsonElementUtil() {}
+
+ public static JsonElement getAsJsonElement(final JsonElement jsonElement, final String... path) {
+ JsonElement currentElement = jsonElement;
+ for (final String propertyName : path) {
+ if (currentElement == null) {
+ return null;
+ }
+ if (jsonElement.isJsonObject()) {
+ currentElement = ((JsonObject) currentElement).get(propertyName);
+ } else {
+ return null;
+ }
+ }
+ return currentElement;
+ }
+
+ public static Integer getAsInt(final JsonElement jsonElement, final String... path) {
+ final JsonElement targetElement = getAsJsonElement(jsonElement, path);
+ if (targetElement == null || !targetElement.isJsonPrimitive()) {
+ return null;
+ }
+ final JsonPrimitive asPrimitive = (JsonPrimitive) targetElement;
+ return asPrimitive.getAsInt();
+ }
+
+ public static String getAsString(final JsonElement jsonElement, final String... path) {
+ final JsonElement targetElement = getAsJsonElement(jsonElement, path);
+ return targetElement == null ? null : targetElement.getAsString();
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/a5510a0a/awsapi/src/com/cloud/stack/CloudStackClientException.java
----------------------------------------------------------------------
diff --git a/awsapi/src/com/cloud/stack/CloudStackClientException.java b/awsapi/src/com/cloud/stack/CloudStackClientException.java
new file mode 100644
index 0000000..ac1b3ef
--- /dev/null
+++ b/awsapi/src/com/cloud/stack/CloudStackClientException.java
@@ -0,0 +1,21 @@
+package com.cloud.stack;
+
+/**
+ * @author Dmitry Batkovich
+ */
+public class CloudStackClientException extends Exception {
+ public CloudStackClientException() {
+ }
+
+ public CloudStackClientException(final String s) {
+ super(s);
+ }
+
+ public CloudStackClientException(final String s, final Throwable throwable) {
+ super(s, throwable);
+ }
+
+ public CloudStackClientException(final Throwable throwable) {
+ super(throwable);
+ }
+}
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/a5510a0a/awsapi/src/com/cloud/stack/CloudStackCommand.java
----------------------------------------------------------------------
diff --git a/awsapi/src/com/cloud/stack/CloudStackCommand.java b/awsapi/src/com/cloud/stack/CloudStackCommand.java
deleted file mode 100644
index 8d6aa68..0000000
--- a/awsapi/src/com/cloud/stack/CloudStackCommand.java
+++ /dev/null
@@ -1,149 +0,0 @@
-// Licensed to the Apache Software Foundation (ASF) under one
-// or more contributor license agreements. See the NOTICE file
-// distributed with this work for additional information
-// regarding copyright ownership. The ASF licenses this file
-// to you under the Apache License, Version 2.0 (the
-// "License"); you may not use this file except in compliance
-// with the License. You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing,
-// software distributed under the License is distributed on an
-// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-// KIND, either express or implied. See the License for the
-// specific language governing permissions and limitations
-// under the License.
-package com.cloud.stack;
-
-import java.io.UnsupportedEncodingException;
-import java.net.URLEncoder;
-import java.security.SignatureException;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-import javax.crypto.Mac;
-import javax.crypto.spec.SecretKeySpec;
-
-import org.apache.commons.codec.binary.Base64;
-
-/**
- * CloudStackCommand wraps command properties that are being sent to CloudStack
- *
- */
-public class CloudStackCommand {
- Map<String, String> _params = new HashMap<String, String>();
-
- public CloudStackCommand(String cmdName) {
- this(cmdName, "json");
- }
-
- public CloudStackCommand(String cmdName, String responseType) {
- _params.put("command", cmdName);
- if (responseType != null)
- _params.put("response", responseType);
- }
-
- public CloudStackCommand setParam(String paramName, String paramValue) {
- assert (paramName != null);
- assert (paramValue != null);
-
- _params.put(paramName, paramValue);
- return this;
- }
-
- public String signCommand(String apiKey, String secretKey) throws SignatureException {
- assert (_params.get("command") != null);
-
- List<String> paramNames = new ArrayList<String>();
- for (String paramName : _params.keySet())
- paramNames.add(paramName);
-
- paramNames.add("apikey");
- Collections.sort(paramNames);
-
- StringBuffer sb = new StringBuffer();
- for (String name : paramNames) {
- String value;
- if ("apikey".equals(name))
- value = apiKey;
- else
- value = _params.get(name);
-
- assert (value != null);
-
- value = urlSafe(value);
-
- if (sb.length() == 0) {
- sb.append(name).append("=").append(value);
- } else {
- sb.append("&").append(name).append("=").append(value);
- }
- }
-
- String signature = calculateRFC2104HMAC(sb.toString().toLowerCase(), secretKey);
- return composeQueryString(apiKey, signature);
- }
-
- private String composeQueryString(String apiKey, String signature) {
- StringBuffer sb = new StringBuffer();
- String name;
- String value;
-
- // treat command specially (although not really necessary )
- name = "command";
- value = _params.get(name);
- if (value != null) {
- value = urlSafe(value);
- sb.append(name).append("=").append(value);
- }
-
- for (Map.Entry<String, String> entry : _params.entrySet()) {
- name = entry.getKey();
-
- if (!"command".equals(name)) {
- value = urlSafe(entry.getValue());
-
- if (sb.length() == 0)
- sb.append(name).append("=").append(value);
- else
- sb.append("&").append(name).append("=").append(value);
- }
- }
-
- sb.append("&apikey=").append(urlSafe(apiKey));
- sb.append("&signature=").append(urlSafe(signature));
-
- return sb.toString();
- }
-
- private String calculateRFC2104HMAC(String signIt, String secretKey) throws SignatureException {
- String result = null;
- try {
- SecretKeySpec key = new SecretKeySpec(secretKey.getBytes(), "HmacSHA1");
- Mac hmacSha1 = Mac.getInstance("HmacSHA1");
- hmacSha1.init(key);
- byte[] rawHmac = hmacSha1.doFinal(signIt.getBytes());
- result = new String(Base64.encodeBase64(rawHmac));
- } catch (Exception e) {
- throw new SignatureException("Failed to generate keyed HMAC on soap request: " + e.getMessage());
- }
- return result.trim();
- }
-
- private String urlSafe(String value) {
- try {
- if (value != null)
- return URLEncoder.encode(value, "UTF-8").replaceAll("\\+", "%20");
- else
- return null;
- } catch (UnsupportedEncodingException e) {
- assert (false);
- }
-
- return value;
- }
-}
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/a5510a0a/awsapi/src/com/cloud/stack/CloudStackQueryBuilder.java
----------------------------------------------------------------------
diff --git a/awsapi/src/com/cloud/stack/CloudStackQueryBuilder.java b/awsapi/src/com/cloud/stack/CloudStackQueryBuilder.java
new file mode 100644
index 0000000..a7aff68
--- /dev/null
+++ b/awsapi/src/com/cloud/stack/CloudStackQueryBuilder.java
@@ -0,0 +1,118 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package com.cloud.stack;
+
+import java.io.UnsupportedEncodingException;
+import java.net.URLEncoder;
+import java.security.SignatureException;
+import java.util.*;
+
+import javax.crypto.Mac;
+import javax.crypto.spec.SecretKeySpec;
+
+import com.cloud.utils.StringUtils;
+import org.apache.commons.codec.binary.Base64;
+import org.apache.commons.httpclient.HttpMethod;
+import org.apache.commons.httpclient.NameValuePair;
+import org.apache.commons.httpclient.URI;
+import org.apache.commons.httpclient.URIException;
+import org.apache.commons.httpclient.methods.GetMethod;
+import org.apache.commons.httpclient.methods.PostMethod;
+
+/**
+ * CloudStackQueryBuilder wraps command properties that are being sent to CloudStack
+ */
+public class CloudStackQueryBuilder {
+ private static final String HMAC_SHA_1 = "HmacSHA1";
+ private static final String COMMAND_KEY = "command";
+ private static final String APIKEY_KEY = "apikey";
+
+ private final Collection<NameValuePair> params = new ArrayList<NameValuePair>();
+
+ public CloudStackQueryBuilder(final String commandName) {
+ params.add(new NameValuePair("command", commandName));
+ params.add(new NameValuePair("response", "json"));
+ }
+
+ public static CloudStackQueryBuilder create(final String commandName) {
+ return new CloudStackQueryBuilder(commandName);
+ }
+
+ /**
+ * parameter will be stored to query only if paramValue != null. This assumption is very useful
+ * for optional parameters
+ * @param paramName - not null parameter name
+ * @param paramValue - nullable parameter value
+ */
+ public CloudStackQueryBuilder addParam(final String paramName, final Object paramValue) {
+ if (paramName == null) {
+ throw new NullPointerException();
+ }
+ if (paramValue != null) {
+ params.add(new NameValuePair(paramName, String.valueOf(paramValue)));
+ }
+ return this;
+ }
+
+ public HttpMethod buildRequest(final String apiKey, final String secretKey) throws SignatureException {
+ final PostMethod postMethod = new PostMethod();
+ for (final NameValuePair param : params) {
+ postMethod.addParameter(param);
+ }
+ postMethod.addParameter(APIKEY_KEY, apiKey);
+ postMethod.addParameter("signature", calculateSignature(secretKey, apiKey));
+ return postMethod;
+ }
+
+ private String calculateSignature(final String secretKey, final String apiKey) throws SignatureException {
+ final List<NameValuePair> paramsCopy = new ArrayList<NameValuePair>(params.size() + 1);
+ paramsCopy.addAll(params);
+ paramsCopy.add(new NameValuePair(APIKEY_KEY, urlSafe(apiKey)));
+ Collections.sort(paramsCopy, new Comparator<NameValuePair>() {
+ @Override
+ public int compare(final NameValuePair nameValuePair, final NameValuePair nameValuePair2) {
+ return nameValuePair.getName().compareTo(nameValuePair2.getName());
+ }
+ });
+
+ final List<String> serializedParameters = new ArrayList<String>(paramsCopy.size());
+ for (final NameValuePair pair : paramsCopy) {
+ serializedParameters.add(pair.getName() + "=" + urlSafe(pair.getValue()));
+ }
+ final String toSign = StringUtils.join(serializedParameters, "&").toLowerCase();
+ return calculateRFC2104HMAC(toSign, secretKey);
+ }
+
+ private static String calculateRFC2104HMAC(final String signIt, final String secretKey) throws SignatureException {
+ try {
+ final Mac hmacSha1 = Mac.getInstance(HMAC_SHA_1);
+ hmacSha1.init(new SecretKeySpec(secretKey.getBytes(), HMAC_SHA_1));
+ final byte[] rawHmac = hmacSha1.doFinal(signIt.getBytes());
+ return new String(Base64.encodeBase64(rawHmac)).trim();
+ } catch (final Exception e) {
+ throw new SignatureException("Failed to generate keyed HMAC on soap request: " + e.getMessage());
+ }
+ }
+
+ private static String urlSafe(final String value) {
+ try {
+ return value == null ? null : URLEncoder.encode(value, "UTF-8").replaceAll("\\+", "%20");
+ } catch (final UnsupportedEncodingException e) {
+ throw new RuntimeException(e);
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/a5510a0a/awsapi/test/com/cloud/gate/util/JsonAccessorTestCase.java
----------------------------------------------------------------------
diff --git a/awsapi/test/com/cloud/gate/util/JsonAccessorTestCase.java b/awsapi/test/com/cloud/gate/util/JsonAccessorTestCase.java
deleted file mode 100644
index 8603e59..0000000
--- a/awsapi/test/com/cloud/gate/util/JsonAccessorTestCase.java
+++ /dev/null
@@ -1,69 +0,0 @@
-// Licensed to the Apache Software Foundation (ASF) under one
-// or more contributor license agreements. See the NOTICE file
-// distributed with this work for additional information
-// regarding copyright ownership. The ASF licenses this file
-// to you under the Apache License, Version 2.0 (the
-// "License"); you may not use this file except in compliance
-// with the License. You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing,
-// software distributed under the License is distributed on an
-// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-// KIND, either express or implied. See the License for the
-// specific language governing permissions and limitations
-// under the License.
-package com.cloud.gate.util;
-
-import junit.framework.Assert;
-
-import org.apache.log4j.Logger;
-
-import com.google.gson.Gson;
-import com.google.gson.JsonElement;
-import com.google.gson.JsonParser;
-
-import com.cloud.bridge.util.JsonAccessor;
-import com.cloud.gate.testcase.BaseTestCase;
-import com.cloud.stack.models.CloudStackSnapshot;
-
-public class JsonAccessorTestCase extends BaseTestCase {
- protected final static Logger logger = Logger.getLogger(UtilTestCase.class);
-
- public void testJsonAccessor() {
- JsonParser parser = new JsonParser();
- JsonElement json = parser.parse("{firstName: 'Kelven', lastName: 'Yang', arrayObj: [{name: 'elem1'}, {name: 'elem2'}]}");
- JsonAccessor jsonAccessor = new JsonAccessor(json);
-
- Assert.assertTrue("Kelven".equals(jsonAccessor.getAsString("firstName")));
- Assert.assertTrue("Kelven".equals(jsonAccessor.getAsString("this.firstName")));
- Assert.assertTrue("Yang".equals(jsonAccessor.getAsString("lastName")));
- Assert.assertTrue("Yang".equals(jsonAccessor.getAsString("this.lastName")));
-
- Assert.assertTrue("elem1".equals(jsonAccessor.getAsString("arrayObj[0].name")));
- Assert.assertTrue("elem2".equals(jsonAccessor.getAsString("arrayObj[1].name")));
-
- Assert.assertTrue("elem1".equals(jsonAccessor.getAsString("this.arrayObj.this[0].name")));
- Assert.assertTrue("elem2".equals(jsonAccessor.getAsString("this.arrayObj.this[1].name")));
-
- Assert.assertTrue(jsonAccessor.getMatchCount("firstName") == 1);
- Assert.assertTrue(jsonAccessor.getMatchCount("middleName") == -1);
- Assert.assertTrue(jsonAccessor.getMatchCount("arrayObj") == 2);
- Assert.assertTrue(jsonAccessor.getMatchCount("arrayObj[0]") == 1);
- }
-
- public void testGson() {
- String response =
- "{ \"queryasyncjobresultresponse\" : {\"jobid\":5868,\"jobstatus\":1,\"jobprocstatus\":0,\"jobresultcode\":0,\"jobresulttype\":\"object\",\"jobresult\":{\"snapshot\":{\"id\":3161,\"account\":\"admin\",\"domainid\":1,\"domain\":\"ROOT\",\"snapshottype\":\"MANUAL\",\"volumeid\":186928,\"volumename\":\"KY-DATA-VOL\",\"volumetype\":\"DATADISK\",\"created\":\"2011-06-02T05:05:41-0700\",\"name\":\"i-2-246446-VM_KY-DATA-VOL_20110602120541\",\"intervaltype\":\"MANUAL\",\"state\":\"BackedUp\"}}}}";
-
- JsonParser parser = new JsonParser();
- JsonElement json = parser.parse(response);
- JsonAccessor jsonAccessor = new JsonAccessor(json);
-
- Gson gson = new Gson();
- CloudStackSnapshot snapshot = gson.fromJson(jsonAccessor.eval("queryasyncjobresultresponse.jobresult.snapshot"), CloudStackSnapshot.class);
-
- Assert.assertTrue("BackedUp".equals(snapshot.getState()));
- }
-}
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/a5510a0a/awsapi/test/com/cloud/gate/util/JsonElementUtilTestCase.java
----------------------------------------------------------------------
diff --git a/awsapi/test/com/cloud/gate/util/JsonElementUtilTestCase.java b/awsapi/test/com/cloud/gate/util/JsonElementUtilTestCase.java
new file mode 100644
index 0000000..8b4f267
--- /dev/null
+++ b/awsapi/test/com/cloud/gate/util/JsonElementUtilTestCase.java
@@ -0,0 +1,48 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package com.cloud.gate.util;
+
+import com.cloud.bridge.util.JsonElementUtil;
+import com.google.gson.JsonArray;
+import junit.framework.Assert;
+
+import com.cloud.gate.testcase.BaseTestCase;
+import com.cloud.stack.models.CloudStackSnapshot;
+import com.google.gson.Gson;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonParser;
+
+public class JsonElementUtilTestCase extends BaseTestCase {
+ private final static JsonParser JSON_PARSER = new JsonParser();
+
+ public void testJsonElementUtils() {
+ JsonElement json = JSON_PARSER.parse("{firstName: 'Kelven', lastName: 'Yang', arrayObj: [{name: 'elem1'}, {name: 'elem2'}], level1: {level2: 'some'}}");
+
+ assertEquals("Kelven", JsonElementUtil.getAsString(json, "firstName"));
+ assertEquals("Yang", JsonElementUtil.getAsString(json, "lastName"));
+ assertEquals("some", JsonElementUtil.getAsString(json, "level1", "level2"));
+ assertTrue(JsonElementUtil.getAsJsonElement(json, "arrayObj") instanceof JsonArray);
+ }
+
+ public void testGson() {
+ String response = "{ \"queryasyncjobresultresponse\" : {\"jobid\":5868,\"jobstatus\":1,\"jobprocstatus\":0,\"jobresultcode\":0,\"jobresulttype\":\"object\",\"jobresult\":{\"snapshot\":{\"id\":3161,\"account\":\"admin\",\"domainid\":1,\"domain\":\"ROOT\",\"snapshottype\":\"MANUAL\",\"volumeid\":186928,\"volumename\":\"KY-DATA-VOL\",\"volumetype\":\"DATADISK\",\"created\":\"2011-06-02T05:05:41-0700\",\"name\":\"i-2-246446-VM_KY-DATA-VOL_20110602120541\",\"intervaltype\":\"MANUAL\",\"state\":\"BackedUp\"}}}}";
+ JsonElement json = JSON_PARSER.parse(response);
+ Gson gson = new Gson();
+ CloudStackSnapshot snapshot = gson.fromJson(JsonElementUtil.getAsJsonElement(json, "queryasyncjobresultresponse", "jobresult", "snapshot"), CloudStackSnapshot.class);
+ Assert.assertTrue("BackedUp".equals(snapshot.getState()));
+ }
+}
Re: git commit: updated refs/heads/4.4 to a5510a0
Posted by sebgoa <ru...@gmail.com>.
taking care of it, if I don't get a new patch, I will correct it myself..
thanks
On Mar 24, 2014, at 4:11 PM, David Nalley <da...@gnsa.us> wrote:
> Licenses headers are missing in some of the new files. Also @author
> tags are generally frowned upon.
>
> awsapi/src/com/cloud/stack/CloudStackClientException.java
> awsapi/src/com/cloud/bridge/util/JsonElementUtil.java
>
> --David
>
> On Mon, Mar 24, 2014 at 11:00 AM, <se...@apache.org> wrote:
>> Repository: cloudstack
>> Updated Branches:
>> refs/heads/4.4 18934345a -> a5510a0a0
>>
>>
>> cloudstack api post and ssl fix
>>
>> Signed-off-by: Sebastien Goasguen <ru...@gmail.com>
>>
>>
>> Project: http://git-wip-us.apache.org/repos/asf/cloudstack/repo
>> Commit: http://git-wip-us.apache.org/repos/asf/cloudstack/commit/a5510a0a
>> Tree: http://git-wip-us.apache.org/repos/asf/cloudstack/tree/a5510a0a
>> Diff: http://git-wip-us.apache.org/repos/asf/cloudstack/diff/a5510a0a
>>
>> Branch: refs/heads/4.4
>> Commit: a5510a0a0aadf711b88ab5687484b1096c91e084
>> Parents: 1893434
>> Author: Dmitry Batkovich <ba...@gmail.com>
>> Authored: Mon Mar 24 18:46:45 2014 +0400
>> Committer: Sebastien Goasguen <ru...@gmail.com>
>> Committed: Mon Mar 24 16:00:13 2014 +0100
>>
>> ----------------------------------------------------------------------
>> .../src/com/cloud/bridge/util/JsonAccessor.java | 248 -------------------
>> .../com/cloud/bridge/util/JsonElementUtil.java | 45 ++++
>> .../cloud/stack/CloudStackClientException.java | 21 ++
>> .../src/com/cloud/stack/CloudStackCommand.java | 149 -----------
>> .../com/cloud/stack/CloudStackQueryBuilder.java | 118 +++++++++
>> .../cloud/gate/util/JsonAccessorTestCase.java | 69 ------
>> .../gate/util/JsonElementUtilTestCase.java | 48 ++++
>> 7 files changed, 232 insertions(+), 466 deletions(-)
>> ----------------------------------------------------------------------
>>
>>
>> http://git-wip-us.apache.org/repos/asf/cloudstack/blob/a5510a0a/awsapi/src/com/cloud/bridge/util/JsonAccessor.java
>> ----------------------------------------------------------------------
>> diff --git a/awsapi/src/com/cloud/bridge/util/JsonAccessor.java b/awsapi/src/com/cloud/bridge/util/JsonAccessor.java
>> deleted file mode 100644
>> index 2a94dea..0000000
>> --- a/awsapi/src/com/cloud/bridge/util/JsonAccessor.java
>> +++ /dev/null
>> @@ -1,248 +0,0 @@
>> -// Licensed to the Apache Software Foundation (ASF) under one
>> -// or more contributor license agreements. See the NOTICE file
>> -// distributed with this work for additional information
>> -// regarding copyright ownership. The ASF licenses this file
>> -// to you under the Apache License, Version 2.0 (the
>> -// "License"); you may not use this file except in compliance
>> -// with the License. You may obtain a copy of the License at
>> -//
>> -// http://www.apache.org/licenses/LICENSE-2.0
>> -//
>> -// Unless required by applicable law or agreed to in writing,
>> -// software distributed under the License is distributed on an
>> -// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
>> -// KIND, either express or implied. See the License for the
>> -// specific language governing permissions and limitations
>> -// under the License.
>> -package com.cloud.bridge.util;
>> -
>> -import java.math.BigDecimal;
>> -import java.math.BigInteger;
>> -import java.util.ArrayList;
>> -import java.util.regex.Matcher;
>> -import java.util.regex.Pattern;
>> -
>> -import com.google.gson.JsonArray;
>> -import com.google.gson.JsonElement;
>> -import com.google.gson.JsonObject;
>> -import com.google.gson.JsonPrimitive;
>> -
>> -import com.cloud.bridge.service.exception.InternalErrorException;
>> -
>> -/**
>> - * JsonAccessor provides the functionality to allow navigating JSON object graph using simple expressions,
>> - * for example, following property access expressions are all valid ones
>> - *
>> - * rootobj.level1obj[1].property
>> - * this[0].level1obj[1].property
>> - *
>> - */
>> -public class JsonAccessor {
>> - private JsonElement _json;
>> -
>> - Pattern _arrayAccessorMatcher = Pattern.compile("(.*)\\[(\\d+)\\]");
>> -
>> - public JsonAccessor(JsonElement json) {
>> - assert (json != null);
>> - _json = json;
>> - }
>> -
>> - public BigDecimal getAsBigDecimal(String propPath) {
>> - JsonElement jsonElement = eval(propPath);
>> - return jsonElement.getAsBigDecimal();
>> - }
>> -
>> - public BigInteger getAsBigInteger(String propPath) {
>> - JsonElement jsonElement = eval(propPath);
>> - return jsonElement.getAsBigInteger();
>> - }
>> -
>> - public boolean getAsBoolean(String propPath) {
>> - JsonElement jsonElement = eval(propPath);
>> - return jsonElement.getAsBoolean();
>> - }
>> -
>> - public byte getAsByte(String propPath) {
>> - JsonElement jsonElement = eval(propPath);
>> - return jsonElement.getAsByte();
>> - }
>> -
>> - public char getAsCharacter(String propPath) {
>> - JsonElement jsonElement = eval(propPath);
>> - return jsonElement.getAsCharacter();
>> - }
>> -
>> - public double getAsDouble(String propPath) {
>> - JsonElement jsonElement = eval(propPath);
>> - return jsonElement.getAsDouble();
>> - }
>> -
>> - public float getAsFloat(String propPath) {
>> - JsonElement jsonElement = eval(propPath);
>> - return jsonElement.getAsFloat();
>> - }
>> -
>> - public int getAsInt(String propPath) {
>> - JsonElement jsonElement = eval(propPath);
>> - return jsonElement.getAsInt();
>> - }
>> -
>> - public long getAsLong(String propPath) {
>> - JsonElement jsonElement = eval(propPath);
>> - return jsonElement.getAsLong();
>> - }
>> -
>> - public Number getAsNumber(String propPath) {
>> - JsonElement jsonElement = eval(propPath);
>> - return jsonElement.getAsNumber();
>> - }
>> -
>> - public short getAsShort(String propPath) {
>> - JsonElement jsonElement = eval(propPath);
>> - return jsonElement.getAsShort();
>> - }
>> -
>> - public String getAsString(String propPath) {
>> - JsonElement jsonElement = eval(propPath);
>> - return jsonElement.getAsString();
>> - }
>> -
>> - public boolean isBoolean(String propPath) {
>> - JsonElement jsonElement = eval(propPath);
>> - if (jsonElement instanceof JsonPrimitive)
>> - return ((JsonPrimitive)jsonElement).isBoolean();
>> -
>> - return false;
>> - }
>> -
>> - public boolean isNumber(String propPath) {
>> - JsonElement jsonElement = eval(propPath);
>> -
>> - if (jsonElement instanceof JsonPrimitive)
>> - return ((JsonPrimitive)jsonElement).isNumber();
>> - return false;
>> - }
>> -
>> - public boolean isString(String propPath) {
>> - JsonElement jsonElement = eval(propPath);
>> -
>> - if (jsonElement instanceof JsonPrimitive)
>> - return ((JsonPrimitive)jsonElement).isString();
>> - return false;
>> - }
>> -
>> - /*
>> - * Return
>> - * -1 : property expression can not be resolved
>> - * 0 : match to a null JSON object
>> - * 1+ : matched, for array element, the count of the elements inside the array
>> - */
>> - public int getMatchCount(String propPath) {
>> - JsonElement jsonElement = tryEval(propPath);
>> - if (jsonElement == null)
>> - return -1;
>> -
>> - if (jsonElement.isJsonNull())
>> - return 0;
>> -
>> - if (jsonElement.isJsonArray())
>> - return ((JsonArray)jsonElement).size();
>> -
>> - return 1;
>> - }
>> -
>> - public JsonElement eval(String propPath) {
>> - JsonElement jsonElement = tryEval(propPath);
>> - if (jsonElement == null)
>> - throw new InternalErrorException("Property " + propPath + " is resolved to null JSON element on object: " + _json.toString());
>> -
>> - return jsonElement;
>> - }
>> -
>> - public JsonElement tryEval(String propPath) {
>> - assert (propPath != null);
>> - String[] tokens = propPath.split("\\.");
>> -
>> - ArrayList<Resolver> resolverChain = new ArrayList<Resolver>();
>> - for (String token : tokens) {
>> - Matcher matcher = _arrayAccessorMatcher.matcher(token);
>> - if (matcher.find()) {
>> - String propStr = matcher.group(1);
>> - String indexStr = matcher.group(2);
>> -
>> - resolverChain.add(new ArrayPropertyResolver(propStr, Integer.parseInt(indexStr)));
>> - } else {
>> - resolverChain.add(new PropertyResolver(token));
>> - }
>> - }
>> -
>> - JsonElement jsonElementToResolveAt = _json;
>> - for (Resolver resolver : resolverChain) {
>> - jsonElementToResolveAt = resolver.resolve(jsonElementToResolveAt);
>> -
>> - if (jsonElementToResolveAt == null)
>> - break;
>> - }
>> -
>> - return jsonElementToResolveAt;
>> - }
>> -
>> - //
>> - // Property resolvers
>> - //
>> - private static interface Resolver {
>> - public JsonElement resolve(JsonElement jsonElementToResolveAt);
>> - }
>> -
>> - private static class PropertyResolver implements Resolver {
>> - protected String _propName;
>> -
>> - public PropertyResolver(String propName) {
>> - _propName = propName;
>> - }
>> -
>> - public JsonElement resolve(JsonElement jsonElementToResolveAt) {
>> - if ("this".equals(_propName))
>> - return jsonElementToResolveAt;
>> -
>> - if (jsonElementToResolveAt.isJsonObject())
>> - return ((JsonObject)jsonElementToResolveAt).get(_propName);
>> -
>> - if (jsonElementToResolveAt.isJsonNull())
>> - throw new NullPointerException(String.format("Property %s points to a null element on object: %s", _propName, jsonElementToResolveAt.toString()));
>> -
>> - throw new InternalErrorException("Unable to evaluate JSON accessor property: " + _propName + ", on object: " + jsonElementToResolveAt.toString());
>> - }
>> - }
>> -
>> - private static class ArrayPropertyResolver extends PropertyResolver {
>> - protected int _index;
>> -
>> - public ArrayPropertyResolver(String propName, int index) {
>> - super(propName);
>> - _index = index;
>> - }
>> -
>> - public JsonElement resolve(JsonElement jsonElementToResolveAt) {
>> - if (!"this".equals(_propName)) {
>> - if (jsonElementToResolveAt.isJsonObject()) {
>> - jsonElementToResolveAt = ((JsonObject)jsonElementToResolveAt).get(_propName);
>> - } else {
>> - if (jsonElementToResolveAt.isJsonNull())
>> - throw new NullPointerException(String.format("Property %s points to a null element on object: %s", _propName, jsonElementToResolveAt.toString()));
>> -
>> - throw new InternalErrorException("Unable to evaluate JSON accessor property: " + _propName + ", on object: " + jsonElementToResolveAt.toString());
>> - }
>> - }
>> -
>> - if (jsonElementToResolveAt instanceof JsonArray) {
>> - return ((JsonArray)jsonElementToResolveAt).get(_index);
>> - }
>> -
>> - if (jsonElementToResolveAt.isJsonNull())
>> - throw new NullPointerException(String.format("Property %s points to a null element on object: %s", _propName, jsonElementToResolveAt.toString()));
>> -
>> - throw new InternalErrorException("Unable to evaluate JSON accessor property: " + _propName + ", on object: " + jsonElementToResolveAt.toString());
>> - }
>> - }
>> -}
>>
>> http://git-wip-us.apache.org/repos/asf/cloudstack/blob/a5510a0a/awsapi/src/com/cloud/bridge/util/JsonElementUtil.java
>> ----------------------------------------------------------------------
>> diff --git a/awsapi/src/com/cloud/bridge/util/JsonElementUtil.java b/awsapi/src/com/cloud/bridge/util/JsonElementUtil.java
>> new file mode 100644
>> index 0000000..2d8afb5
>> --- /dev/null
>> +++ b/awsapi/src/com/cloud/bridge/util/JsonElementUtil.java
>> @@ -0,0 +1,45 @@
>> +package com.cloud.bridge.util;
>> +
>> +import com.google.gson.JsonElement;
>> +import com.google.gson.JsonObject;
>> +import com.google.gson.JsonPrimitive;
>> +
>> +/**
>> + * @author Dmitry Batkovich
>> + *
>> + * For more complex cases (JsonArrays or other) it can be rewrite to matcher pattern
>> + */
>> +public final class JsonElementUtil {
>> +
>> + private JsonElementUtil() {}
>> +
>> + public static JsonElement getAsJsonElement(final JsonElement jsonElement, final String... path) {
>> + JsonElement currentElement = jsonElement;
>> + for (final String propertyName : path) {
>> + if (currentElement == null) {
>> + return null;
>> + }
>> + if (jsonElement.isJsonObject()) {
>> + currentElement = ((JsonObject) currentElement).get(propertyName);
>> + } else {
>> + return null;
>> + }
>> + }
>> + return currentElement;
>> + }
>> +
>> + public static Integer getAsInt(final JsonElement jsonElement, final String... path) {
>> + final JsonElement targetElement = getAsJsonElement(jsonElement, path);
>> + if (targetElement == null || !targetElement.isJsonPrimitive()) {
>> + return null;
>> + }
>> + final JsonPrimitive asPrimitive = (JsonPrimitive) targetElement;
>> + return asPrimitive.getAsInt();
>> + }
>> +
>> + public static String getAsString(final JsonElement jsonElement, final String... path) {
>> + final JsonElement targetElement = getAsJsonElement(jsonElement, path);
>> + return targetElement == null ? null : targetElement.getAsString();
>> + }
>> +
>> +}
>>
>> http://git-wip-us.apache.org/repos/asf/cloudstack/blob/a5510a0a/awsapi/src/com/cloud/stack/CloudStackClientException.java
>> ----------------------------------------------------------------------
>> diff --git a/awsapi/src/com/cloud/stack/CloudStackClientException.java b/awsapi/src/com/cloud/stack/CloudStackClientException.java
>> new file mode 100644
>> index 0000000..ac1b3ef
>> --- /dev/null
>> +++ b/awsapi/src/com/cloud/stack/CloudStackClientException.java
>> @@ -0,0 +1,21 @@
>> +package com.cloud.stack;
>> +
>> +/**
>> + * @author Dmitry Batkovich
>> + */
>> +public class CloudStackClientException extends Exception {
>> + public CloudStackClientException() {
>> + }
>> +
>> + public CloudStackClientException(final String s) {
>> + super(s);
>> + }
>> +
>> + public CloudStackClientException(final String s, final Throwable throwable) {
>> + super(s, throwable);
>> + }
>> +
>> + public CloudStackClientException(final Throwable throwable) {
>> + super(throwable);
>> + }
>> +}
>>
>> http://git-wip-us.apache.org/repos/asf/cloudstack/blob/a5510a0a/awsapi/src/com/cloud/stack/CloudStackCommand.java
>> ----------------------------------------------------------------------
>> diff --git a/awsapi/src/com/cloud/stack/CloudStackCommand.java b/awsapi/src/com/cloud/stack/CloudStackCommand.java
>> deleted file mode 100644
>> index 8d6aa68..0000000
>> --- a/awsapi/src/com/cloud/stack/CloudStackCommand.java
>> +++ /dev/null
>> @@ -1,149 +0,0 @@
>> -// Licensed to the Apache Software Foundation (ASF) under one
>> -// or more contributor license agreements. See the NOTICE file
>> -// distributed with this work for additional information
>> -// regarding copyright ownership. The ASF licenses this file
>> -// to you under the Apache License, Version 2.0 (the
>> -// "License"); you may not use this file except in compliance
>> -// with the License. You may obtain a copy of the License at
>> -//
>> -// http://www.apache.org/licenses/LICENSE-2.0
>> -//
>> -// Unless required by applicable law or agreed to in writing,
>> -// software distributed under the License is distributed on an
>> -// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
>> -// KIND, either express or implied. See the License for the
>> -// specific language governing permissions and limitations
>> -// under the License.
>> -package com.cloud.stack;
>> -
>> -import java.io.UnsupportedEncodingException;
>> -import java.net.URLEncoder;
>> -import java.security.SignatureException;
>> -import java.util.ArrayList;
>> -import java.util.Collections;
>> -import java.util.HashMap;
>> -import java.util.List;
>> -import java.util.Map;
>> -
>> -import javax.crypto.Mac;
>> -import javax.crypto.spec.SecretKeySpec;
>> -
>> -import org.apache.commons.codec.binary.Base64;
>> -
>> -/**
>> - * CloudStackCommand wraps command properties that are being sent to CloudStack
>> - *
>> - */
>> -public class CloudStackCommand {
>> - Map<String, String> _params = new HashMap<String, String>();
>> -
>> - public CloudStackCommand(String cmdName) {
>> - this(cmdName, "json");
>> - }
>> -
>> - public CloudStackCommand(String cmdName, String responseType) {
>> - _params.put("command", cmdName);
>> - if (responseType != null)
>> - _params.put("response", responseType);
>> - }
>> -
>> - public CloudStackCommand setParam(String paramName, String paramValue) {
>> - assert (paramName != null);
>> - assert (paramValue != null);
>> -
>> - _params.put(paramName, paramValue);
>> - return this;
>> - }
>> -
>> - public String signCommand(String apiKey, String secretKey) throws SignatureException {
>> - assert (_params.get("command") != null);
>> -
>> - List<String> paramNames = new ArrayList<String>();
>> - for (String paramName : _params.keySet())
>> - paramNames.add(paramName);
>> -
>> - paramNames.add("apikey");
>> - Collections.sort(paramNames);
>> -
>> - StringBuffer sb = new StringBuffer();
>> - for (String name : paramNames) {
>> - String value;
>> - if ("apikey".equals(name))
>> - value = apiKey;
>> - else
>> - value = _params.get(name);
>> -
>> - assert (value != null);
>> -
>> - value = urlSafe(value);
>> -
>> - if (sb.length() == 0) {
>> - sb.append(name).append("=").append(value);
>> - } else {
>> - sb.append("&").append(name).append("=").append(value);
>> - }
>> - }
>> -
>> - String signature = calculateRFC2104HMAC(sb.toString().toLowerCase(), secretKey);
>> - return composeQueryString(apiKey, signature);
>> - }
>> -
>> - private String composeQueryString(String apiKey, String signature) {
>> - StringBuffer sb = new StringBuffer();
>> - String name;
>> - String value;
>> -
>> - // treat command specially (although not really necessary )
>> - name = "command";
>> - value = _params.get(name);
>> - if (value != null) {
>> - value = urlSafe(value);
>> - sb.append(name).append("=").append(value);
>> - }
>> -
>> - for (Map.Entry<String, String> entry : _params.entrySet()) {
>> - name = entry.getKey();
>> -
>> - if (!"command".equals(name)) {
>> - value = urlSafe(entry.getValue());
>> -
>> - if (sb.length() == 0)
>> - sb.append(name).append("=").append(value);
>> - else
>> - sb.append("&").append(name).append("=").append(value);
>> - }
>> - }
>> -
>> - sb.append("&apikey=").append(urlSafe(apiKey));
>> - sb.append("&signature=").append(urlSafe(signature));
>> -
>> - return sb.toString();
>> - }
>> -
>> - private String calculateRFC2104HMAC(String signIt, String secretKey) throws SignatureException {
>> - String result = null;
>> - try {
>> - SecretKeySpec key = new SecretKeySpec(secretKey.getBytes(), "HmacSHA1");
>> - Mac hmacSha1 = Mac.getInstance("HmacSHA1");
>> - hmacSha1.init(key);
>> - byte[] rawHmac = hmacSha1.doFinal(signIt.getBytes());
>> - result = new String(Base64.encodeBase64(rawHmac));
>> - } catch (Exception e) {
>> - throw new SignatureException("Failed to generate keyed HMAC on soap request: " + e.getMessage());
>> - }
>> - return result.trim();
>> - }
>> -
>> - private String urlSafe(String value) {
>> - try {
>> - if (value != null)
>> - return URLEncoder.encode(value, "UTF-8").replaceAll("\\+", "%20");
>> - else
>> - return null;
>> - } catch (UnsupportedEncodingException e) {
>> - assert (false);
>> - }
>> -
>> - return value;
>> - }
>> -}
>>
>> http://git-wip-us.apache.org/repos/asf/cloudstack/blob/a5510a0a/awsapi/src/com/cloud/stack/CloudStackQueryBuilder.java
>> ----------------------------------------------------------------------
>> diff --git a/awsapi/src/com/cloud/stack/CloudStackQueryBuilder.java b/awsapi/src/com/cloud/stack/CloudStackQueryBuilder.java
>> new file mode 100644
>> index 0000000..a7aff68
>> --- /dev/null
>> +++ b/awsapi/src/com/cloud/stack/CloudStackQueryBuilder.java
>> @@ -0,0 +1,118 @@
>> +// Licensed to the Apache Software Foundation (ASF) under one
>> +// or more contributor license agreements. See the NOTICE file
>> +// distributed with this work for additional information
>> +// regarding copyright ownership. The ASF licenses this file
>> +// to you under the Apache License, Version 2.0 (the
>> +// "License"); you may not use this file except in compliance
>> +// with the License. You may obtain a copy of the License at
>> +//
>> +// http://www.apache.org/licenses/LICENSE-2.0
>> +//
>> +// Unless required by applicable law or agreed to in writing,
>> +// software distributed under the License is distributed on an
>> +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
>> +// KIND, either express or implied. See the License for the
>> +// specific language governing permissions and limitations
>> +// under the License.
>> +package com.cloud.stack;
>> +
>> +import java.io.UnsupportedEncodingException;
>> +import java.net.URLEncoder;
>> +import java.security.SignatureException;
>> +import java.util.*;
>> +
>> +import javax.crypto.Mac;
>> +import javax.crypto.spec.SecretKeySpec;
>> +
>> +import com.cloud.utils.StringUtils;
>> +import org.apache.commons.codec.binary.Base64;
>> +import org.apache.commons.httpclient.HttpMethod;
>> +import org.apache.commons.httpclient.NameValuePair;
>> +import org.apache.commons.httpclient.URI;
>> +import org.apache.commons.httpclient.URIException;
>> +import org.apache.commons.httpclient.methods.GetMethod;
>> +import org.apache.commons.httpclient.methods.PostMethod;
>> +
>> +/**
>> + * CloudStackQueryBuilder wraps command properties that are being sent to CloudStack
>> + */
>> +public class CloudStackQueryBuilder {
>> + private static final String HMAC_SHA_1 = "HmacSHA1";
>> + private static final String COMMAND_KEY = "command";
>> + private static final String APIKEY_KEY = "apikey";
>> +
>> + private final Collection<NameValuePair> params = new ArrayList<NameValuePair>();
>> +
>> + public CloudStackQueryBuilder(final String commandName) {
>> + params.add(new NameValuePair("command", commandName));
>> + params.add(new NameValuePair("response", "json"));
>> + }
>> +
>> + public static CloudStackQueryBuilder create(final String commandName) {
>> + return new CloudStackQueryBuilder(commandName);
>> + }
>> +
>> + /**
>> + * parameter will be stored to query only if paramValue != null. This assumption is very useful
>> + * for optional parameters
>> + * @param paramName - not null parameter name
>> + * @param paramValue - nullable parameter value
>> + */
>> + public CloudStackQueryBuilder addParam(final String paramName, final Object paramValue) {
>> + if (paramName == null) {
>> + throw new NullPointerException();
>> + }
>> + if (paramValue != null) {
>> + params.add(new NameValuePair(paramName, String.valueOf(paramValue)));
>> + }
>> + return this;
>> + }
>> +
>> + public HttpMethod buildRequest(final String apiKey, final String secretKey) throws SignatureException {
>> + final PostMethod postMethod = new PostMethod();
>> + for (final NameValuePair param : params) {
>> + postMethod.addParameter(param);
>> + }
>> + postMethod.addParameter(APIKEY_KEY, apiKey);
>> + postMethod.addParameter("signature", calculateSignature(secretKey, apiKey));
>> + return postMethod;
>> + }
>> +
>> + private String calculateSignature(final String secretKey, final String apiKey) throws SignatureException {
>> + final List<NameValuePair> paramsCopy = new ArrayList<NameValuePair>(params.size() + 1);
>> + paramsCopy.addAll(params);
>> + paramsCopy.add(new NameValuePair(APIKEY_KEY, urlSafe(apiKey)));
>> + Collections.sort(paramsCopy, new Comparator<NameValuePair>() {
>> + @Override
>> + public int compare(final NameValuePair nameValuePair, final NameValuePair nameValuePair2) {
>> + return nameValuePair.getName().compareTo(nameValuePair2.getName());
>> + }
>> + });
>> +
>> + final List<String> serializedParameters = new ArrayList<String>(paramsCopy.size());
>> + for (final NameValuePair pair : paramsCopy) {
>> + serializedParameters.add(pair.getName() + "=" + urlSafe(pair.getValue()));
>> + }
>> + final String toSign = StringUtils.join(serializedParameters, "&").toLowerCase();
>> + return calculateRFC2104HMAC(toSign, secretKey);
>> + }
>> +
>> + private static String calculateRFC2104HMAC(final String signIt, final String secretKey) throws SignatureException {
>> + try {
>> + final Mac hmacSha1 = Mac.getInstance(HMAC_SHA_1);
>> + hmacSha1.init(new SecretKeySpec(secretKey.getBytes(), HMAC_SHA_1));
>> + final byte[] rawHmac = hmacSha1.doFinal(signIt.getBytes());
>> + return new String(Base64.encodeBase64(rawHmac)).trim();
>> + } catch (final Exception e) {
>> + throw new SignatureException("Failed to generate keyed HMAC on soap request: " + e.getMessage());
>> + }
>> + }
>> +
>> + private static String urlSafe(final String value) {
>> + try {
>> + return value == null ? null : URLEncoder.encode(value, "UTF-8").replaceAll("\\+", "%20");
>> + } catch (final UnsupportedEncodingException e) {
>> + throw new RuntimeException(e);
>> + }
>> + }
>> +}
>>
>> http://git-wip-us.apache.org/repos/asf/cloudstack/blob/a5510a0a/awsapi/test/com/cloud/gate/util/JsonAccessorTestCase.java
>> ----------------------------------------------------------------------
>> diff --git a/awsapi/test/com/cloud/gate/util/JsonAccessorTestCase.java b/awsapi/test/com/cloud/gate/util/JsonAccessorTestCase.java
>> deleted file mode 100644
>> index 8603e59..0000000
>> --- a/awsapi/test/com/cloud/gate/util/JsonAccessorTestCase.java
>> +++ /dev/null
>> @@ -1,69 +0,0 @@
>> -// Licensed to the Apache Software Foundation (ASF) under one
>> -// or more contributor license agreements. See the NOTICE file
>> -// distributed with this work for additional information
>> -// regarding copyright ownership. The ASF licenses this file
>> -// to you under the Apache License, Version 2.0 (the
>> -// "License"); you may not use this file except in compliance
>> -// with the License. You may obtain a copy of the License at
>> -//
>> -// http://www.apache.org/licenses/LICENSE-2.0
>> -//
>> -// Unless required by applicable law or agreed to in writing,
>> -// software distributed under the License is distributed on an
>> -// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
>> -// KIND, either express or implied. See the License for the
>> -// specific language governing permissions and limitations
>> -// under the License.
>> -package com.cloud.gate.util;
>> -
>> -import junit.framework.Assert;
>> -
>> -import org.apache.log4j.Logger;
>> -
>> -import com.google.gson.Gson;
>> -import com.google.gson.JsonElement;
>> -import com.google.gson.JsonParser;
>> -
>> -import com.cloud.bridge.util.JsonAccessor;
>> -import com.cloud.gate.testcase.BaseTestCase;
>> -import com.cloud.stack.models.CloudStackSnapshot;
>> -
>> -public class JsonAccessorTestCase extends BaseTestCase {
>> - protected final static Logger logger = Logger.getLogger(UtilTestCase.class);
>> -
>> - public void testJsonAccessor() {
>> - JsonParser parser = new JsonParser();
>> - JsonElement json = parser.parse("{firstName: 'Kelven', lastName: 'Yang', arrayObj: [{name: 'elem1'}, {name: 'elem2'}]}");
>> - JsonAccessor jsonAccessor = new JsonAccessor(json);
>> -
>> - Assert.assertTrue("Kelven".equals(jsonAccessor.getAsString("firstName")));
>> - Assert.assertTrue("Kelven".equals(jsonAccessor.getAsString("this.firstName")));
>> - Assert.assertTrue("Yang".equals(jsonAccessor.getAsString("lastName")));
>> - Assert.assertTrue("Yang".equals(jsonAccessor.getAsString("this.lastName")));
>> -
>> - Assert.assertTrue("elem1".equals(jsonAccessor.getAsString("arrayObj[0].name")));
>> - Assert.assertTrue("elem2".equals(jsonAccessor.getAsString("arrayObj[1].name")));
>> -
>> - Assert.assertTrue("elem1".equals(jsonAccessor.getAsString("this.arrayObj.this[0].name")));
>> - Assert.assertTrue("elem2".equals(jsonAccessor.getAsString("this.arrayObj.this[1].name")));
>> -
>> - Assert.assertTrue(jsonAccessor.getMatchCount("firstName") == 1);
>> - Assert.assertTrue(jsonAccessor.getMatchCount("middleName") == -1);
>> - Assert.assertTrue(jsonAccessor.getMatchCount("arrayObj") == 2);
>> - Assert.assertTrue(jsonAccessor.getMatchCount("arrayObj[0]") == 1);
>> - }
>> -
>> - public void testGson() {
>> - String response =
>> - "{ \"queryasyncjobresultresponse\" : {\"jobid\":5868,\"jobstatus\":1,\"jobprocstatus\":0,\"jobresultcode\":0,\"jobresulttype\":\"object\",\"jobresult\":{\"snapshot\":{\"id\":3161,\"account\":\"admin\",\"domainid\":1,\"domain\":\"ROOT\",\"snapshottype\":\"MANUAL\",\"volumeid\":186928,\"volumename\":\"KY-DATA-VOL\",\"volumetype\":\"DATADISK\",\"created\":\"2011-06-02T05:05:41-0700\",\"name\":\"i-2-246446-VM_KY-DATA-VOL_20110602120541\",\"intervaltype\":\"MANUAL\",\"state\":\"BackedUp\"}}}}";
>> -
>> - JsonParser parser = new JsonParser();
>> - JsonElement json = parser.parse(response);
>> - JsonAccessor jsonAccessor = new JsonAccessor(json);
>> -
>> - Gson gson = new Gson();
>> - CloudStackSnapshot snapshot = gson.fromJson(jsonAccessor.eval("queryasyncjobresultresponse.jobresult.snapshot"), CloudStackSnapshot.class);
>> -
>> - Assert.assertTrue("BackedUp".equals(snapshot.getState()));
>> - }
>> -}
>>
>> http://git-wip-us.apache.org/repos/asf/cloudstack/blob/a5510a0a/awsapi/test/com/cloud/gate/util/JsonElementUtilTestCase.java
>> ----------------------------------------------------------------------
>> diff --git a/awsapi/test/com/cloud/gate/util/JsonElementUtilTestCase.java b/awsapi/test/com/cloud/gate/util/JsonElementUtilTestCase.java
>> new file mode 100644
>> index 0000000..8b4f267
>> --- /dev/null
>> +++ b/awsapi/test/com/cloud/gate/util/JsonElementUtilTestCase.java
>> @@ -0,0 +1,48 @@
>> +// Licensed to the Apache Software Foundation (ASF) under one
>> +// or more contributor license agreements. See the NOTICE file
>> +// distributed with this work for additional information
>> +// regarding copyright ownership. The ASF licenses this file
>> +// to you under the Apache License, Version 2.0 (the
>> +// "License"); you may not use this file except in compliance
>> +// with the License. You may obtain a copy of the License at
>> +//
>> +// http://www.apache.org/licenses/LICENSE-2.0
>> +//
>> +// Unless required by applicable law or agreed to in writing,
>> +// software distributed under the License is distributed on an
>> +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
>> +// KIND, either express or implied. See the License for the
>> +// specific language governing permissions and limitations
>> +// under the License.
>> +package com.cloud.gate.util;
>> +
>> +import com.cloud.bridge.util.JsonElementUtil;
>> +import com.google.gson.JsonArray;
>> +import junit.framework.Assert;
>> +
>> +import com.cloud.gate.testcase.BaseTestCase;
>> +import com.cloud.stack.models.CloudStackSnapshot;
>> +import com.google.gson.Gson;
>> +import com.google.gson.JsonElement;
>> +import com.google.gson.JsonParser;
>> +
>> +public class JsonElementUtilTestCase extends BaseTestCase {
>> + private final static JsonParser JSON_PARSER = new JsonParser();
>> +
>> + public void testJsonElementUtils() {
>> + JsonElement json = JSON_PARSER.parse("{firstName: 'Kelven', lastName: 'Yang', arrayObj: [{name: 'elem1'}, {name: 'elem2'}], level1: {level2: 'some'}}");
>> +
>> + assertEquals("Kelven", JsonElementUtil.getAsString(json, "firstName"));
>> + assertEquals("Yang", JsonElementUtil.getAsString(json, "lastName"));
>> + assertEquals("some", JsonElementUtil.getAsString(json, "level1", "level2"));
>> + assertTrue(JsonElementUtil.getAsJsonElement(json, "arrayObj") instanceof JsonArray);
>> + }
>> +
>> + public void testGson() {
>> + String response = "{ \"queryasyncjobresultresponse\" : {\"jobid\":5868,\"jobstatus\":1,\"jobprocstatus\":0,\"jobresultcode\":0,\"jobresulttype\":\"object\",\"jobresult\":{\"snapshot\":{\"id\":3161,\"account\":\"admin\",\"domainid\":1,\"domain\":\"ROOT\",\"snapshottype\":\"MANUAL\",\"volumeid\":186928,\"volumename\":\"KY-DATA-VOL\",\"volumetype\":\"DATADISK\",\"created\":\"2011-06-02T05:05:41-0700\",\"name\":\"i-2-246446-VM_KY-DATA-VOL_20110602120541\",\"intervaltype\":\"MANUAL\",\"state\":\"BackedUp\"}}}}";
>> + JsonElement json = JSON_PARSER.parse(response);
>> + Gson gson = new Gson();
>> + CloudStackSnapshot snapshot = gson.fromJson(JsonElementUtil.getAsJsonElement(json, "queryasyncjobresultresponse", "jobresult", "snapshot"), CloudStackSnapshot.class);
>> + Assert.assertTrue("BackedUp".equals(snapshot.getState()));
>> + }
>> +}
>>
Re: git commit: updated refs/heads/4.4 to a5510a0
Posted by David Nalley <da...@gnsa.us>.
Licenses headers are missing in some of the new files. Also @author
tags are generally frowned upon.
awsapi/src/com/cloud/stack/CloudStackClientException.java
awsapi/src/com/cloud/bridge/util/JsonElementUtil.java
--David
On Mon, Mar 24, 2014 at 11:00 AM, <se...@apache.org> wrote:
> Repository: cloudstack
> Updated Branches:
> refs/heads/4.4 18934345a -> a5510a0a0
>
>
> cloudstack api post and ssl fix
>
> Signed-off-by: Sebastien Goasguen <ru...@gmail.com>
>
>
> Project: http://git-wip-us.apache.org/repos/asf/cloudstack/repo
> Commit: http://git-wip-us.apache.org/repos/asf/cloudstack/commit/a5510a0a
> Tree: http://git-wip-us.apache.org/repos/asf/cloudstack/tree/a5510a0a
> Diff: http://git-wip-us.apache.org/repos/asf/cloudstack/diff/a5510a0a
>
> Branch: refs/heads/4.4
> Commit: a5510a0a0aadf711b88ab5687484b1096c91e084
> Parents: 1893434
> Author: Dmitry Batkovich <ba...@gmail.com>
> Authored: Mon Mar 24 18:46:45 2014 +0400
> Committer: Sebastien Goasguen <ru...@gmail.com>
> Committed: Mon Mar 24 16:00:13 2014 +0100
>
> ----------------------------------------------------------------------
> .../src/com/cloud/bridge/util/JsonAccessor.java | 248 -------------------
> .../com/cloud/bridge/util/JsonElementUtil.java | 45 ++++
> .../cloud/stack/CloudStackClientException.java | 21 ++
> .../src/com/cloud/stack/CloudStackCommand.java | 149 -----------
> .../com/cloud/stack/CloudStackQueryBuilder.java | 118 +++++++++
> .../cloud/gate/util/JsonAccessorTestCase.java | 69 ------
> .../gate/util/JsonElementUtilTestCase.java | 48 ++++
> 7 files changed, 232 insertions(+), 466 deletions(-)
> ----------------------------------------------------------------------
>
>
> http://git-wip-us.apache.org/repos/asf/cloudstack/blob/a5510a0a/awsapi/src/com/cloud/bridge/util/JsonAccessor.java
> ----------------------------------------------------------------------
> diff --git a/awsapi/src/com/cloud/bridge/util/JsonAccessor.java b/awsapi/src/com/cloud/bridge/util/JsonAccessor.java
> deleted file mode 100644
> index 2a94dea..0000000
> --- a/awsapi/src/com/cloud/bridge/util/JsonAccessor.java
> +++ /dev/null
> @@ -1,248 +0,0 @@
> -// Licensed to the Apache Software Foundation (ASF) under one
> -// or more contributor license agreements. See the NOTICE file
> -// distributed with this work for additional information
> -// regarding copyright ownership. The ASF licenses this file
> -// to you under the Apache License, Version 2.0 (the
> -// "License"); you may not use this file except in compliance
> -// with the License. You may obtain a copy of the License at
> -//
> -// http://www.apache.org/licenses/LICENSE-2.0
> -//
> -// Unless required by applicable law or agreed to in writing,
> -// software distributed under the License is distributed on an
> -// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
> -// KIND, either express or implied. See the License for the
> -// specific language governing permissions and limitations
> -// under the License.
> -package com.cloud.bridge.util;
> -
> -import java.math.BigDecimal;
> -import java.math.BigInteger;
> -import java.util.ArrayList;
> -import java.util.regex.Matcher;
> -import java.util.regex.Pattern;
> -
> -import com.google.gson.JsonArray;
> -import com.google.gson.JsonElement;
> -import com.google.gson.JsonObject;
> -import com.google.gson.JsonPrimitive;
> -
> -import com.cloud.bridge.service.exception.InternalErrorException;
> -
> -/**
> - * JsonAccessor provides the functionality to allow navigating JSON object graph using simple expressions,
> - * for example, following property access expressions are all valid ones
> - *
> - * rootobj.level1obj[1].property
> - * this[0].level1obj[1].property
> - *
> - */
> -public class JsonAccessor {
> - private JsonElement _json;
> -
> - Pattern _arrayAccessorMatcher = Pattern.compile("(.*)\\[(\\d+)\\]");
> -
> - public JsonAccessor(JsonElement json) {
> - assert (json != null);
> - _json = json;
> - }
> -
> - public BigDecimal getAsBigDecimal(String propPath) {
> - JsonElement jsonElement = eval(propPath);
> - return jsonElement.getAsBigDecimal();
> - }
> -
> - public BigInteger getAsBigInteger(String propPath) {
> - JsonElement jsonElement = eval(propPath);
> - return jsonElement.getAsBigInteger();
> - }
> -
> - public boolean getAsBoolean(String propPath) {
> - JsonElement jsonElement = eval(propPath);
> - return jsonElement.getAsBoolean();
> - }
> -
> - public byte getAsByte(String propPath) {
> - JsonElement jsonElement = eval(propPath);
> - return jsonElement.getAsByte();
> - }
> -
> - public char getAsCharacter(String propPath) {
> - JsonElement jsonElement = eval(propPath);
> - return jsonElement.getAsCharacter();
> - }
> -
> - public double getAsDouble(String propPath) {
> - JsonElement jsonElement = eval(propPath);
> - return jsonElement.getAsDouble();
> - }
> -
> - public float getAsFloat(String propPath) {
> - JsonElement jsonElement = eval(propPath);
> - return jsonElement.getAsFloat();
> - }
> -
> - public int getAsInt(String propPath) {
> - JsonElement jsonElement = eval(propPath);
> - return jsonElement.getAsInt();
> - }
> -
> - public long getAsLong(String propPath) {
> - JsonElement jsonElement = eval(propPath);
> - return jsonElement.getAsLong();
> - }
> -
> - public Number getAsNumber(String propPath) {
> - JsonElement jsonElement = eval(propPath);
> - return jsonElement.getAsNumber();
> - }
> -
> - public short getAsShort(String propPath) {
> - JsonElement jsonElement = eval(propPath);
> - return jsonElement.getAsShort();
> - }
> -
> - public String getAsString(String propPath) {
> - JsonElement jsonElement = eval(propPath);
> - return jsonElement.getAsString();
> - }
> -
> - public boolean isBoolean(String propPath) {
> - JsonElement jsonElement = eval(propPath);
> - if (jsonElement instanceof JsonPrimitive)
> - return ((JsonPrimitive)jsonElement).isBoolean();
> -
> - return false;
> - }
> -
> - public boolean isNumber(String propPath) {
> - JsonElement jsonElement = eval(propPath);
> -
> - if (jsonElement instanceof JsonPrimitive)
> - return ((JsonPrimitive)jsonElement).isNumber();
> - return false;
> - }
> -
> - public boolean isString(String propPath) {
> - JsonElement jsonElement = eval(propPath);
> -
> - if (jsonElement instanceof JsonPrimitive)
> - return ((JsonPrimitive)jsonElement).isString();
> - return false;
> - }
> -
> - /*
> - * Return
> - * -1 : property expression can not be resolved
> - * 0 : match to a null JSON object
> - * 1+ : matched, for array element, the count of the elements inside the array
> - */
> - public int getMatchCount(String propPath) {
> - JsonElement jsonElement = tryEval(propPath);
> - if (jsonElement == null)
> - return -1;
> -
> - if (jsonElement.isJsonNull())
> - return 0;
> -
> - if (jsonElement.isJsonArray())
> - return ((JsonArray)jsonElement).size();
> -
> - return 1;
> - }
> -
> - public JsonElement eval(String propPath) {
> - JsonElement jsonElement = tryEval(propPath);
> - if (jsonElement == null)
> - throw new InternalErrorException("Property " + propPath + " is resolved to null JSON element on object: " + _json.toString());
> -
> - return jsonElement;
> - }
> -
> - public JsonElement tryEval(String propPath) {
> - assert (propPath != null);
> - String[] tokens = propPath.split("\\.");
> -
> - ArrayList<Resolver> resolverChain = new ArrayList<Resolver>();
> - for (String token : tokens) {
> - Matcher matcher = _arrayAccessorMatcher.matcher(token);
> - if (matcher.find()) {
> - String propStr = matcher.group(1);
> - String indexStr = matcher.group(2);
> -
> - resolverChain.add(new ArrayPropertyResolver(propStr, Integer.parseInt(indexStr)));
> - } else {
> - resolverChain.add(new PropertyResolver(token));
> - }
> - }
> -
> - JsonElement jsonElementToResolveAt = _json;
> - for (Resolver resolver : resolverChain) {
> - jsonElementToResolveAt = resolver.resolve(jsonElementToResolveAt);
> -
> - if (jsonElementToResolveAt == null)
> - break;
> - }
> -
> - return jsonElementToResolveAt;
> - }
> -
> - //
> - // Property resolvers
> - //
> - private static interface Resolver {
> - public JsonElement resolve(JsonElement jsonElementToResolveAt);
> - }
> -
> - private static class PropertyResolver implements Resolver {
> - protected String _propName;
> -
> - public PropertyResolver(String propName) {
> - _propName = propName;
> - }
> -
> - public JsonElement resolve(JsonElement jsonElementToResolveAt) {
> - if ("this".equals(_propName))
> - return jsonElementToResolveAt;
> -
> - if (jsonElementToResolveAt.isJsonObject())
> - return ((JsonObject)jsonElementToResolveAt).get(_propName);
> -
> - if (jsonElementToResolveAt.isJsonNull())
> - throw new NullPointerException(String.format("Property %s points to a null element on object: %s", _propName, jsonElementToResolveAt.toString()));
> -
> - throw new InternalErrorException("Unable to evaluate JSON accessor property: " + _propName + ", on object: " + jsonElementToResolveAt.toString());
> - }
> - }
> -
> - private static class ArrayPropertyResolver extends PropertyResolver {
> - protected int _index;
> -
> - public ArrayPropertyResolver(String propName, int index) {
> - super(propName);
> - _index = index;
> - }
> -
> - public JsonElement resolve(JsonElement jsonElementToResolveAt) {
> - if (!"this".equals(_propName)) {
> - if (jsonElementToResolveAt.isJsonObject()) {
> - jsonElementToResolveAt = ((JsonObject)jsonElementToResolveAt).get(_propName);
> - } else {
> - if (jsonElementToResolveAt.isJsonNull())
> - throw new NullPointerException(String.format("Property %s points to a null element on object: %s", _propName, jsonElementToResolveAt.toString()));
> -
> - throw new InternalErrorException("Unable to evaluate JSON accessor property: " + _propName + ", on object: " + jsonElementToResolveAt.toString());
> - }
> - }
> -
> - if (jsonElementToResolveAt instanceof JsonArray) {
> - return ((JsonArray)jsonElementToResolveAt).get(_index);
> - }
> -
> - if (jsonElementToResolveAt.isJsonNull())
> - throw new NullPointerException(String.format("Property %s points to a null element on object: %s", _propName, jsonElementToResolveAt.toString()));
> -
> - throw new InternalErrorException("Unable to evaluate JSON accessor property: " + _propName + ", on object: " + jsonElementToResolveAt.toString());
> - }
> - }
> -}
>
> http://git-wip-us.apache.org/repos/asf/cloudstack/blob/a5510a0a/awsapi/src/com/cloud/bridge/util/JsonElementUtil.java
> ----------------------------------------------------------------------
> diff --git a/awsapi/src/com/cloud/bridge/util/JsonElementUtil.java b/awsapi/src/com/cloud/bridge/util/JsonElementUtil.java
> new file mode 100644
> index 0000000..2d8afb5
> --- /dev/null
> +++ b/awsapi/src/com/cloud/bridge/util/JsonElementUtil.java
> @@ -0,0 +1,45 @@
> +package com.cloud.bridge.util;
> +
> +import com.google.gson.JsonElement;
> +import com.google.gson.JsonObject;
> +import com.google.gson.JsonPrimitive;
> +
> +/**
> + * @author Dmitry Batkovich
> + *
> + * For more complex cases (JsonArrays or other) it can be rewrite to matcher pattern
> + */
> +public final class JsonElementUtil {
> +
> + private JsonElementUtil() {}
> +
> + public static JsonElement getAsJsonElement(final JsonElement jsonElement, final String... path) {
> + JsonElement currentElement = jsonElement;
> + for (final String propertyName : path) {
> + if (currentElement == null) {
> + return null;
> + }
> + if (jsonElement.isJsonObject()) {
> + currentElement = ((JsonObject) currentElement).get(propertyName);
> + } else {
> + return null;
> + }
> + }
> + return currentElement;
> + }
> +
> + public static Integer getAsInt(final JsonElement jsonElement, final String... path) {
> + final JsonElement targetElement = getAsJsonElement(jsonElement, path);
> + if (targetElement == null || !targetElement.isJsonPrimitive()) {
> + return null;
> + }
> + final JsonPrimitive asPrimitive = (JsonPrimitive) targetElement;
> + return asPrimitive.getAsInt();
> + }
> +
> + public static String getAsString(final JsonElement jsonElement, final String... path) {
> + final JsonElement targetElement = getAsJsonElement(jsonElement, path);
> + return targetElement == null ? null : targetElement.getAsString();
> + }
> +
> +}
>
> http://git-wip-us.apache.org/repos/asf/cloudstack/blob/a5510a0a/awsapi/src/com/cloud/stack/CloudStackClientException.java
> ----------------------------------------------------------------------
> diff --git a/awsapi/src/com/cloud/stack/CloudStackClientException.java b/awsapi/src/com/cloud/stack/CloudStackClientException.java
> new file mode 100644
> index 0000000..ac1b3ef
> --- /dev/null
> +++ b/awsapi/src/com/cloud/stack/CloudStackClientException.java
> @@ -0,0 +1,21 @@
> +package com.cloud.stack;
> +
> +/**
> + * @author Dmitry Batkovich
> + */
> +public class CloudStackClientException extends Exception {
> + public CloudStackClientException() {
> + }
> +
> + public CloudStackClientException(final String s) {
> + super(s);
> + }
> +
> + public CloudStackClientException(final String s, final Throwable throwable) {
> + super(s, throwable);
> + }
> +
> + public CloudStackClientException(final Throwable throwable) {
> + super(throwable);
> + }
> +}
>
> http://git-wip-us.apache.org/repos/asf/cloudstack/blob/a5510a0a/awsapi/src/com/cloud/stack/CloudStackCommand.java
> ----------------------------------------------------------------------
> diff --git a/awsapi/src/com/cloud/stack/CloudStackCommand.java b/awsapi/src/com/cloud/stack/CloudStackCommand.java
> deleted file mode 100644
> index 8d6aa68..0000000
> --- a/awsapi/src/com/cloud/stack/CloudStackCommand.java
> +++ /dev/null
> @@ -1,149 +0,0 @@
> -// Licensed to the Apache Software Foundation (ASF) under one
> -// or more contributor license agreements. See the NOTICE file
> -// distributed with this work for additional information
> -// regarding copyright ownership. The ASF licenses this file
> -// to you under the Apache License, Version 2.0 (the
> -// "License"); you may not use this file except in compliance
> -// with the License. You may obtain a copy of the License at
> -//
> -// http://www.apache.org/licenses/LICENSE-2.0
> -//
> -// Unless required by applicable law or agreed to in writing,
> -// software distributed under the License is distributed on an
> -// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
> -// KIND, either express or implied. See the License for the
> -// specific language governing permissions and limitations
> -// under the License.
> -package com.cloud.stack;
> -
> -import java.io.UnsupportedEncodingException;
> -import java.net.URLEncoder;
> -import java.security.SignatureException;
> -import java.util.ArrayList;
> -import java.util.Collections;
> -import java.util.HashMap;
> -import java.util.List;
> -import java.util.Map;
> -
> -import javax.crypto.Mac;
> -import javax.crypto.spec.SecretKeySpec;
> -
> -import org.apache.commons.codec.binary.Base64;
> -
> -/**
> - * CloudStackCommand wraps command properties that are being sent to CloudStack
> - *
> - */
> -public class CloudStackCommand {
> - Map<String, String> _params = new HashMap<String, String>();
> -
> - public CloudStackCommand(String cmdName) {
> - this(cmdName, "json");
> - }
> -
> - public CloudStackCommand(String cmdName, String responseType) {
> - _params.put("command", cmdName);
> - if (responseType != null)
> - _params.put("response", responseType);
> - }
> -
> - public CloudStackCommand setParam(String paramName, String paramValue) {
> - assert (paramName != null);
> - assert (paramValue != null);
> -
> - _params.put(paramName, paramValue);
> - return this;
> - }
> -
> - public String signCommand(String apiKey, String secretKey) throws SignatureException {
> - assert (_params.get("command") != null);
> -
> - List<String> paramNames = new ArrayList<String>();
> - for (String paramName : _params.keySet())
> - paramNames.add(paramName);
> -
> - paramNames.add("apikey");
> - Collections.sort(paramNames);
> -
> - StringBuffer sb = new StringBuffer();
> - for (String name : paramNames) {
> - String value;
> - if ("apikey".equals(name))
> - value = apiKey;
> - else
> - value = _params.get(name);
> -
> - assert (value != null);
> -
> - value = urlSafe(value);
> -
> - if (sb.length() == 0) {
> - sb.append(name).append("=").append(value);
> - } else {
> - sb.append("&").append(name).append("=").append(value);
> - }
> - }
> -
> - String signature = calculateRFC2104HMAC(sb.toString().toLowerCase(), secretKey);
> - return composeQueryString(apiKey, signature);
> - }
> -
> - private String composeQueryString(String apiKey, String signature) {
> - StringBuffer sb = new StringBuffer();
> - String name;
> - String value;
> -
> - // treat command specially (although not really necessary )
> - name = "command";
> - value = _params.get(name);
> - if (value != null) {
> - value = urlSafe(value);
> - sb.append(name).append("=").append(value);
> - }
> -
> - for (Map.Entry<String, String> entry : _params.entrySet()) {
> - name = entry.getKey();
> -
> - if (!"command".equals(name)) {
> - value = urlSafe(entry.getValue());
> -
> - if (sb.length() == 0)
> - sb.append(name).append("=").append(value);
> - else
> - sb.append("&").append(name).append("=").append(value);
> - }
> - }
> -
> - sb.append("&apikey=").append(urlSafe(apiKey));
> - sb.append("&signature=").append(urlSafe(signature));
> -
> - return sb.toString();
> - }
> -
> - private String calculateRFC2104HMAC(String signIt, String secretKey) throws SignatureException {
> - String result = null;
> - try {
> - SecretKeySpec key = new SecretKeySpec(secretKey.getBytes(), "HmacSHA1");
> - Mac hmacSha1 = Mac.getInstance("HmacSHA1");
> - hmacSha1.init(key);
> - byte[] rawHmac = hmacSha1.doFinal(signIt.getBytes());
> - result = new String(Base64.encodeBase64(rawHmac));
> - } catch (Exception e) {
> - throw new SignatureException("Failed to generate keyed HMAC on soap request: " + e.getMessage());
> - }
> - return result.trim();
> - }
> -
> - private String urlSafe(String value) {
> - try {
> - if (value != null)
> - return URLEncoder.encode(value, "UTF-8").replaceAll("\\+", "%20");
> - else
> - return null;
> - } catch (UnsupportedEncodingException e) {
> - assert (false);
> - }
> -
> - return value;
> - }
> -}
>
> http://git-wip-us.apache.org/repos/asf/cloudstack/blob/a5510a0a/awsapi/src/com/cloud/stack/CloudStackQueryBuilder.java
> ----------------------------------------------------------------------
> diff --git a/awsapi/src/com/cloud/stack/CloudStackQueryBuilder.java b/awsapi/src/com/cloud/stack/CloudStackQueryBuilder.java
> new file mode 100644
> index 0000000..a7aff68
> --- /dev/null
> +++ b/awsapi/src/com/cloud/stack/CloudStackQueryBuilder.java
> @@ -0,0 +1,118 @@
> +// Licensed to the Apache Software Foundation (ASF) under one
> +// or more contributor license agreements. See the NOTICE file
> +// distributed with this work for additional information
> +// regarding copyright ownership. The ASF licenses this file
> +// to you under the Apache License, Version 2.0 (the
> +// "License"); you may not use this file except in compliance
> +// with the License. You may obtain a copy of the License at
> +//
> +// http://www.apache.org/licenses/LICENSE-2.0
> +//
> +// Unless required by applicable law or agreed to in writing,
> +// software distributed under the License is distributed on an
> +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
> +// KIND, either express or implied. See the License for the
> +// specific language governing permissions and limitations
> +// under the License.
> +package com.cloud.stack;
> +
> +import java.io.UnsupportedEncodingException;
> +import java.net.URLEncoder;
> +import java.security.SignatureException;
> +import java.util.*;
> +
> +import javax.crypto.Mac;
> +import javax.crypto.spec.SecretKeySpec;
> +
> +import com.cloud.utils.StringUtils;
> +import org.apache.commons.codec.binary.Base64;
> +import org.apache.commons.httpclient.HttpMethod;
> +import org.apache.commons.httpclient.NameValuePair;
> +import org.apache.commons.httpclient.URI;
> +import org.apache.commons.httpclient.URIException;
> +import org.apache.commons.httpclient.methods.GetMethod;
> +import org.apache.commons.httpclient.methods.PostMethod;
> +
> +/**
> + * CloudStackQueryBuilder wraps command properties that are being sent to CloudStack
> + */
> +public class CloudStackQueryBuilder {
> + private static final String HMAC_SHA_1 = "HmacSHA1";
> + private static final String COMMAND_KEY = "command";
> + private static final String APIKEY_KEY = "apikey";
> +
> + private final Collection<NameValuePair> params = new ArrayList<NameValuePair>();
> +
> + public CloudStackQueryBuilder(final String commandName) {
> + params.add(new NameValuePair("command", commandName));
> + params.add(new NameValuePair("response", "json"));
> + }
> +
> + public static CloudStackQueryBuilder create(final String commandName) {
> + return new CloudStackQueryBuilder(commandName);
> + }
> +
> + /**
> + * parameter will be stored to query only if paramValue != null. This assumption is very useful
> + * for optional parameters
> + * @param paramName - not null parameter name
> + * @param paramValue - nullable parameter value
> + */
> + public CloudStackQueryBuilder addParam(final String paramName, final Object paramValue) {
> + if (paramName == null) {
> + throw new NullPointerException();
> + }
> + if (paramValue != null) {
> + params.add(new NameValuePair(paramName, String.valueOf(paramValue)));
> + }
> + return this;
> + }
> +
> + public HttpMethod buildRequest(final String apiKey, final String secretKey) throws SignatureException {
> + final PostMethod postMethod = new PostMethod();
> + for (final NameValuePair param : params) {
> + postMethod.addParameter(param);
> + }
> + postMethod.addParameter(APIKEY_KEY, apiKey);
> + postMethod.addParameter("signature", calculateSignature(secretKey, apiKey));
> + return postMethod;
> + }
> +
> + private String calculateSignature(final String secretKey, final String apiKey) throws SignatureException {
> + final List<NameValuePair> paramsCopy = new ArrayList<NameValuePair>(params.size() + 1);
> + paramsCopy.addAll(params);
> + paramsCopy.add(new NameValuePair(APIKEY_KEY, urlSafe(apiKey)));
> + Collections.sort(paramsCopy, new Comparator<NameValuePair>() {
> + @Override
> + public int compare(final NameValuePair nameValuePair, final NameValuePair nameValuePair2) {
> + return nameValuePair.getName().compareTo(nameValuePair2.getName());
> + }
> + });
> +
> + final List<String> serializedParameters = new ArrayList<String>(paramsCopy.size());
> + for (final NameValuePair pair : paramsCopy) {
> + serializedParameters.add(pair.getName() + "=" + urlSafe(pair.getValue()));
> + }
> + final String toSign = StringUtils.join(serializedParameters, "&").toLowerCase();
> + return calculateRFC2104HMAC(toSign, secretKey);
> + }
> +
> + private static String calculateRFC2104HMAC(final String signIt, final String secretKey) throws SignatureException {
> + try {
> + final Mac hmacSha1 = Mac.getInstance(HMAC_SHA_1);
> + hmacSha1.init(new SecretKeySpec(secretKey.getBytes(), HMAC_SHA_1));
> + final byte[] rawHmac = hmacSha1.doFinal(signIt.getBytes());
> + return new String(Base64.encodeBase64(rawHmac)).trim();
> + } catch (final Exception e) {
> + throw new SignatureException("Failed to generate keyed HMAC on soap request: " + e.getMessage());
> + }
> + }
> +
> + private static String urlSafe(final String value) {
> + try {
> + return value == null ? null : URLEncoder.encode(value, "UTF-8").replaceAll("\\+", "%20");
> + } catch (final UnsupportedEncodingException e) {
> + throw new RuntimeException(e);
> + }
> + }
> +}
>
> http://git-wip-us.apache.org/repos/asf/cloudstack/blob/a5510a0a/awsapi/test/com/cloud/gate/util/JsonAccessorTestCase.java
> ----------------------------------------------------------------------
> diff --git a/awsapi/test/com/cloud/gate/util/JsonAccessorTestCase.java b/awsapi/test/com/cloud/gate/util/JsonAccessorTestCase.java
> deleted file mode 100644
> index 8603e59..0000000
> --- a/awsapi/test/com/cloud/gate/util/JsonAccessorTestCase.java
> +++ /dev/null
> @@ -1,69 +0,0 @@
> -// Licensed to the Apache Software Foundation (ASF) under one
> -// or more contributor license agreements. See the NOTICE file
> -// distributed with this work for additional information
> -// regarding copyright ownership. The ASF licenses this file
> -// to you under the Apache License, Version 2.0 (the
> -// "License"); you may not use this file except in compliance
> -// with the License. You may obtain a copy of the License at
> -//
> -// http://www.apache.org/licenses/LICENSE-2.0
> -//
> -// Unless required by applicable law or agreed to in writing,
> -// software distributed under the License is distributed on an
> -// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
> -// KIND, either express or implied. See the License for the
> -// specific language governing permissions and limitations
> -// under the License.
> -package com.cloud.gate.util;
> -
> -import junit.framework.Assert;
> -
> -import org.apache.log4j.Logger;
> -
> -import com.google.gson.Gson;
> -import com.google.gson.JsonElement;
> -import com.google.gson.JsonParser;
> -
> -import com.cloud.bridge.util.JsonAccessor;
> -import com.cloud.gate.testcase.BaseTestCase;
> -import com.cloud.stack.models.CloudStackSnapshot;
> -
> -public class JsonAccessorTestCase extends BaseTestCase {
> - protected final static Logger logger = Logger.getLogger(UtilTestCase.class);
> -
> - public void testJsonAccessor() {
> - JsonParser parser = new JsonParser();
> - JsonElement json = parser.parse("{firstName: 'Kelven', lastName: 'Yang', arrayObj: [{name: 'elem1'}, {name: 'elem2'}]}");
> - JsonAccessor jsonAccessor = new JsonAccessor(json);
> -
> - Assert.assertTrue("Kelven".equals(jsonAccessor.getAsString("firstName")));
> - Assert.assertTrue("Kelven".equals(jsonAccessor.getAsString("this.firstName")));
> - Assert.assertTrue("Yang".equals(jsonAccessor.getAsString("lastName")));
> - Assert.assertTrue("Yang".equals(jsonAccessor.getAsString("this.lastName")));
> -
> - Assert.assertTrue("elem1".equals(jsonAccessor.getAsString("arrayObj[0].name")));
> - Assert.assertTrue("elem2".equals(jsonAccessor.getAsString("arrayObj[1].name")));
> -
> - Assert.assertTrue("elem1".equals(jsonAccessor.getAsString("this.arrayObj.this[0].name")));
> - Assert.assertTrue("elem2".equals(jsonAccessor.getAsString("this.arrayObj.this[1].name")));
> -
> - Assert.assertTrue(jsonAccessor.getMatchCount("firstName") == 1);
> - Assert.assertTrue(jsonAccessor.getMatchCount("middleName") == -1);
> - Assert.assertTrue(jsonAccessor.getMatchCount("arrayObj") == 2);
> - Assert.assertTrue(jsonAccessor.getMatchCount("arrayObj[0]") == 1);
> - }
> -
> - public void testGson() {
> - String response =
> - "{ \"queryasyncjobresultresponse\" : {\"jobid\":5868,\"jobstatus\":1,\"jobprocstatus\":0,\"jobresultcode\":0,\"jobresulttype\":\"object\",\"jobresult\":{\"snapshot\":{\"id\":3161,\"account\":\"admin\",\"domainid\":1,\"domain\":\"ROOT\",\"snapshottype\":\"MANUAL\",\"volumeid\":186928,\"volumename\":\"KY-DATA-VOL\",\"volumetype\":\"DATADISK\",\"created\":\"2011-06-02T05:05:41-0700\",\"name\":\"i-2-246446-VM_KY-DATA-VOL_20110602120541\",\"intervaltype\":\"MANUAL\",\"state\":\"BackedUp\"}}}}";
> -
> - JsonParser parser = new JsonParser();
> - JsonElement json = parser.parse(response);
> - JsonAccessor jsonAccessor = new JsonAccessor(json);
> -
> - Gson gson = new Gson();
> - CloudStackSnapshot snapshot = gson.fromJson(jsonAccessor.eval("queryasyncjobresultresponse.jobresult.snapshot"), CloudStackSnapshot.class);
> -
> - Assert.assertTrue("BackedUp".equals(snapshot.getState()));
> - }
> -}
>
> http://git-wip-us.apache.org/repos/asf/cloudstack/blob/a5510a0a/awsapi/test/com/cloud/gate/util/JsonElementUtilTestCase.java
> ----------------------------------------------------------------------
> diff --git a/awsapi/test/com/cloud/gate/util/JsonElementUtilTestCase.java b/awsapi/test/com/cloud/gate/util/JsonElementUtilTestCase.java
> new file mode 100644
> index 0000000..8b4f267
> --- /dev/null
> +++ b/awsapi/test/com/cloud/gate/util/JsonElementUtilTestCase.java
> @@ -0,0 +1,48 @@
> +// Licensed to the Apache Software Foundation (ASF) under one
> +// or more contributor license agreements. See the NOTICE file
> +// distributed with this work for additional information
> +// regarding copyright ownership. The ASF licenses this file
> +// to you under the Apache License, Version 2.0 (the
> +// "License"); you may not use this file except in compliance
> +// with the License. You may obtain a copy of the License at
> +//
> +// http://www.apache.org/licenses/LICENSE-2.0
> +//
> +// Unless required by applicable law or agreed to in writing,
> +// software distributed under the License is distributed on an
> +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
> +// KIND, either express or implied. See the License for the
> +// specific language governing permissions and limitations
> +// under the License.
> +package com.cloud.gate.util;
> +
> +import com.cloud.bridge.util.JsonElementUtil;
> +import com.google.gson.JsonArray;
> +import junit.framework.Assert;
> +
> +import com.cloud.gate.testcase.BaseTestCase;
> +import com.cloud.stack.models.CloudStackSnapshot;
> +import com.google.gson.Gson;
> +import com.google.gson.JsonElement;
> +import com.google.gson.JsonParser;
> +
> +public class JsonElementUtilTestCase extends BaseTestCase {
> + private final static JsonParser JSON_PARSER = new JsonParser();
> +
> + public void testJsonElementUtils() {
> + JsonElement json = JSON_PARSER.parse("{firstName: 'Kelven', lastName: 'Yang', arrayObj: [{name: 'elem1'}, {name: 'elem2'}], level1: {level2: 'some'}}");
> +
> + assertEquals("Kelven", JsonElementUtil.getAsString(json, "firstName"));
> + assertEquals("Yang", JsonElementUtil.getAsString(json, "lastName"));
> + assertEquals("some", JsonElementUtil.getAsString(json, "level1", "level2"));
> + assertTrue(JsonElementUtil.getAsJsonElement(json, "arrayObj") instanceof JsonArray);
> + }
> +
> + public void testGson() {
> + String response = "{ \"queryasyncjobresultresponse\" : {\"jobid\":5868,\"jobstatus\":1,\"jobprocstatus\":0,\"jobresultcode\":0,\"jobresulttype\":\"object\",\"jobresult\":{\"snapshot\":{\"id\":3161,\"account\":\"admin\",\"domainid\":1,\"domain\":\"ROOT\",\"snapshottype\":\"MANUAL\",\"volumeid\":186928,\"volumename\":\"KY-DATA-VOL\",\"volumetype\":\"DATADISK\",\"created\":\"2011-06-02T05:05:41-0700\",\"name\":\"i-2-246446-VM_KY-DATA-VOL_20110602120541\",\"intervaltype\":\"MANUAL\",\"state\":\"BackedUp\"}}}}";
> + JsonElement json = JSON_PARSER.parse(response);
> + Gson gson = new Gson();
> + CloudStackSnapshot snapshot = gson.fromJson(JsonElementUtil.getAsJsonElement(json, "queryasyncjobresultresponse", "jobresult", "snapshot"), CloudStackSnapshot.class);
> + Assert.assertTrue("BackedUp".equals(snapshot.getState()));
> + }
> +}
>