diff --git a/spring-integration-core/src/main/java/org/springframework/integration/config/xml/GatewayParser.java b/spring-integration-core/src/main/java/org/springframework/integration/config/xml/GatewayParser.java index f2e48873b4..82c950e0a2 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/config/xml/GatewayParser.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/config/xml/GatewayParser.java @@ -83,27 +83,26 @@ public class GatewayParser extends AbstractSimpleBeanDefinitionParser { IntegrationNamespaceUtils.setReferenceIfAttributeDefined(builder, element, attributeName); } List elements = DomUtils.getChildElementsByTagName(element, "method"); - - ManagedMap methodToChannelMap = null; - if (elements != null && elements.size() > 0){ - methodToChannelMap = new ManagedMap(); + ManagedMap methodMetadataMap = null; + if (elements != null && elements.size() > 0) { + methodMetadataMap = new ManagedMap(); } for (Element methodElement : elements) { String methodName = methodElement.getAttribute("name"); - BeanDefinitionBuilder gatewayDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition( - "org.springframework.integration.gateway.GatewayMethodDefinition"); - gatewayDefinitionBuilder.addPropertyValue("requestChannelName", methodElement.getAttribute("request-channel")); - gatewayDefinitionBuilder.addPropertyValue("replyChannelName", methodElement.getAttribute("reply-channel")); - gatewayDefinitionBuilder.addPropertyValue("requestTimeout", methodElement.getAttribute("request-timeout")); - gatewayDefinitionBuilder.addPropertyValue("replyTimeout", methodElement.getAttribute("reply-timeout")); - IntegrationNamespaceUtils.setValueIfAttributeDefined(gatewayDefinitionBuilder, methodElement, "payload-expression"); + BeanDefinitionBuilder methodMetadataBuilder = BeanDefinitionBuilder.genericBeanDefinition( + "org.springframework.integration.gateway.GatewayMethodMetadata"); + methodMetadataBuilder.addPropertyValue("requestChannelName", methodElement.getAttribute("request-channel")); + methodMetadataBuilder.addPropertyValue("replyChannelName", methodElement.getAttribute("reply-channel")); + methodMetadataBuilder.addPropertyValue("requestTimeout", methodElement.getAttribute("request-timeout")); + methodMetadataBuilder.addPropertyValue("replyTimeout", methodElement.getAttribute("reply-timeout")); + IntegrationNamespaceUtils.setValueIfAttributeDefined(methodMetadataBuilder, methodElement, "payload-expression"); List invocationHeaders = DomUtils.getChildElementsByTagName(methodElement, "header"); - if (!CollectionUtils.isEmpty(invocationHeaders)){ - this.setMethodInvocationHeaders(gatewayDefinitionBuilder, invocationHeaders); + if (!CollectionUtils.isEmpty(invocationHeaders)) { + this.setMethodInvocationHeaders(methodMetadataBuilder, invocationHeaders); } - methodToChannelMap.put(methodName, gatewayDefinitionBuilder.getBeanDefinition()); + methodMetadataMap.put(methodName, methodMetadataBuilder.getBeanDefinition()); } - builder.addPropertyValue("methodToChannelMap", methodToChannelMap); + builder.addPropertyValue("methodMetadataMap", methodMetadataMap); } private void setMethodInvocationHeaders(BeanDefinitionBuilder gatewayDefinitionBuilder, List invocationHeaders) { diff --git a/spring-integration-core/src/main/java/org/springframework/integration/gateway/GatewayMethodDefinition.java b/spring-integration-core/src/main/java/org/springframework/integration/gateway/GatewayMethodMetadata.java similarity index 86% rename from spring-integration-core/src/main/java/org/springframework/integration/gateway/GatewayMethodDefinition.java rename to spring-integration-core/src/main/java/org/springframework/integration/gateway/GatewayMethodMetadata.java index 508db86b3d..e4a0ea49d1 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/gateway/GatewayMethodDefinition.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/gateway/GatewayMethodMetadata.java @@ -22,13 +22,16 @@ import java.util.Map; import org.springframework.expression.Expression; /** - * Represents the definition of Gateway methods, when using multiple methods per Gateway interface. - * <si:method name="echo" request-channel="inputA" reply-timeout="2" request-timeout="200"/> + * Represents the metadata associated with a Gateway method. This is most useful when there are + * multiple methods per Gateway interface. + *

+ * The sub-element of a <gateway> element would look like this: + * <method name="echo" request-channel="inputA" reply-timeout="2" request-timeout="200"/> * * @author Oleg Zhurakousky * @since 2.0 */ -public class GatewayMethodDefinition { +class GatewayMethodMetadata { private volatile String payloadExpression; diff --git a/spring-integration-core/src/main/java/org/springframework/integration/gateway/GatewayProxyFactoryBean.java b/spring-integration-core/src/main/java/org/springframework/integration/gateway/GatewayProxyFactoryBean.java index 3fd7e5e9b9..7d928d5623 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/gateway/GatewayProxyFactoryBean.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/gateway/GatewayProxyFactoryBean.java @@ -100,7 +100,7 @@ public class GatewayProxyFactoryBean extends AbstractEndpoint implements Trackab private final Object initializationMonitor = new Object(); - private Map methodToChannelMap; + private Map methodMetadataMap; /** @@ -326,24 +326,24 @@ public class GatewayProxyFactoryBean extends AbstractEndpoint implements Trackab requestTimeout = gatewayAnnotation.requestTimeout(); replyTimeout = gatewayAnnotation.replyTimeout(); } - else if (methodToChannelMap != null && methodToChannelMap.size() > 0) { - GatewayMethodDefinition gatewayDefinition = methodToChannelMap.get(method.getName()); - if (gatewayDefinition != null) { - payloadExpression = gatewayDefinition.getPayloadExpression(); - headerExpressions = gatewayDefinition.getHeaderExpressions(); - String requestChannelName = gatewayDefinition.getRequestChannelName(); + else if (methodMetadataMap != null && methodMetadataMap.size() > 0) { + GatewayMethodMetadata methodMetadata = methodMetadataMap.get(method.getName()); + if (methodMetadata != null) { + payloadExpression = methodMetadata.getPayloadExpression(); + headerExpressions = methodMetadata.getHeaderExpressions(); + String requestChannelName = methodMetadata.getRequestChannelName(); if (StringUtils.hasText(requestChannelName)) { requestChannel = this.resolveChannelName(requestChannelName); } - String replyChannelName = gatewayDefinition.getReplyChannelName(); + String replyChannelName = methodMetadata.getReplyChannelName(); if (StringUtils.hasText(replyChannelName)) { replyChannel = this.resolveChannelName(replyChannelName); } - String reqTimeout = gatewayDefinition.getRequestTimeout(); + String reqTimeout = methodMetadata.getRequestTimeout(); if (StringUtils.hasText(reqTimeout)){ requestTimeout = this.convert(reqTimeout, Long.class); } - String repTimeout = gatewayDefinition.getReplyTimeout(); + String repTimeout = methodMetadata.getReplyTimeout(); if (StringUtils.hasText(repTimeout)){ replyTimeout = this.convert(repTimeout, Long.class); } @@ -397,12 +397,8 @@ public class GatewayProxyFactoryBean extends AbstractEndpoint implements Trackab } } - public Map getMethodToChannelMap() { - return methodToChannelMap; - } - - public void setMethodToChannelMap(Map methodToChannelMap) { - this.methodToChannelMap = methodToChannelMap; + public void setMethodMetadataMap(Map methodMetadataMap) { + this.methodMetadataMap = methodMetadataMap; } public InboundMessageMapper getExceptionMapper() { diff --git a/spring-integration-core/src/main/java/org/springframework/integration/handler/HandlerMethodUtils.java b/spring-integration-core/src/main/java/org/springframework/integration/handler/HandlerMethodUtils.java deleted file mode 100644 index 1c354c9b4a..0000000000 --- a/spring-integration-core/src/main/java/org/springframework/integration/handler/HandlerMethodUtils.java +++ /dev/null @@ -1,116 +0,0 @@ -/* - * Copyright 2002-2009 the original author or authors. - * - * Licensed 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.springframework.integration.handler; - -import java.lang.annotation.Annotation; -import java.lang.reflect.Method; -import java.lang.reflect.Modifier; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; - -import org.springframework.aop.support.AopUtils; -import org.springframework.integration.annotation.Header; -import org.springframework.integration.annotation.Headers; -import org.springframework.util.ReflectionUtils; - -/** - * Utility methods for common behavior related to Message-handling methods. - * - * @author Mark Fisher - * @author Oleg Zhurakousky - */ -abstract class HandlerMethodUtils { - - /** - * Verifies that the provided Method is capable of handling Messages. - * It must be public, and not defined directly on Object. If it expects - * more than one parameter, at most one of them may expect the payload - * object. Others must be annotated for accepting Message header values. - */ - public static boolean isValidHandlerMethod(Method method) { - if (isMethodDefinedOnObjectClass(method)) { - return false; - } - if (!Modifier.isPublic(method.getModifiers())) { - return false; - } - Class[] parameterTypes = method.getParameterTypes(); - if (parameterTypes.length > 1) { - // at most one parameter can be expecting a Message or payload. - boolean foundPayloadParam = false; - Annotation[][] allParamAnnotations = method.getParameterAnnotations(); - for (int i = 0; i < parameterTypes.length; i++) { - Class currentType = parameterTypes[i]; - Annotation[] paramAnnotations = allParamAnnotations[i]; - // it's possible that a Map is the payload type at runtime, but we can't know that here - if (!containsHeaderAnnotation(paramAnnotations) && !Map.class.isAssignableFrom(currentType)) { - if (foundPayloadParam) { - return false; - } - foundPayloadParam = true; - } - } - } - return true; - } - - public static Method[] getCandidateHandlerMethods(Object object) { - final List candidates = new ArrayList(); - Class clazz = AopUtils.getTargetClass(object); - if (clazz == null) { - clazz = object.getClass(); - } - for (Method method : clazz.getMethods()) { - if (HandlerMethodUtils.isValidHandlerMethod(method)) { - candidates.add(method); - } - } - return candidates.toArray(new Method[candidates.size()]); - } - - /** - * Checks the array of Annotations for a method parameter to see if either - * the @Header or @Headers annotation is present. - */ - public static boolean containsHeaderAnnotation(Annotation[] parameterAnnotations) { - for (Annotation annotation : parameterAnnotations) { - if (annotation.annotationType().equals(Header.class) - || annotation.annotationType().equals(Headers.class)) { - return true; - } - } - return false; - } - - private static boolean isMethodDefinedOnObjectClass(Method method) { - if (method == null) { - return false; - } - if (method.getDeclaringClass().equals(Object.class)) { - return true; - } - if (ReflectionUtils.isEqualsMethod(method) || - ReflectionUtils.isHashCodeMethod(method) || - ReflectionUtils.isToStringMethod(method) || - AopUtils.isFinalizeMethod(method)) { - return true; - } - return (method.getName().equals("clone") && method.getParameterTypes().length == 0); - } - -} diff --git a/spring-integration-core/src/test/java/org/springframework/integration/handler/HandlerMethodUtilsTests.java b/spring-integration-core/src/test/java/org/springframework/integration/handler/HandlerMethodUtilsTests.java deleted file mode 100644 index f0db52e4fc..0000000000 --- a/spring-integration-core/src/test/java/org/springframework/integration/handler/HandlerMethodUtilsTests.java +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Copyright 2002-2009 the original author or authors. - * - * Licensed 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.springframework.integration.handler; - -import static org.junit.Assert.assertEquals; - -import java.lang.reflect.Method; - -import org.aopalliance.intercept.MethodInterceptor; -import org.aopalliance.intercept.MethodInvocation; -import org.junit.Test; - -import org.springframework.aop.framework.ProxyFactory; - -/** - * @author Mark Fisher - */ -public class HandlerMethodUtilsTests { - - @Test - public void testNonProxyIgnoresMethodsFromObjectClass() { - TestBean testBean = new TestBean(); - Method[] methods = HandlerMethodUtils.getCandidateHandlerMethods(testBean); - assertEquals(2, methods.length); - } - - @Test - public void testDynamicProxyIgnoresMethodsFromObjectClass() { - ProxyFactory pf = new ProxyFactory(TestInterface.class, new TestInterceptor()); - pf.setTarget(new TestBean()); - Object proxy = pf.getProxy(); - Method[] methods = HandlerMethodUtils.getCandidateHandlerMethods(proxy); - assertEquals(2, methods.length); - } - - @Test - public void testCglibProxyIgnoresMethodsFromObjectClass() { - ProxyFactory pf = new ProxyFactory(TestInterface.class, new TestInterceptor()); - pf.setTarget(new TestBean()); - pf.setProxyTargetClass(true); - Object proxy = pf.getProxy(); - Method[] methods = HandlerMethodUtils.getCandidateHandlerMethods(proxy); - assertEquals(2, methods.length); - } - - - public static class TestBean implements TestInterface { - - public void foo() { - } - - public void foo(String s) { - } - - public String toString() { - return "test"; - } - - public boolean equals(Object o) { - return (this == o); - } - - public int hashCode() { - return 23; - } - - public Object clone() { - return new TestBean(); - } - - public void finalize() { - } - } - - - public static interface TestInterface { - void foo(); - } - - - public static class TestInterceptor implements MethodInterceptor { - public Object invoke(MethodInvocation invocation) throws Throwable { - return invocation.proceed(); - } - } - -}