Created
September 12, 2011 10:36
-
-
Save anpieber/1210983 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| diff --git a/core/api/src/main/java/org/openengsb/core/api/remote/CustomJsonMarshaller.java b/core/api/src/main/java/org/openengsb/core/api/remote/CustomJsonMarshaller.java | |
| new file mode 100644 | |
| index 0000000..a598eef | |
| --- /dev/null | |
| +++ b/core/api/src/main/java/org/openengsb/core/api/remote/CustomJsonMarshaller.java | |
| @@ -0,0 +1,36 @@ | |
| +/** | |
| + * 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.api.remote; | |
| + | |
| +/** | |
| + * Custom mapper interface used in case of json argument marshalling. The problem is that java does not have static type | |
| + * information which finally requires that you add custom marshaller. For example the default marshalling process has no | |
| + * idea about e.g. of a generic list of type X. | |
| + * | |
| + * To configure the custom marshaller for an argument use the {@link UseCustomJasonMarshaller} annotation at the param | |
| + * with the classname. The two conditions which have to be fullfilled are that the class has a default constructure and | |
| + * that it implements this interface. | |
| + */ | |
| +public interface CustomJsonMarshaller<OutputType> { | |
| + | |
| + /** | |
| + * Map an object argument with (optional) use of the mapper into the specific object of type OutputType. | |
| + */ | |
| + OutputType transformArg(Object arg); | |
| + | |
| +} | |
| diff --git a/core/api/src/main/java/org/openengsb/core/api/remote/UseCustomJasonMarshaller.java b/core/api/src/main/java/org/openengsb/core/api/remote/UseCustomJasonMarshaller.java | |
| new file mode 100644 | |
| index 0000000..9b7e7e1 | |
| --- /dev/null | |
| +++ b/core/api/src/main/java/org/openengsb/core/api/remote/UseCustomJasonMarshaller.java | |
| @@ -0,0 +1,39 @@ | |
| +/** | |
| + * 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.api.remote; | |
| + | |
| +import java.lang.annotation.Documented; | |
| +import java.lang.annotation.ElementType; | |
| +import java.lang.annotation.Retention; | |
| +import java.lang.annotation.RetentionPolicy; | |
| +import java.lang.annotation.Target; | |
| + | |
| +/** | |
| + * Annotation defining which {@link CustomJsonMarshaller} to use for argument. | |
| + */ | |
| +@Documented | |
| +@Retention(value = RetentionPolicy.RUNTIME) | |
| +@Target(ElementType.PARAMETER) | |
| +public @interface UseCustomJasonMarshaller { | |
| + | |
| + /** | |
| + * Nothing more required than to define which class to use to execute the marshaling. | |
| + */ | |
| + Class<? extends CustomJsonMarshaller<?>> value(); | |
| + | |
| +} | |
| diff --git a/core/services/src/main/java/org/openengsb/core/services/internal/RequestHandlerImpl.java b/core/services/src/main/java/org/openengsb/core/services/internal/RequestHandlerImpl.java | |
| index cc9d9cf..4360534 100644 | |
| --- a/core/services/src/main/java/org/openengsb/core/services/internal/RequestHandlerImpl.java | |
| +++ b/core/services/src/main/java/org/openengsb/core/services/internal/RequestHandlerImpl.java | |
| @@ -17,6 +17,7 @@ | |
| package org.openengsb.core.services.internal; | |
| +import java.lang.annotation.Annotation; | |
| import java.lang.reflect.InvocationTargetException; | |
| import java.lang.reflect.Method; | |
| import java.util.ArrayList; | |
| @@ -25,12 +26,16 @@ import java.util.Map; | |
| import org.openengsb.core.api.Constants; | |
| import org.openengsb.core.api.context.ContextHolder; | |
| +import org.openengsb.core.api.remote.CustomJsonMarshaller; | |
| import org.openengsb.core.api.remote.MethodCall; | |
| import org.openengsb.core.api.remote.MethodResult; | |
| import org.openengsb.core.api.remote.MethodResult.ReturnType; | |
| import org.openengsb.core.api.remote.RequestHandler; | |
| +import org.openengsb.core.api.remote.UseCustomJasonMarshaller; | |
| import org.openengsb.core.common.OpenEngSBCoreServices; | |
| +import com.google.common.base.Throwables; | |
| + | |
| public class RequestHandlerImpl implements RequestHandler { | |
| @Override | |
| @@ -41,13 +46,49 @@ public class RequestHandlerImpl implements RequestHandler { | |
| ContextHolder.get().setCurrentContextId(contextId); | |
| } | |
| Object service = retrieveOpenEngSBService(call); | |
| - Object[] args = call.getArgs(); | |
| Method method = findMethod(service, call.getMethodName(), getArgTypes(call)); | |
| + Object[] args = retrieveArguments(call, method); | |
| MethodResult methodResult = invokeMethod(service, method, args); | |
| methodResult.setMetaData(call.getMetaData()); | |
| return methodResult; | |
| } | |
| + private Object[] retrieveArguments(MethodCall call, Method method) { | |
| + Annotation[][] parameterAnnotations = method.getParameterAnnotations(); | |
| + Object[] originalArgs = call.getArgs(); | |
| + for (int i = 0; i < originalArgs.length; i++) { | |
| + Annotation[] currentArgAnnotations = parameterAnnotations[i]; | |
| + Class<? extends CustomJsonMarshaller<?>> transformationAnnotation = | |
| + searchForTransformationAnnotation(currentArgAnnotations); | |
| + if (transformationAnnotation == null) { | |
| + continue; | |
| + } | |
| + CustomJsonMarshaller<?> transformationInstance = createTransformationInstance(transformationAnnotation); | |
| + originalArgs[i] = transformationInstance.transformArg(originalArgs[i]); | |
| + } | |
| + return originalArgs; | |
| + } | |
| + | |
| + private CustomJsonMarshaller<?> createTransformationInstance( | |
| + Class<? extends CustomJsonMarshaller<?>> transformationAnnotation) { | |
| + try { | |
| + return transformationAnnotation.newInstance(); | |
| + } catch (Exception e) { | |
| + throw new IllegalStateException("It's not possible to create transformation because of " | |
| + + Throwables.getStackTraceAsString(e)); | |
| + } | |
| + } | |
| + | |
| + private Class<? extends CustomJsonMarshaller<?>> searchForTransformationAnnotation( | |
| + Annotation[] currentArgAnnotations) { | |
| + for (Annotation annotation : currentArgAnnotations) { | |
| + if (annotation instanceof UseCustomJasonMarshaller) { | |
| + return ((UseCustomJasonMarshaller) annotation).value(); | |
| + } | |
| + } | |
| + return null; | |
| + } | |
| + | |
| private Object retrieveOpenEngSBService(MethodCall call) { | |
| Map<String, String> metaData = call.getMetaData(); | |
| String serviceId = metaData.get("serviceId"); | |
| diff --git a/core/services/src/test/java/org/openengsb/core/services/internal/RequestHandlerImplTest.java b/core/services/src/test/java/org/openengsb/core/services/internal/RequestHandlerImplTest.java | |
| index a84ee4b..eb9dd9c 100644 | |
| --- a/core/services/src/test/java/org/openengsb/core/services/internal/RequestHandlerImplTest.java | |
| +++ b/core/services/src/test/java/org/openengsb/core/services/internal/RequestHandlerImplTest.java | |
| @@ -33,14 +33,17 @@ import java.util.Map; | |
| import org.junit.Before; | |
| import org.junit.Test; | |
| import org.openengsb.core.api.OsgiUtilsService; | |
| +import org.openengsb.core.api.remote.CustomJsonMarshaller; | |
| import org.openengsb.core.api.remote.MethodCall; | |
| import org.openengsb.core.api.remote.MethodResult; | |
| import org.openengsb.core.api.remote.RequestHandler; | |
| +import org.openengsb.core.api.remote.UseCustomJasonMarshaller; | |
| import org.openengsb.core.common.OpenEngSBCoreServices; | |
| import org.openengsb.core.common.util.DefaultOsgiUtilsService; | |
| import org.openengsb.core.test.AbstractOsgiMockServiceTest; | |
| import org.osgi.framework.BundleContext; | |
| +import com.google.common.base.Preconditions; | |
| import com.google.common.collect.ImmutableMap; | |
| public class RequestHandlerImplTest extends AbstractOsgiMockServiceTest { | |
| @@ -52,6 +55,16 @@ public class RequestHandlerImplTest extends AbstractOsgiMockServiceTest { | |
| Integer test(Integer arg); | |
| } | |
| + public static class CustomMarshaller implements CustomJsonMarshaller<Integer> { | |
| + | |
| + @Override | |
| + public Integer transformArg(Object arg) { | |
| + Preconditions.checkArgument(arg instanceof Integer); | |
| + return (Integer) arg + 1; | |
| + } | |
| + | |
| + } | |
| + | |
| @Before | |
| public void setup() throws Exception { | |
| requestHandler = new RequestHandlerImpl(); | |
| @@ -64,6 +77,12 @@ public class RequestHandlerImplTest extends AbstractOsgiMockServiceTest { | |
| return mockService; | |
| } | |
| + private TestInterface registerServiceWithProps(TestInterface mockService, Map<String, Object> propData) { | |
| + Dictionary<String, Object> props = new Hashtable<String, Object>(propData); | |
| + registerService(mockService, props, TestInterface.class); | |
| + return mockService; | |
| + } | |
| + | |
| @Test | |
| public void testCallByServiceId_shouldCallService() throws Exception { | |
| TestInterface mockService = mockService(TestInterface.class, "testid"); | |
| @@ -110,6 +129,26 @@ public class RequestHandlerImplTest extends AbstractOsgiMockServiceTest { | |
| } | |
| @Test | |
| + public void testCallByFilterAndServiceIdWithCustomMarshaller_shouldCallService() throws Exception { | |
| + Map<String, Object> propData = | |
| + ImmutableMap.of("testprop", (Object) new String[]{ "blub", "bleh", }, "id", "xxx"); | |
| + TestInterface realObject = new TestInterface() { | |
| + @Override | |
| + public Integer test(@UseCustomJasonMarshaller(CustomMarshaller.class) Integer arg) { | |
| + return arg; | |
| + } | |
| + }; | |
| + registerServiceWithProps(realObject, propData); | |
| + | |
| + Map<String, String> metaData = ImmutableMap.of("serviceFilter", "(testprop=blub)", "serviceId", "xxx"); | |
| + MethodCall c = new MethodCall("test", new Object[]{ 42 }, metaData); | |
| + MethodResult result = requestHandler.handleCall(c); | |
| + | |
| + assertThat(result.getClassName(), is(Integer.class.getName())); | |
| + assertThat((Integer) result.getArg(), is(43)); | |
| + } | |
| + | |
| + @Test | |
| public void testCallButBothAttrsNull_shouldThrowException() throws Exception { | |
| Map<String, Object> propData = | |
| ImmutableMap.of("testprop", (Object) new String[]{ "bla", "bleh", }); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment