Added initial support for the MessageTransformer strategy and the @Transformer method-level annotation. Also added the PayloadTransformerAdapter implementation (INT-6).
This commit is contained in:
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright 2002-2008 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.annotation;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Inherited;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Indicates that a method is capable of transforming a message, message header,
|
||||
* or message payload.
|
||||
*
|
||||
* @author Mark Fisher
|
||||
*/
|
||||
@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Inherited
|
||||
@Documented
|
||||
@Handler
|
||||
public @interface Transformer {
|
||||
|
||||
}
|
||||
@@ -18,12 +18,16 @@ package org.springframework.integration.config.annotation;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.core.OrderComparator;
|
||||
import org.springframework.core.annotation.AnnotationUtils;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.integration.ConfigurationException;
|
||||
import org.springframework.integration.annotation.Aggregator;
|
||||
import org.springframework.integration.annotation.Concurrency;
|
||||
@@ -31,6 +35,7 @@ import org.springframework.integration.annotation.Handler;
|
||||
import org.springframework.integration.annotation.Polled;
|
||||
import org.springframework.integration.annotation.Router;
|
||||
import org.springframework.integration.annotation.Splitter;
|
||||
import org.springframework.integration.annotation.Transformer;
|
||||
import org.springframework.integration.bus.MessageBus;
|
||||
import org.springframework.integration.channel.ChannelRegistryAware;
|
||||
import org.springframework.integration.endpoint.ConcurrencyPolicy;
|
||||
@@ -44,6 +49,7 @@ import org.springframework.integration.router.config.AggregatorMessageHandlerCre
|
||||
import org.springframework.integration.router.config.RouterMessageHandlerCreator;
|
||||
import org.springframework.integration.router.config.SplitterMessageHandlerCreator;
|
||||
import org.springframework.integration.scheduling.Subscription;
|
||||
import org.springframework.integration.transformer.config.TransformerMessageHandlerCreator;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
@@ -64,6 +70,7 @@ public class HandlerAnnotationPostProcessor extends AbstractAnnotationMethodPost
|
||||
this.handlerCreators.put(Router.class, new RouterMessageHandlerCreator());
|
||||
this.handlerCreators.put(Splitter.class, new SplitterMessageHandlerCreator());
|
||||
this.handlerCreators.put(Aggregator.class, new AggregatorMessageHandlerCreator(messageBus));
|
||||
this.handlerCreators.put(Transformer.class, new TransformerMessageHandlerCreator());
|
||||
}
|
||||
|
||||
|
||||
@@ -82,7 +89,12 @@ public class HandlerAnnotationPostProcessor extends AbstractAnnotationMethodPost
|
||||
+ annotation.annotationType() + "', using DefaultMessageHandlerCreator.");
|
||||
}
|
||||
}
|
||||
MessageHandler handler = handlerCreator.createHandler(bean, method, AnnotationUtils.getAnnotationAttributes(annotation));
|
||||
Map<String, Object> attributes = AnnotationUtils.getAnnotationAttributes(annotation);
|
||||
Order order = AnnotationUtils.findAnnotation(method, Order.class);
|
||||
if (order != null) {
|
||||
attributes.put("order", order.value());
|
||||
}
|
||||
MessageHandler handler = handlerCreator.createHandler(bean, method, attributes);
|
||||
if (handler != null) {
|
||||
if (handler instanceof ChannelRegistryAware) {
|
||||
((ChannelRegistryAware) handler).setChannelRegistry(this.getMessageBus());
|
||||
@@ -110,6 +122,9 @@ public class HandlerAnnotationPostProcessor extends AbstractAnnotationMethodPost
|
||||
if (handlerChain.getHandlers().size() == 1) {
|
||||
return handlerChain.getHandlers().get(0);
|
||||
}
|
||||
List<MessageHandler> handlers = new ArrayList<MessageHandler>(handlerChain.getHandlers());
|
||||
Collections.sort(handlers, new OrderComparator());
|
||||
handlerChain.setHandlers(handlers);
|
||||
return handlerChain;
|
||||
}
|
||||
|
||||
|
||||
@@ -19,20 +19,14 @@ package org.springframework.integration.handler;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.integration.ConfigurationException;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.integration.message.DefaultMessageCreator;
|
||||
import org.springframework.integration.message.DefaultMessageMapper;
|
||||
import org.springframework.integration.message.Message;
|
||||
import org.springframework.integration.message.MessageCreator;
|
||||
import org.springframework.integration.message.MessageHandlingException;
|
||||
import org.springframework.integration.message.MessageMapper;
|
||||
import org.springframework.integration.util.DefaultMethodInvoker;
|
||||
import org.springframework.integration.util.MethodInvoker;
|
||||
import org.springframework.integration.util.NameResolvingMethodInvoker;
|
||||
import org.springframework.integration.util.AbstractMethodInvokingAdapter;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
@@ -50,18 +44,12 @@ import org.springframework.util.ObjectUtils;
|
||||
*
|
||||
* @author Mark Fisher
|
||||
*/
|
||||
public abstract class AbstractMessageHandlerAdapter implements MessageHandler, InitializingBean {
|
||||
public abstract class AbstractMessageHandlerAdapter extends AbstractMethodInvokingAdapter implements MessageHandler {
|
||||
|
||||
public static final String OUTPUT_CHANNEL_NAME_KEY = "outputChannelName";
|
||||
|
||||
|
||||
protected final Log logger = LogFactory.getLog(this.getClass());
|
||||
|
||||
private volatile Object object;
|
||||
|
||||
private volatile Method method;
|
||||
|
||||
private volatile String methodName;
|
||||
private volatile int order;
|
||||
|
||||
private volatile boolean methodExpectsMessage;
|
||||
|
||||
@@ -69,32 +57,6 @@ public abstract class AbstractMessageHandlerAdapter implements MessageHandler, I
|
||||
|
||||
private volatile MessageCreator messageCreator = new DefaultMessageCreator();
|
||||
|
||||
protected volatile MethodInvoker invoker;
|
||||
|
||||
private volatile boolean initialized;
|
||||
|
||||
private final Object initializationMonitor = new Object();
|
||||
|
||||
|
||||
public void setObject(Object object) {
|
||||
this.object = object;
|
||||
}
|
||||
|
||||
protected Object getObject() {
|
||||
return this.object;
|
||||
}
|
||||
|
||||
public void setMethod(Method method) {
|
||||
this.method = method;
|
||||
}
|
||||
|
||||
protected Method getMethod() {
|
||||
return this.method;
|
||||
}
|
||||
|
||||
public void setMethodName(String methodName) {
|
||||
this.methodName = methodName;
|
||||
}
|
||||
|
||||
public void setMethodExpectsMessage(boolean methodExpectsMessage) {
|
||||
this.methodExpectsMessage = methodExpectsMessage;
|
||||
@@ -110,45 +72,13 @@ public abstract class AbstractMessageHandlerAdapter implements MessageHandler, I
|
||||
this.messageCreator = messageCreator;
|
||||
}
|
||||
|
||||
public void afterPropertiesSet() {
|
||||
synchronized (this.initializationMonitor) {
|
||||
if (this.initialized) {
|
||||
return;
|
||||
}
|
||||
if (this.object == null) {
|
||||
throw new ConfigurationException("The target 'object' must not be null.");
|
||||
}
|
||||
if (this.method == null && this.methodName == null) {
|
||||
throw new ConfigurationException("Either a 'method' or 'methodName' is required.");
|
||||
}
|
||||
if (this.method != null) {
|
||||
if (this.methodName != null && !this.methodName.equals(this.method.getName())) {
|
||||
throw new ConfigurationException("An ambiguity exists between the 'method' and 'methodName' properties. " +
|
||||
"Note that only one of them is required, but if both are provided they must match.");
|
||||
}
|
||||
this.invoker = new DefaultMethodInvoker(this.object, this.method);
|
||||
}
|
||||
else {
|
||||
this.invoker = new NameResolvingMethodInvoker(this.object, this.methodName);
|
||||
}
|
||||
this.initialized = true;
|
||||
}
|
||||
this.initialize();
|
||||
}
|
||||
|
||||
/**
|
||||
* Subclasses may override this method for custom initialization requirements.
|
||||
*/
|
||||
protected void initialize() {
|
||||
}
|
||||
|
||||
public Message<?> handle(Message<?> message) {
|
||||
if (!this.isInitialized()) {
|
||||
this.afterPropertiesSet();
|
||||
}
|
||||
if (message == null) {
|
||||
throw new IllegalArgumentException("message must not be null");
|
||||
}
|
||||
if (!this.initialized) {
|
||||
this.afterPropertiesSet();
|
||||
}
|
||||
Object args[] = null;
|
||||
Object mappingResult = (this.methodExpectsMessage) ? message : this.messageMapper.mapMessage(message);
|
||||
if (mappingResult != null && mappingResult.getClass().isArray()
|
||||
@@ -161,10 +91,10 @@ public abstract class AbstractMessageHandlerAdapter implements MessageHandler, I
|
||||
try {
|
||||
Object result = null;
|
||||
try {
|
||||
result = this.invoker.invokeMethod(args);
|
||||
result = this.invokeMethod(args);
|
||||
}
|
||||
catch (NoSuchMethodException e) {
|
||||
result = this.invoker.invokeMethod(message);
|
||||
result = this.invokeMethod(message);
|
||||
this.methodExpectsMessage = true;
|
||||
}
|
||||
if (result == null) {
|
||||
@@ -173,12 +103,12 @@ public abstract class AbstractMessageHandlerAdapter implements MessageHandler, I
|
||||
return this.handleReturnValue(result, message);
|
||||
}
|
||||
catch (InvocationTargetException e) {
|
||||
throw new MessageHandlingException(message,
|
||||
"Handler method '" + this.method + "' threw an Exception.", e.getTargetException());
|
||||
throw new MessageHandlingException(message, "Handler method '"
|
||||
+ this.getMethod() + "' threw an Exception.", e.getTargetException());
|
||||
}
|
||||
catch (Throwable e) {
|
||||
throw new MessageHandlingException(message, "Failed to invoke handler method '" + this.method +
|
||||
"' with arguments: " + ObjectUtils.nullSafeToString(args), e);
|
||||
throw new MessageHandlingException(message, "Failed to invoke handler method '"
|
||||
+ this.getMethod() + "' with arguments: " + ObjectUtils.nullSafeToString(args), e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -14,9 +14,8 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.integration.transformer;
|
||||
package org.springframework.integration.handler;
|
||||
|
||||
import org.springframework.integration.handler.MessageHandler;
|
||||
import org.springframework.integration.message.Message;
|
||||
import org.springframework.integration.message.selector.MessageSelector;
|
||||
|
||||
@@ -22,6 +22,7 @@ import java.util.Map;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.integration.ConfigurationException;
|
||||
import org.springframework.integration.handler.MessageHandler;
|
||||
import org.springframework.integration.util.AbstractMethodInvokingAdapter;
|
||||
|
||||
/**
|
||||
* Base class for handler creators that generate a {@link MessageHandler}
|
||||
@@ -33,6 +34,12 @@ public abstract class AbstractMessageHandlerCreator implements MessageHandlerCre
|
||||
|
||||
public final MessageHandler createHandler(Object object, Method method, Map<String, ?> attributes) {
|
||||
MessageHandler handler = this.doCreateHandler(object, method, attributes);
|
||||
if (attributes != null && handler instanceof AbstractMethodInvokingAdapter) {
|
||||
Object order = attributes.get("order");
|
||||
if (order != null && order instanceof Integer) {
|
||||
((AbstractMethodInvokingAdapter) handler).setOrder(((Integer) order).intValue());
|
||||
}
|
||||
}
|
||||
if (handler instanceof InitializingBean) {
|
||||
try {
|
||||
((InitializingBean) handler).afterPropertiesSet();
|
||||
|
||||
@@ -34,7 +34,7 @@ public class GenericMessage<T> implements Message<T> {
|
||||
|
||||
private final MessageHeader header = new MessageHeader();
|
||||
|
||||
private final T payload;
|
||||
private volatile T payload;
|
||||
|
||||
private transient final IdGenerator defaultIdGenerator = new RandomUuidGenerator();
|
||||
|
||||
@@ -91,6 +91,11 @@ public class GenericMessage<T> implements Message<T> {
|
||||
return this.payload;
|
||||
}
|
||||
|
||||
public void setPayload(T payload) {
|
||||
Assert.notNull(payload, "payload must not be null");
|
||||
this.payload = payload;
|
||||
}
|
||||
|
||||
public boolean isExpired() {
|
||||
Date expiration = this.header.getExpiration();
|
||||
return (expiration != null) ? expiration.getTime() < System.currentTimeMillis() : false;
|
||||
|
||||
@@ -31,6 +31,8 @@ public interface Message<T> extends Serializable {
|
||||
|
||||
T getPayload();
|
||||
|
||||
void setPayload(T payload);
|
||||
|
||||
boolean isExpired();
|
||||
|
||||
void copyHeader(MessageHeader header, boolean overwriteExistingValues);
|
||||
|
||||
@@ -0,0 +1,110 @@
|
||||
/*
|
||||
* Copyright 2002-2008 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.transformer;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
|
||||
import org.springframework.integration.handler.MessageHandler;
|
||||
import org.springframework.integration.handler.annotation.AnnotationMethodMessageMapper;
|
||||
import org.springframework.integration.message.DefaultMessageMapper;
|
||||
import org.springframework.integration.message.Message;
|
||||
import org.springframework.integration.message.MessageMapper;
|
||||
import org.springframework.integration.message.MessagingException;
|
||||
import org.springframework.integration.util.AbstractMethodInvokingAdapter;
|
||||
|
||||
/**
|
||||
* @author Mark Fisher
|
||||
*/
|
||||
public class AnnotationMethodTransformerAdapter extends AbstractMethodInvokingAdapter
|
||||
implements MessageTransformer, MessageHandler {
|
||||
|
||||
private volatile MessageMapper mapper;
|
||||
|
||||
private volatile boolean methodExpectsMessage;
|
||||
|
||||
|
||||
public void setMethodExpectsMessage(boolean methodExpectsMessage) {
|
||||
this.methodExpectsMessage = methodExpectsMessage;
|
||||
}
|
||||
|
||||
protected void initialize() {
|
||||
this.mapper = (this.getMethod() != null)
|
||||
? new AnnotationMethodMessageMapper(this.getMethod())
|
||||
: new DefaultMessageMapper();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public void transform(Message message) {
|
||||
if (!this.isInitialized()) {
|
||||
this.afterPropertiesSet();
|
||||
}
|
||||
if (message.getPayload() == null) {
|
||||
return;
|
||||
}
|
||||
Object param = (this.methodExpectsMessage) ? message : this.mapper.mapMessage(message);
|
||||
try {
|
||||
Object args[] = null;
|
||||
if (param != null && param.getClass().isArray()
|
||||
&& (Object.class.isAssignableFrom(param.getClass().getComponentType()))) {
|
||||
args = (Object[]) param;
|
||||
}
|
||||
else {
|
||||
args = new Object[] { param };
|
||||
}
|
||||
Object result = null;
|
||||
try {
|
||||
result = this.invokeMethod(args);
|
||||
}
|
||||
catch (NoSuchMethodException e) {
|
||||
result = this.invokeMethod(message);
|
||||
this.methodExpectsMessage = true;
|
||||
}
|
||||
if (result == null) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("MessageTransformer returned a null result");
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (result instanceof Properties && !(message.getPayload() instanceof Properties)) {
|
||||
Properties propertiesToSet = (Properties) result;
|
||||
for (Object keyObject : propertiesToSet.keySet()) {
|
||||
String key = (String) keyObject;
|
||||
message.getHeader().setProperty(key, propertiesToSet.getProperty(key));
|
||||
}
|
||||
}
|
||||
else if (result instanceof Map && !(message.getPayload() instanceof Map)) {
|
||||
Map<String, ?> attributesToSet = (Map) result;
|
||||
for (String key : attributesToSet.keySet()) {
|
||||
message.getHeader().setAttribute(key, attributesToSet.get(key));
|
||||
}
|
||||
}
|
||||
else {
|
||||
message.setPayload(result);
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new MessagingException(message, "failed to transform message payload", e);
|
||||
}
|
||||
}
|
||||
|
||||
public Message<?> handle(Message<?> message) {
|
||||
this.transform(message);
|
||||
return message;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright 2002-2008 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.transformer;
|
||||
|
||||
import org.springframework.integration.message.Message;
|
||||
|
||||
/**
|
||||
* Base interface for message transformers.
|
||||
*
|
||||
* @author Mark Fisher
|
||||
*/
|
||||
public interface MessageTransformer {
|
||||
|
||||
void transform(Message<?> message);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Copyright 2002-2008 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.transformer;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
|
||||
import org.springframework.integration.message.Message;
|
||||
|
||||
/**
|
||||
* @author Mark Fisher
|
||||
*/
|
||||
public class MessageTransformerChain implements MessageTransformer {
|
||||
|
||||
private final List<MessageTransformer> transformers = new CopyOnWriteArrayList<MessageTransformer>();
|
||||
|
||||
|
||||
/**
|
||||
* Add a transformer to the end of the chain.
|
||||
*/
|
||||
public void add(MessageTransformer transformer) {
|
||||
this.transformers.add(transformer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a transformer to the chain at the specified index.
|
||||
*/
|
||||
public void add(int index, MessageTransformer transformer) {
|
||||
this.transformers.add(index, transformer);
|
||||
}
|
||||
|
||||
public void setTransformers(List<MessageTransformer> transformers) {
|
||||
this.transformers.clear();
|
||||
this.transformers.addAll(transformers);
|
||||
}
|
||||
|
||||
public void transform(Message<?> message) {
|
||||
for (MessageTransformer next : transformers) {
|
||||
next.transform(message);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright 2002-2008 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.transformer;
|
||||
|
||||
import org.springframework.integration.message.Message;
|
||||
import org.springframework.integration.message.MessagingException;
|
||||
import org.springframework.integration.util.AbstractMethodInvokingAdapter;
|
||||
|
||||
/**
|
||||
* @author Mark Fisher
|
||||
*/
|
||||
public class PayloadTransformerAdapter extends AbstractMethodInvokingAdapter implements MessageTransformer {
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public void transform(Message message) {
|
||||
try {
|
||||
message.setPayload(this.invokeMethod(message.getPayload()));
|
||||
} catch (Exception e) {
|
||||
throw new MessagingException(message, "failed to transform message payload", e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright 2002-2008 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.transformer;
|
||||
|
||||
import org.springframework.integration.handler.MessageHandler;
|
||||
import org.springframework.integration.message.Message;
|
||||
|
||||
/**
|
||||
* @author Mark Fisher
|
||||
*/
|
||||
public class TransformerMessageHandlerAdapter implements MessageHandler {
|
||||
|
||||
private final MessageTransformer transformer;
|
||||
|
||||
|
||||
public TransformerMessageHandlerAdapter(MessageTransformer transformer) {
|
||||
this.transformer = transformer;
|
||||
}
|
||||
|
||||
|
||||
public Message<?> handle(Message<?> message) {
|
||||
this.transformer.transform(message);
|
||||
return message;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright 2002-2008 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.transformer.config;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.integration.handler.MessageHandler;
|
||||
import org.springframework.integration.handler.config.AbstractMessageHandlerCreator;
|
||||
import org.springframework.integration.transformer.AnnotationMethodTransformerAdapter;
|
||||
|
||||
/**
|
||||
* @author Mark Fisher
|
||||
*/
|
||||
public class TransformerMessageHandlerCreator extends AbstractMessageHandlerCreator {
|
||||
|
||||
public MessageHandler doCreateHandler(Object object, Method method, Map<String, ?> attributes) {
|
||||
AnnotationMethodTransformerAdapter adapter = new AnnotationMethodTransformerAdapter();
|
||||
adapter.setObject(object);
|
||||
adapter.setMethodName(method.getName());
|
||||
adapter.afterPropertiesSet();
|
||||
return adapter;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,128 @@
|
||||
/*
|
||||
* Copyright 2002-2008 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.util;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.integration.ConfigurationException;
|
||||
|
||||
/**
|
||||
* An base class for adapters that invoke a specified method and target object.
|
||||
* Either a {@link Method} reference or a 'methodName' may be provided, but both
|
||||
* are not necessary. In fact, while preference is given to a {@link Method}
|
||||
* reference if available, an Exception will be thrown if a non-matching
|
||||
* 'methodName' has also been provided. Therefore, to avoid such ambiguity,
|
||||
* it is recommended to provide just one or the other.
|
||||
*
|
||||
* @author Mark Fisher
|
||||
*/
|
||||
public abstract class AbstractMethodInvokingAdapter implements MethodInvoker, InitializingBean, Ordered {
|
||||
|
||||
protected final Log logger = LogFactory.getLog(this.getClass());
|
||||
|
||||
private volatile Object object;
|
||||
|
||||
private volatile Method method;
|
||||
|
||||
private volatile String methodName;
|
||||
|
||||
private volatile int order;
|
||||
|
||||
private volatile MethodInvoker invoker;
|
||||
|
||||
private volatile boolean initialized;
|
||||
|
||||
private final Object initializationMonitor = new Object();
|
||||
|
||||
|
||||
public void setObject(Object object) {
|
||||
this.object = object;
|
||||
}
|
||||
|
||||
protected Object getObject() {
|
||||
return this.object;
|
||||
}
|
||||
|
||||
public void setMethod(Method method) {
|
||||
this.method = method;
|
||||
}
|
||||
|
||||
protected Method getMethod() {
|
||||
return this.method;
|
||||
}
|
||||
|
||||
public void setMethodName(String methodName) {
|
||||
this.methodName = methodName;
|
||||
}
|
||||
|
||||
public void setOrder(int order) {
|
||||
this.order = order;
|
||||
}
|
||||
|
||||
public int getOrder() {
|
||||
return order;
|
||||
}
|
||||
|
||||
protected boolean isInitialized() {
|
||||
return this.initialized;
|
||||
}
|
||||
|
||||
public void afterPropertiesSet() {
|
||||
synchronized (this.initializationMonitor) {
|
||||
if (this.initialized) {
|
||||
return;
|
||||
}
|
||||
if (this.object == null) {
|
||||
throw new ConfigurationException("The target 'object' must not be null.");
|
||||
}
|
||||
if (this.method == null && this.methodName == null) {
|
||||
throw new ConfigurationException("Either a 'method' or 'methodName' is required.");
|
||||
}
|
||||
if (this.method != null) {
|
||||
if (this.methodName != null && !this.methodName.equals(this.method.getName())) {
|
||||
throw new ConfigurationException("An ambiguity exists between the 'method' and 'methodName' properties. " +
|
||||
"Note that only one of them is required, but if both are provided they must match.");
|
||||
}
|
||||
this.invoker = new DefaultMethodInvoker(this.object, this.method);
|
||||
}
|
||||
else {
|
||||
this.invoker = new NameResolvingMethodInvoker(this.object, this.methodName);
|
||||
}
|
||||
this.initialized = true;
|
||||
}
|
||||
this.initialize();
|
||||
}
|
||||
|
||||
/**
|
||||
* Subclasses may override this method for custom initialization requirements.
|
||||
*/
|
||||
protected void initialize() {
|
||||
}
|
||||
|
||||
public Object invokeMethod(Object ... args) throws Exception {
|
||||
if (!this.initialized) {
|
||||
this.afterPropertiesSet();
|
||||
}
|
||||
return this.invoker.invokeMethod(args);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -34,6 +34,7 @@ import org.springframework.aop.framework.ProxyFactory;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.support.AbstractApplicationContext;
|
||||
import org.springframework.context.support.ClassPathXmlApplicationContext;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.integration.ConfigurationException;
|
||||
import org.springframework.integration.annotation.Concurrency;
|
||||
import org.springframework.integration.annotation.Handler;
|
||||
@@ -42,6 +43,7 @@ import org.springframework.integration.annotation.MessageSource;
|
||||
import org.springframework.integration.annotation.MessageTarget;
|
||||
import org.springframework.integration.annotation.Polled;
|
||||
import org.springframework.integration.annotation.Splitter;
|
||||
import org.springframework.integration.annotation.Transformer;
|
||||
import org.springframework.integration.bus.MessageBus;
|
||||
import org.springframework.integration.channel.ChannelRegistry;
|
||||
import org.springframework.integration.channel.ChannelRegistryAware;
|
||||
@@ -372,6 +374,17 @@ public class MessagingAnnotationPostProcessorTests {
|
||||
messageBus.stop();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHandlerWithTransformers() {
|
||||
MessageBus messageBus = new MessageBus();
|
||||
MessagingAnnotationPostProcessor postProcessor = new MessagingAnnotationPostProcessor(messageBus);
|
||||
postProcessor.afterPropertiesSet();
|
||||
HandlerWithTransformers testBean = new HandlerWithTransformers();
|
||||
MessageHandler handler = (MessageHandler) postProcessor.postProcessAfterInitialization(testBean, "testBean");
|
||||
Message<?> reply = handler.handle(new StringMessage("foo"));
|
||||
assertEquals("PRE.FOO.post", reply.getPayload());
|
||||
}
|
||||
|
||||
|
||||
@MessageEndpoint(input="testChannel")
|
||||
private static class TargetAnnotationTestBean {
|
||||
@@ -508,7 +521,28 @@ public class MessagingAnnotationPostProcessorTests {
|
||||
public String test() {
|
||||
return "test";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static class HandlerWithTransformers {
|
||||
|
||||
@Transformer
|
||||
@Order(-1)
|
||||
public String transformBefore(String input) {
|
||||
return "pre." + input;
|
||||
}
|
||||
|
||||
@Handler
|
||||
@Order(0)
|
||||
public String handle(String input) {
|
||||
return input.toUpperCase();
|
||||
}
|
||||
|
||||
@Transformer
|
||||
@Order(1)
|
||||
public String transformAfter(String input) {
|
||||
return input + ".post";
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.integration.handler.annotation;
|
||||
package org.springframework.integration.config.annotation;
|
||||
|
||||
import org.springframework.integration.annotation.Handler;
|
||||
|
||||
@@ -18,6 +18,6 @@
|
||||
<beans:constructor-arg ref="internal.MessageBus"/>
|
||||
</beans:bean>
|
||||
|
||||
<beans:bean id="simpleHandler" class="org.springframework.integration.handler.annotation.SimpleHandlerTestBean"/>
|
||||
<beans:bean id="simpleHandler" class="org.springframework.integration.config.annotation.SimpleHandlerTestBean"/>
|
||||
|
||||
</beans:beans>
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.integration.transformer;
|
||||
package org.springframework.integration.handler;
|
||||
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
@@ -23,6 +23,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.integration.handler.MessageFilter;
|
||||
import org.springframework.integration.handler.MessageHandler;
|
||||
import org.springframework.integration.handler.MessageHandlerChain;
|
||||
import org.springframework.integration.message.Message;
|
||||
@@ -0,0 +1,190 @@
|
||||
/*
|
||||
* Copyright 2002-2008 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.transformer;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNull;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.Properties;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.integration.annotation.Transformer;
|
||||
import org.springframework.integration.handler.annotation.HeaderAttribute;
|
||||
import org.springframework.integration.handler.annotation.HeaderProperty;
|
||||
import org.springframework.integration.message.GenericMessage;
|
||||
import org.springframework.integration.message.Message;
|
||||
import org.springframework.integration.message.MessageHandlingException;
|
||||
import org.springframework.integration.message.MessagingException;
|
||||
import org.springframework.integration.message.StringMessage;
|
||||
|
||||
/**
|
||||
* @author Mark Fisher
|
||||
*/
|
||||
public class AnnotationMethodTransformerAdapterTests {
|
||||
|
||||
@Test
|
||||
public void testSimplePayload() throws Exception {
|
||||
TestBean testBean = new TestBean();
|
||||
AnnotationMethodTransformerAdapter adapter = new AnnotationMethodTransformerAdapter();
|
||||
adapter.setObject(testBean);
|
||||
adapter.setMethod(testBean.getClass().getMethod("exclaim", String.class));
|
||||
Message<?> message = new StringMessage("foo");
|
||||
adapter.transform(message);
|
||||
assertEquals("FOO!", message.getPayload());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTypeConversion() throws Exception {
|
||||
TestBean testBean = new TestBean();
|
||||
AnnotationMethodTransformerAdapter adapter = new AnnotationMethodTransformerAdapter();
|
||||
adapter.setObject(testBean);
|
||||
adapter.setMethod(testBean.getClass().getMethod("exclaim", String.class));
|
||||
Message<?> message = new GenericMessage<Integer>(123);
|
||||
adapter.transform(message);
|
||||
assertEquals("123!", message.getPayload());
|
||||
}
|
||||
|
||||
@Test(expected=MessagingException.class)
|
||||
public void testTypeConversionFailure() throws Exception {
|
||||
TestBean testBean = new TestBean();
|
||||
AnnotationMethodTransformerAdapter adapter = new AnnotationMethodTransformerAdapter();
|
||||
adapter.setObject(testBean);
|
||||
adapter.setMethod(testBean.getClass().getMethod("exclaim", String.class));
|
||||
Message<?> message = new GenericMessage<Date>(new Date());
|
||||
adapter.transform(message);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHeaderAttributeAnnotation() throws Exception {
|
||||
TestBean testBean = new TestBean();
|
||||
AnnotationMethodTransformerAdapter adapter = new AnnotationMethodTransformerAdapter();
|
||||
adapter.setObject(testBean);
|
||||
adapter.setMethod(testBean.getClass().getMethod("attributeTest", String.class, Integer.class));
|
||||
Message<?> message = new StringMessage("foo");
|
||||
message.getHeader().setAttribute("number", 123);
|
||||
adapter.transform(message);
|
||||
assertEquals("foo123", message.getPayload());
|
||||
}
|
||||
|
||||
@Test(expected=MessageHandlingException.class)
|
||||
public void testHeaderAttributeNotProvided() throws Exception {
|
||||
TestBean testBean = new TestBean();
|
||||
AnnotationMethodTransformerAdapter adapter = new AnnotationMethodTransformerAdapter();
|
||||
adapter.setObject(testBean);
|
||||
adapter.setMethod(testBean.getClass().getMethod("attributeTest", String.class, Integer.class));
|
||||
Message<?> message = new StringMessage("foo");
|
||||
message.getHeader().setAttribute("wrong", 123);
|
||||
adapter.transform(message);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHeaderPropertyAnnotation() throws Exception {
|
||||
TestBean testBean = new TestBean();
|
||||
AnnotationMethodTransformerAdapter adapter = new AnnotationMethodTransformerAdapter();
|
||||
adapter.setObject(testBean);
|
||||
adapter.setMethod(testBean.getClass().getMethod("propertyTest", String.class, String.class));
|
||||
Message<?> message = new StringMessage("foo");
|
||||
message.getHeader().setProperty("suffix", "bar");
|
||||
adapter.transform(message);
|
||||
assertEquals("foobar", message.getPayload());
|
||||
}
|
||||
|
||||
@Test(expected=MessageHandlingException.class)
|
||||
public void testHeaderPropertyNotAvailable() throws Exception {
|
||||
TestBean testBean = new TestBean();
|
||||
AnnotationMethodTransformerAdapter adapter = new AnnotationMethodTransformerAdapter();
|
||||
adapter.setObject(testBean);
|
||||
adapter.setMethod(testBean.getClass().getMethod("propertyTest", String.class, String.class));
|
||||
Message<?> message = new StringMessage("foo");
|
||||
message.getHeader().setProperty("wrong", "bar");
|
||||
adapter.transform(message);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPropertyEnricher() throws Exception {
|
||||
TestBean testBean = new TestBean();
|
||||
AnnotationMethodTransformerAdapter adapter = new AnnotationMethodTransformerAdapter();
|
||||
adapter.setObject(testBean);
|
||||
adapter.setMethod(testBean.getClass().getMethod("propertyEnricherTest", String.class));
|
||||
Message<?> message = new StringMessage("test");
|
||||
message.getHeader().setProperty("prop1", "bad");
|
||||
message.getHeader().setProperty("prop3", "baz");
|
||||
adapter.transform(message);
|
||||
assertEquals("test", message.getPayload());
|
||||
assertEquals("foo", message.getHeader().getProperty("prop1"));
|
||||
assertEquals("bar", message.getHeader().getProperty("prop2"));
|
||||
assertEquals("baz", message.getHeader().getProperty("prop3"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPropertyPayload() throws Exception {
|
||||
TestBean testBean = new TestBean();
|
||||
AnnotationMethodTransformerAdapter adapter = new AnnotationMethodTransformerAdapter();
|
||||
adapter.setObject(testBean);
|
||||
adapter.setMethod(testBean.getClass().getMethod("propertyPayloadTest", Properties.class));
|
||||
Properties props = new Properties();
|
||||
props.setProperty("prop1", "bad");
|
||||
props.setProperty("prop3", "baz");
|
||||
Message<Properties> message = new GenericMessage<Properties>(props);
|
||||
adapter.transform(message);
|
||||
assertEquals(Properties.class, message.getPayload().getClass());
|
||||
Properties payload = message.getPayload();
|
||||
assertEquals("foo", payload.getProperty("prop1"));
|
||||
assertEquals("bar", payload.getProperty("prop2"));
|
||||
assertEquals("baz", payload.getProperty("prop3"));
|
||||
assertNull(message.getHeader().getProperty("prop1"));
|
||||
assertNull(message.getHeader().getProperty("prop2"));
|
||||
assertNull(message.getHeader().getProperty("prop3"));
|
||||
}
|
||||
|
||||
|
||||
private static class TestBean {
|
||||
|
||||
@Transformer
|
||||
public String exclaim(String s) {
|
||||
return s.toUpperCase() + "!";
|
||||
}
|
||||
|
||||
@Transformer
|
||||
public String attributeTest(String s, @HeaderAttribute("number") Integer num) {
|
||||
return s + num;
|
||||
}
|
||||
|
||||
@Transformer
|
||||
public String propertyTest(String s, @HeaderProperty("suffix") String suffix) {
|
||||
return s + suffix;
|
||||
}
|
||||
|
||||
@Transformer
|
||||
public Properties propertyEnricherTest(String s) {
|
||||
Properties properties = new Properties();
|
||||
properties.setProperty("prop1", "foo");
|
||||
properties.setProperty("prop2", "bar");
|
||||
return properties;
|
||||
}
|
||||
|
||||
@Transformer
|
||||
public Properties propertyPayloadTest(Properties properties) {
|
||||
properties.setProperty("prop1", "foo");
|
||||
properties.setProperty("prop2", "bar");
|
||||
return properties;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* Copyright 2002-2008 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.transformer;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.integration.message.GenericMessage;
|
||||
import org.springframework.integration.message.Message;
|
||||
import org.springframework.integration.message.MessagingException;
|
||||
import org.springframework.integration.message.StringMessage;
|
||||
|
||||
/**
|
||||
* @author Mark Fisher
|
||||
*/
|
||||
public class PayloadTransformerAdapterTests {
|
||||
|
||||
@Test
|
||||
public void testSimpleMethod() {
|
||||
PayloadTransformerAdapter adapter = new PayloadTransformerAdapter();
|
||||
adapter.setObject(new TestBean());
|
||||
adapter.setMethodName("exclaim");
|
||||
Message<?> message = new StringMessage("foo");
|
||||
adapter.transform(message);
|
||||
assertEquals("FOO!", message.getPayload());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTypeConversion() {
|
||||
PayloadTransformerAdapter adapter = new PayloadTransformerAdapter();
|
||||
adapter.setObject(new TestBean());
|
||||
adapter.setMethodName("exclaim");
|
||||
Message<?> message = new GenericMessage<Integer>(123);
|
||||
adapter.transform(message);
|
||||
assertEquals("123!", message.getPayload());
|
||||
}
|
||||
|
||||
@Test(expected=MessagingException.class)
|
||||
public void testTypeConversionFailure() {
|
||||
PayloadTransformerAdapter adapter = new PayloadTransformerAdapter();
|
||||
adapter.setObject(new TestBean());
|
||||
adapter.setMethodName("exclaim");
|
||||
Message<?> message = new GenericMessage<Date>(new Date());
|
||||
adapter.transform(message);
|
||||
}
|
||||
|
||||
|
||||
private static class TestBean {
|
||||
|
||||
String exclaim(String input) {
|
||||
return input.toUpperCase() + "!";
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user