From d5333f4596460c7123b66ad5c19fc69442696ea2 Mon Sep 17 00:00:00 2001 From: Dmitry Batkovich Date: Mon, 24 Mar 2014 18:46:45 +0400 Subject: [PATCH] cloudstack api post and ssl fix Signed-off-by: Sebastien Goasguen --- .../com/cloud/bridge/util/JsonAccessor.java | 248 ------------------ .../cloud/bridge/util/JsonElementUtil.java | 45 ++++ .../stack/CloudStackClientException.java | 21 ++ .../com/cloud/stack/CloudStackCommand.java | 149 ----------- .../cloud/stack/CloudStackQueryBuilder.java | 118 +++++++++ .../cloud/gate/util/JsonAccessorTestCase.java | 69 ----- .../gate/util/JsonElementUtilTestCase.java | 48 ++++ 7 files changed, 232 insertions(+), 466 deletions(-) delete mode 100644 awsapi/src/com/cloud/bridge/util/JsonAccessor.java create mode 100644 awsapi/src/com/cloud/bridge/util/JsonElementUtil.java create mode 100644 awsapi/src/com/cloud/stack/CloudStackClientException.java delete mode 100644 awsapi/src/com/cloud/stack/CloudStackCommand.java create mode 100644 awsapi/src/com/cloud/stack/CloudStackQueryBuilder.java delete mode 100644 awsapi/test/com/cloud/gate/util/JsonAccessorTestCase.java create mode 100644 awsapi/test/com/cloud/gate/util/JsonElementUtilTestCase.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 2a94deaf31e..00000000000 --- 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 resolverChain = new ArrayList(); - 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()); - } - } -} 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 00000000000..2d8afb545fa --- /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(); + } + +} diff --git a/awsapi/src/com/cloud/stack/CloudStackClientException.java b/awsapi/src/com/cloud/stack/CloudStackClientException.java new file mode 100644 index 00000000000..ac1b3ef573e --- /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); + } +} diff --git a/awsapi/src/com/cloud/stack/CloudStackCommand.java b/awsapi/src/com/cloud/stack/CloudStackCommand.java deleted file mode 100644 index 8d6aa68837d..00000000000 --- 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 _params = new HashMap(); - - 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 paramNames = new ArrayList(); - 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 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; - } -} diff --git a/awsapi/src/com/cloud/stack/CloudStackQueryBuilder.java b/awsapi/src/com/cloud/stack/CloudStackQueryBuilder.java new file mode 100644 index 00000000000..a7aff6869f3 --- /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 params = new ArrayList(); + + 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 paramsCopy = new ArrayList(params.size() + 1); + paramsCopy.addAll(params); + paramsCopy.add(new NameValuePair(APIKEY_KEY, urlSafe(apiKey))); + Collections.sort(paramsCopy, new Comparator() { + @Override + public int compare(final NameValuePair nameValuePair, final NameValuePair nameValuePair2) { + return nameValuePair.getName().compareTo(nameValuePair2.getName()); + } + }); + + final List serializedParameters = new ArrayList(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); + } + } +} 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 8603e593440..00000000000 --- 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())); - } -} 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 00000000000..8b4f267e506 --- /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())); + } +}