renamed GatewayMethodDefinition to GatewayMethodMetadata and made it package-protected

This commit is contained in:
Mark Fisher
2010-11-12 15:55:37 -05:00
parent 59c084f737
commit 2148956c6d
5 changed files with 32 additions and 251 deletions

View File

@@ -83,27 +83,26 @@ public class GatewayParser extends AbstractSimpleBeanDefinitionParser {
IntegrationNamespaceUtils.setReferenceIfAttributeDefined(builder, element, attributeName);
}
List<Element> elements = DomUtils.getChildElementsByTagName(element, "method");
ManagedMap<String, BeanDefinition> methodToChannelMap = null;
if (elements != null && elements.size() > 0){
methodToChannelMap = new ManagedMap<String, BeanDefinition>();
ManagedMap<String, BeanDefinition> methodMetadataMap = null;
if (elements != null && elements.size() > 0) {
methodMetadataMap = new ManagedMap<String, BeanDefinition>();
}
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<Element> 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<Element> invocationHeaders) {

View File

@@ -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.
* &lt;si:method name="echo" request-channel="inputA" reply-timeout="2" request-timeout="200"/&gt;
* Represents the metadata associated with a Gateway method. This is most useful when there are
* multiple methods per Gateway interface.
* <p>
* The sub-element of a &lt;gateway&gt; element would look like this:
* &lt;method name="echo" request-channel="inputA" reply-timeout="2" request-timeout="200"/&gt;
*
* @author Oleg Zhurakousky
* @since 2.0
*/
public class GatewayMethodDefinition {
class GatewayMethodMetadata {
private volatile String payloadExpression;

View File

@@ -100,7 +100,7 @@ public class GatewayProxyFactoryBean extends AbstractEndpoint implements Trackab
private final Object initializationMonitor = new Object();
private Map<String, GatewayMethodDefinition> methodToChannelMap;
private Map<String, GatewayMethodMetadata> 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<String, GatewayMethodDefinition> getMethodToChannelMap() {
return methodToChannelMap;
}
public void setMethodToChannelMap(Map<String, GatewayMethodDefinition> methodToChannelMap) {
this.methodToChannelMap = methodToChannelMap;
public void setMethodMetadataMap(Map<String, GatewayMethodMetadata> methodMetadataMap) {
this.methodMetadataMap = methodMetadataMap;
}
public InboundMessageMapper<Throwable> getExceptionMapper() {

View File

@@ -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<Method> candidates = new ArrayList<Method>();
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);
}
}

View File

@@ -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();
}
}
}