Skip to content

Commit

Permalink
Merge pull request #821 from Arcticwolf/OPENENGSB-3539
Browse files Browse the repository at this point in the history
[OPENENGSB-3539] added additional serializer to the JsonUtils class
  • Loading branch information
anpieber committed Mar 15, 2013
2 parents e49bb3b + 92f0ad8 commit b116909
Show file tree
Hide file tree
Showing 6 changed files with 265 additions and 0 deletions.
@@ -0,0 +1,87 @@
/**
* Licensed to the Austrian Association for Software Tool Integration (AASTI)
* under one or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information regarding copyright
* ownership. The AASTI 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 org.openengsb.core.services.internal;

import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;

import java.io.IOException;
import java.util.Arrays;
import java.util.List;

import org.junit.Test;
import org.openengsb.core.api.model.OpenEngSBModelEntry;
import org.openengsb.core.services.internal.model.NullModel;
import org.openengsb.core.services.internal.model.SubModel;
import org.openengsb.core.util.JsonUtils;
import org.openengsb.core.util.ModelUtils;

import com.fasterxml.jackson.databind.ObjectMapper;

public class JsonSupportTest {
private ObjectMapper mapper;

public JsonSupportTest() {
mapper = new ObjectMapper();
}

private NullModel createTestModel() {
NullModel model = new NullModel();
model.setId(20);
model.setValue("test");
SubModel sub1 = new SubModel();
sub1.setId("sub1");
sub1.setName("test1");
SubModel sub2 = new SubModel();
sub2.setId("sub2");
sub2.setName("test2");
model.setSubs(Arrays.asList(sub1, sub2));

ModelUtils.addOpenEngSBModelEntry(model, new OpenEngSBModelEntry("test", "test", String.class));
ModelUtils.addOpenEngSBModelEntry(model, new OpenEngSBModelEntry("test2", "test2", String.class));
return model;
}

@Test(expected = IOException.class)
public void tryConvertJSONIntoModelWithoutAdditionalSerializer_shouldThrowException() throws Exception {
NullModel model = createTestModel();
String result = mapper.writeValueAsString(model);
// the read value call without the additional serialzer throws an IOException because it can not
// deserialize the model tail
mapper.readValue(result, NullModel.class);
}

@Test
public void tryConvertJSONIntoModelWithAdditionalSerializer_shouldThrowNoException() throws Exception {
NullModel model = createTestModel();
String result = mapper.writeValueAsString(model);

NullModel other = JsonUtils.convertObject(result, NullModel.class);
List<OpenEngSBModelEntry> entries = ModelUtils.getOpenEngSBModelTail(other);
assertThat(model.getId(), is(other.getId()));
assertThat(model.getValue(), is(other.getValue()));
assertThat(model.getSubs().size(), is(other.getSubs().size()));
assertThat(model.getSubs().get(0).getId(), is(other.getSubs().get(0).getId()));
assertThat(model.getSubs().get(0).getName(), is(other.getSubs().get(0).getName()));
assertThat(model.getSubs().get(1).getId(), is(other.getSubs().get(1).getId()));
assertThat(model.getSubs().get(1).getName(), is(other.getSubs().get(1).getName()));
assertThat(entries.size(), is(2));
assertThat(entries.contains(new OpenEngSBModelEntry("test", "test", String.class)), is(true));
assertThat(entries.contains(new OpenEngSBModelEntry("test2", "test2", String.class)), is(true));
}
}
Expand Up @@ -16,6 +16,8 @@
*/
package org.openengsb.core.services.internal.model;

import java.util.List;

import org.openengsb.core.api.Constants;
import org.openengsb.core.api.model.annotation.Model;
import org.openengsb.core.api.model.annotation.OpenEngSBModelId;
Expand All @@ -27,6 +29,7 @@ public class NullModel {
@OpenEngSBModelId
private Integer id;
private String value;
private List<SubModel> subs;

public Integer getId() {
return id;
Expand All @@ -43,4 +46,13 @@ public String getValue() {
public void setValue(String value) {
this.value = value;
}

public List<SubModel> getSubs() {
return subs;
}

public void setSubs(List<SubModel> subs) {
this.subs = subs;
}

}
@@ -0,0 +1,48 @@
/**
* Licensed to the Austrian Association for Software Tool Integration (AASTI)
* under one or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information regarding copyright
* ownership. The AASTI 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 org.openengsb.core.services.internal.model;

import org.openengsb.core.api.Constants;
import org.openengsb.core.api.model.annotation.Model;
import org.openengsb.core.api.model.annotation.OpenEngSBModelId;
import org.openengsb.labs.delegation.service.Provide;

@Model
@Provide(context = Constants.DELEGATION_CONTEXT_MODELS)
public class SubModel {
@OpenEngSBModelId
private String id;
private String name;

public String getId() {
return id;
}

public void setId(String id) {
this.id = id;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

}
Expand Up @@ -17,20 +17,27 @@

package org.openengsb.core.util;

import java.io.IOException;
import java.lang.reflect.Array;
import java.util.List;

import org.openengsb.core.api.model.OpenEngSBModelEntry;
import org.openengsb.core.api.remote.MethodCall;
import org.openengsb.core.api.remote.MethodCallMessage;
import org.openengsb.core.api.remote.MethodResult;
import org.openengsb.core.api.remote.MethodResultMessage;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonToken;
import com.fasterxml.jackson.databind.AnnotationIntrospector;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.deser.std.StdScalarDeserializer;
import com.fasterxml.jackson.databind.introspect.AnnotationIntrospectorPair;
import com.fasterxml.jackson.databind.introspect.JacksonAnnotationIntrospector;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.module.jaxb.JaxbAnnotationIntrospector;
import com.google.common.base.Preconditions;

Expand All @@ -40,6 +47,25 @@ public final class JsonUtils {

private static final ObjectMapper MAPPER = new ObjectMapper();

static {
// adding the additional deserializer needed to deserialize models
MAPPER.registerModule(new SimpleModule().addDeserializer(Object.class, new OpenEngSBModelEntryDeserializer()));
}

/**
* Converts an object in JSON format to the given class. Throws an IOException if the conversion could not be
* performed.
*/
public static <T> T convertObject(String json, Class<T> clazz) throws IOException {
try {
return MAPPER.readValue(json, clazz);
} catch (IOException e) {
String error = String.format("Unable to parse given json '%s' into class '%s'.", json, clazz.getName());
LOGGER.error(error, e);
throw new IOException(error, e);
}
}

private static Object convertArgument(String className, Object arg) {
try {
Class<?> type = findType(className);
Expand Down Expand Up @@ -93,4 +119,48 @@ public static ObjectMapper createObjectMapperWithIntroSpectors() {

private JsonUtils() {
}

/**
* The OpenEngSBModelEntryDeserializer class is needed in order to be able to transform the list of
* OpenEngSBModelEntry elements, which is contained in every model tail, from a JSON string into a list of actual
* elements.
*/
@SuppressWarnings("serial")
private static class OpenEngSBModelEntryDeserializer extends StdScalarDeserializer<OpenEngSBModelEntry> {
public OpenEngSBModelEntryDeserializer() {
super(OpenEngSBModelEntry.class);
}

@Override
public OpenEngSBModelEntry deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException {
JsonToken token = jp.getCurrentToken();
OpenEngSBModelEntry entry = new OpenEngSBModelEntry();
if (token != JsonToken.START_OBJECT) {
return null;
} else {
// skip the JsonToken.START_OBJECT token
token = jp.nextValue();
}
do {
if (token == JsonToken.END_OBJECT) {
return entry;
} else {
if (jp.getCurrentName().equals("key")) {
entry.setKey(jp.getValueAsString());
} else if (jp.getCurrentName().equals("value")) {
entry.setValue(jp.getValueAsString());
} else if (jp.getCurrentName().equals("type")) {
try {
entry.setType(findType(jp.getValueAsString()));
} catch (ClassNotFoundException e) {
LOGGER.error("Did not find class of type " + jp.getValueAsString(), e);
break;
}
}
}
token = jp.nextValue();
} while (token != null);
return null;
}
}
}
33 changes: 33 additions & 0 deletions itests/src/test/java/org/openengsb/itests/exam/JMSPortIT.java
Expand Up @@ -45,11 +45,13 @@
import org.junit.runner.RunWith;
import org.openengsb.core.api.AliveState;
import org.openengsb.core.api.model.ConnectorDescription;
import org.openengsb.core.api.model.OpenEngSBModelEntry;
import org.openengsb.core.api.remote.MethodResultMessage;
import org.openengsb.core.api.remote.OutgoingPort;
import org.openengsb.core.common.AbstractOpenEngSBService;
import org.openengsb.core.util.DefaultOsgiUtilsService;
import org.openengsb.core.util.JsonUtils;
import org.openengsb.core.util.ModelUtils;
import org.openengsb.core.workflow.api.model.RuleBaseElementId;
import org.openengsb.core.workflow.api.model.RuleBaseElementType;
import org.openengsb.domain.example.ExampleDomain;
Expand Down Expand Up @@ -218,6 +220,32 @@ public void testSendMethodWithModelAsParamter_shouldWork() throws Exception {
assertThat(decryptedResult.contains("successful"), is(true));
assertThat(model.getResult(), is("successful"));
}

@Test
public void testSendMethodWithModelIncludingTailAsParamter_shouldWork() throws Exception {
ExampleDomain service = new DummyService("test");
Hashtable<String, Object> properties = new Hashtable<String, Object>();
properties.put(Constants.SERVICE_PID, "test");
properties.put(Constants.SERVICE_RANKING, -1);
properties.put("location.root", new String[]{ "foo" });
getBundleContext().registerService(ExampleDomain.class.getName(), service, properties);

JmsTemplate template = prepareActiveMqConnection();
String secureRequest = prepareRequest(METHOD_CALL_WITH_MODEL_INCLUDING_TAIL_PARAMETER, "admin", "password");
SecretKey sessionKey = generateSessionKey();
String encryptedMessage = encryptMessage(secureRequest, sessionKey);

String result = sendMessage(template, encryptedMessage);
String decryptedResult = decryptResult(sessionKey, result);

ObjectMapper mapper = new ObjectMapper();
MethodResultMessage methodResult = mapper.readValue(decryptedResult, MethodResultMessage.class);
JsonUtils.convertResult(methodResult);
ExampleResponseModel model = (ExampleResponseModel) methodResult.getResult().getArg();

assertThat(decryptedResult.contains("successful with tail"), is(true));
assertThat(model.getResult(), is("successful with tail"));
}

private String sendMessage(final JmsTemplate template, final String msg) {
String resultString = template.execute(new SessionCallback<String>() {
Expand Down Expand Up @@ -273,6 +301,11 @@ public AliveState getAliveState() {
public ExampleResponseModel doSomethingWithModel(ExampleRequestModel model) {
ExampleResponseModel response = new ExampleResponseModel();
response.setResult("successful");
for (OpenEngSBModelEntry entry : ModelUtils.getOpenEngSBModelTail(model)) {
if (entry.getKey().equals("specialKey") && entry.getValue().equals("specialValue")) {
response.setResult("successful with tail");
}
}
return response;
}
}
Expand Down
Expand Up @@ -117,6 +117,21 @@ public class AbstractRemoteTestHelper extends AbstractExamTestHelper {
+ " \"args\": ["
+ " { \"id\":10, \"name\":\"test\" } ]"
+ "}";

protected static final String METHOD_CALL_WITH_MODEL_INCLUDING_TAIL_PARAMETER = ""
+ "{"
+ " \"classes\": ["
+ " \"org.openengsb.domain.example.model.ExampleRequestModel\""
+ " ],"
+ " \"methodName\": \"doSomethingWithModel\","
+ " \"metaData\": {"
+ " \"serviceId\": \"test\""
+ " },"
+ " \"args\": ["
+ " { \"id\":10, \"name\":\"test\", \"openEngSBModelTail\" :[{ "
+ " \"key\":\"specialKey\", \"value\":\"specialValue\", \"type\":\"java.lang.String\" }] "
+ " } ]"
+ "}";

protected RuleManager ruleManager;

Expand Down

0 comments on commit b116909

Please sign in to comment.