restructuring: branches/tags/trunk moved to top-level of repo

This commit is contained in:
Mark Fisher
2008-01-04 17:03:27 +00:00
194 changed files with 11787 additions and 0 deletions

View File

@@ -0,0 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?>
<project name="build-spring-integration" default="precommit">
<target name="precommit" depends="clean,clean-integration,jar,test"/>
<path id="bundles">
<pathelement location="../spring-integration-core"/>
<pathelement location="../spring-integration-samples"/>
</path>
<property name="integration.repo.dir" value="${basedir}/../integration-repo"/>
<import file="../spring-build/multi-bundle/default.xml"/>
</project>

View File

@@ -0,0 +1,19 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" path="src/main/java"/>
<classpathentry kind="src" output="target/test-classes" path="src/test/java"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
<classpathentry kind="var" path="IVY_CACHE/org.aopalliance/aopalliance/aopalliance-1.0.jar" sourcepath="IVY_CACHE/org.aopalliance/aopalliance/aopalliance-sources-1.0.jar"/>
<classpathentry kind="var" path="IVY_CACHE/org.apache/commons-logging/commons-logging-1.1.jar" sourcepath="/IVY_CACHE/org.apache/commons-logging/commons-logging-sources-1.1.jar"/>
<classpathentry kind="var" path="IVY_CACHE/org.junit/junit/junit-4.4.jar" sourcepath="/IVY_CACHE/org.junit/junit/junit-sources-4.4.jar"/>
<classpathentry kind="var" path="IVY_CACHE/org.springframework/spring-aop/spring-aop-2.5.0.jar" sourcepath="/IVY_CACHE/org.springframework/spring-aop/spring-aop-sources-2.5.0.jar"/>
<classpathentry kind="var" path="IVY_CACHE/org.springframework/spring-beans/spring-beans-2.5.0.jar" sourcepath="/IVY_CACHE/org.springframework/spring-beans/spring-beans-sources-2.5.0.jar"/>
<classpathentry kind="var" path="IVY_CACHE/org.springframework/spring-context/spring-context-2.5.0.jar" sourcepath="/IVY_CACHE/org.springframework/spring-context/spring-context-sources-2.5.0.jar"/>
<classpathentry kind="var" path="IVY_CACHE/org.springframework/spring-core/spring-core-2.5.0.jar" sourcepath="/IVY_CACHE/org.springframework/spring-core/spring-core-sources-2.5.0.jar"/>
<classpathentry kind="var" path="IVY_CACHE/org.springframework/spring-context-support/spring-context-support-2.5.0.jar" sourcepath="/IVY_CACHE/org.springframework/spring-context-support/spring-context-support-sources-2.5.0.jar"/>
<classpathentry kind="var" path="IVY_CACHE/org.springframework/spring-jms/spring-jms-2.5.0.jar" sourcepath="/IVY_CACHE/org.springframework/spring-jms/spring-jms-sources-2.5.0.jar"/>
<classpathentry kind="var" path="IVY_CACHE/org.springframework/spring-tx/spring-tx-2.5.0.jar"/>
<classpathentry kind="var" path="IVY_CACHE/org.apache/commons-pool/commons-pool-1.3.jar"/>
<classpathentry kind="var" path="IVY_CACHE/javax.jms/jms/jms-1.1.jar"/>
<classpathentry kind="output" path="target/classes"/>
</classpath>

View File

@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>spring-integration-core</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.jdt.core.javanature</nature>
</natures>
</projectDescription>

View File

@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<project name="spring-integration-core">
<property name="version" value="0.5-SNAPSHOT"/>
<property name="integration.repo.dir" value="${basedir}/../integration-repo"/>
<import file="../spring-build/standard/default.xml"/>
</project>

View File

@@ -0,0 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="http://ivyrep.jayasoft.org/ivy-doc.xsl"?>
<ivy-module
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="http://incubator.apache.org/ivy/schemas/ivy.xsd"
version="1.3">
<info organisation="org.springframework" module="${ant.project.name}">
<license name="Apache 2.0" url="http://www.apache.org/licenses/LICENSE-2.0"/>
<ivyauthor name="Mark Fisher"/>
</info>
<configurations>
<include file="${spring.build.dir}/common/default-ivy-configurations.xml"/>
</configurations>
<dependencies>
<dependency org="javax.jms" name="jms" rev="1.1" conf="compile->default"/>
<dependency org="org.junit" name="junit" rev="4.4" conf="test->default"/>
<dependency org="org.springframework" name="spring-context" rev="2.5.0" conf="compile->default"/>
<dependency org="org.springframework" name="spring-aop" rev="2.5.0" conf="compile->default"/>
<dependency org="org.springframework" name="spring-jms" rev="2.5.0" conf="compile->default"/>
<dependency org="org.springframework" name="spring-tx" rev="2.5.0" conf="compile->default"/>
</dependencies>
</ivy-module>

View File

@@ -0,0 +1,6 @@
SPRING INTEGRATION CHANGELOG
============================
Changes in version 1.0 M1 (Jan 04, 2008)
----------------------------------------

View File

@@ -0,0 +1,201 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
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.

View File

@@ -0,0 +1,21 @@
========================================================================
== NOTICE file corresponding to section 4 d of the Apache License, ==
== Version 2.0, in this case for the Spring Integration distribution. ==
========================================================================
This product includes software developed by
the Apache Software Foundation (http://www.apache.org).
The end-user documentation included with a redistribution, if any,
must include the following acknowledgement:
"This product includes software developed by the Spring Framework
Project (http://www.springframework.org)."
Alternatively, this acknowledgement may appear in the software itself,
if and wherever such third-party acknowledgements normally appear.
The names "Spring", "Spring Framework", and "Spring Integration" must
not be used to endorse or promote products derived from this software
without prior written permission. For written permission, please contact
rod.johnson@springsource.com or juergen.hoeller@springsource.com.

View File

@@ -0,0 +1,3 @@
SPRING INTEGRATION 1.0 M1 (JAN 04 2008)
---------------------------------------

View File

@@ -0,0 +1 @@
http\://www.springframework.org/schema/integration=org.springframework.integration.config.IntegrationNamespaceHandler

View File

@@ -0,0 +1 @@
http\://www.springframework.org/schema/integration/spring-integration-1.0.xsd=org/springframework/integration/config/spring-integration-1.0.xsd

View File

@@ -0,0 +1,35 @@
/*
* Copyright 2002-2007 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;
/**
* Exception that indicates an error during message delivery.
*
* @author Mark Fisher
*/
@SuppressWarnings("serial")
public class MessageDeliveryException extends MessagingException {
public MessageDeliveryException(String message) {
super(message);
}
public MessageDeliveryException(String message, Throwable cause) {
super(message, cause);
}
}

View File

@@ -0,0 +1,35 @@
/*
* Copyright 2002-2007 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;
/**
* Exception that indicates an error during message handling.
*
* @author Mark Fisher
*/
@SuppressWarnings("serial")
public class MessageHandlingException extends MessagingException {
public MessageHandlingException(String message) {
super(message);
}
public MessageHandlingException(String message, Throwable cause) {
super(message, cause);
}
}

View File

@@ -0,0 +1,35 @@
/*
* Copyright 2002-2007 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;
/**
* Exception that indicates an incorrectly configured messaging component.
*
* @author Mark Fisher
*/
@SuppressWarnings("serial")
public class MessagingConfigurationException extends MessagingException {
public MessagingConfigurationException(String message) {
super(message);
}
public MessagingConfigurationException(String message, Throwable cause) {
super(message, cause);
}
}

View File

@@ -0,0 +1,35 @@
/*
* Copyright 2002-2007 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;
/**
* The base exception for any failures within the messaging system.
*
* @author Mark Fisher
*/
@SuppressWarnings("serial")
public class MessagingException extends RuntimeException {
public MessagingException(String message) {
super(message);
}
public MessagingException(String message, Throwable cause) {
super(message, cause);
}
}

View File

@@ -0,0 +1,31 @@
/*
* Copyright 2002-2007 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;
/**
* An unchecked wrapper exception for InterruptedExceptions.
*
* @author Mark Fisher
*/
@SuppressWarnings("serial")
public class SystemInterruptedException extends MessagingException {
public SystemInterruptedException(String message, Throwable cause) {
super(message, cause);
}
}

View File

@@ -0,0 +1,65 @@
/*
* Copyright 2002-2007 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.adapter;
import org.springframework.integration.channel.MessageChannel;
import org.springframework.integration.message.Message;
import org.springframework.integration.message.MessageMapper;
import org.springframework.integration.message.SimplePayloadMessageMapper;
import org.springframework.util.Assert;
/**
* A base class providing common behavior for source adapters.
*
* @author Mark Fisher
*/
public class AbstractSourceAdapter<T> implements SourceAdapter {
private MessageChannel channel;
private MessageMapper<?,T> mapper = new SimplePayloadMessageMapper<T>();
private long sendTimeout = -1;
public void setChannel(MessageChannel channel) {
Assert.notNull(channel, "'channel' must not be null");
this.channel = channel;
}
public void setSendTimeout(long sendTimeout) {
this.sendTimeout = sendTimeout;
}
public void setMessageMapper(MessageMapper<?,T> mapper) {
Assert.notNull(mapper, "'mapper' must not be null");
this.mapper = mapper;
}
protected MessageMapper<?,T> getMessageMapper() {
return this.mapper;
}
protected boolean sendToChannel(T object) {
Message<?> message = this.mapper.toMessage(object);
if (this.sendTimeout < 0) {
return this.channel.send(message);
}
return this.channel.send(message, this.sendTimeout);
}
}

View File

@@ -0,0 +1,83 @@
/*
* Copyright 2002-2007 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.adapter;
import org.springframework.integration.bus.ConsumerPolicy;
import org.springframework.integration.channel.MessageChannel;
import org.springframework.integration.message.Message;
import org.springframework.integration.message.MessageMapper;
import org.springframework.integration.message.SimplePayloadMessageMapper;
import org.springframework.util.Assert;
/**
* Base class providing common behavior for target adapters.
*
* @author Mark Fisher
*/
public abstract class AbstractTargetAdapter<T> implements TargetAdapter<T> {
private String name;
private MessageChannel channel;
private MessageMapper<?,T> mapper = new SimplePayloadMessageMapper<T>();
private ConsumerPolicy policy = ConsumerPolicy.newPollingPolicy(5);
public void setName(String name) {
this.name = name;
}
public String getName() {
return this.name;
}
public void setChannel(MessageChannel channel) {
Assert.notNull(channel, "'channel' must not be null");
this.channel = channel;
}
public MessageChannel getChannel() {
return this.channel;
}
public void setMessageMapper(MessageMapper<?,T> mapper) {
Assert.notNull(mapper, "'mapper' must not be null");
this.mapper = mapper;
}
protected MessageMapper<?,T> getMessageMapper() {
return this.mapper;
}
public void setConsumerPolicy(ConsumerPolicy policy) {
Assert.notNull(policy, "'policy' must not be null");
this.policy = policy;
}
public ConsumerPolicy getConsumerPolicy() {
return this.policy;
}
public final void messageReceived(Message message) {
this.sendToTarget(this.mapper.fromMessage(message));
}
protected abstract boolean sendToTarget(T object);
}

View File

@@ -0,0 +1,28 @@
/*
* Copyright 2002-2007 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.adapter;
/**
* A strategy for preparing an argument list from a single source object.
*
* @author Mark Fisher
*/
public interface ArgumentListPreparer {
Object[] prepare(Object source);
}

View File

@@ -0,0 +1,42 @@
/*
* Copyright 2002-2007 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.adapter;
import org.springframework.integration.message.MessageMapper;
import org.springframework.util.Assert;
/**
* Target adapter implementation that delegates to a {@link MessageMapper}
* and then passes the resulting object to the provided {@link Target}.
*
* @author Mark Fisher
*/
public class DefaultTargetAdapter<T> extends AbstractTargetAdapter<T> {
private Target<T> target;
public DefaultTargetAdapter(Target<T> target) {
Assert.notNull(target, "'target' must not be null");
this.target = target;
}
public boolean sendToTarget(T object) {
return this.target.send(object);
}
}

View File

@@ -0,0 +1,76 @@
/*
* Copyright 2002-2007 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.adapter;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Collection;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.integration.MessagingConfigurationException;
import org.springframework.integration.util.MethodValidator;
import org.springframework.integration.util.SimpleMethodInvoker;
import org.springframework.util.Assert;
/**
* A pollable source that invokes a no-argument method so that its return value
* may be sent to a channel.
*
* @author Mark Fisher
*/
public class MethodInvokingSource<T> implements PollableSource<Object>, InitializingBean {
private T object;
private String method;
private SimpleMethodInvoker<T> invoker;
public void setObject(T object) {
Assert.notNull(object, "'object' must not be null");
this.object = object;
}
public void setMethod(String method) {
Assert.notNull(method, "'method' must not be null");
this.method = method;
}
public void afterPropertiesSet() {
this.invoker = new SimpleMethodInvoker<T>(this.object, this.method);
this.invoker.setMethodValidator(new MessageReceivingMethodValidator());
}
public Collection<Object> poll(int limit) {
if (this.invoker == null) {
this.afterPropertiesSet();
}
return Arrays.asList(this.invoker.invokeMethod(new Object[] {}));
}
private static class MessageReceivingMethodValidator implements MethodValidator {
public void validate(Method method) {
if (method.getReturnType().equals(void.class)) {
throw new MessagingConfigurationException("MethodInvokingSource requires a non-void returning method.");
}
}
}
}

View File

@@ -0,0 +1,77 @@
/*
* Copyright 2002-2007 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.adapter;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.integration.util.SimpleMethodInvoker;
import org.springframework.util.Assert;
/**
* A messaging target that invokes the specified method on the provided object.
*
* @author Mark Fisher
*/
public class MethodInvokingTarget<T> implements Target<Object>, InitializingBean {
private Log logger = LogFactory.getLog(this.getClass());
private T object;
private String method;
private SimpleMethodInvoker<T> invoker;
private ArgumentListPreparer argumentListPreparer;
public void setObject(T object) {
Assert.notNull(object, "'object' must not be null");
this.object = object;
}
public void setMethod(String method) {
Assert.notNull(method, "'method' must not be null");
this.method = method;
}
public void setArgumentListPreparer(ArgumentListPreparer argumentListPreparer) {
this.argumentListPreparer = argumentListPreparer;
}
public void afterPropertiesSet() {
this.invoker = new SimpleMethodInvoker<T>(this.object, this.method);
}
public boolean send(Object object) {
Object args[] = null;
if (this.argumentListPreparer != null) {
args = this.argumentListPreparer.prepare(object);
}
else {
args = new Object[] { object };
}
Object result = this.invoker.invokeMethod(args);
if (result != null && logger.isWarnEnabled()) {
logger.warn("ignoring outbound channel adapter's return value");
}
return true;
}
}

View File

@@ -0,0 +1,30 @@
/*
* Copyright 2002-2007 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.adapter;
import java.util.Collection;
/**
* Interface for any external data source that can be polled.
*
* @author Mark Fisher
*/
public interface PollableSource<T> {
Collection<T> poll(int limit);
}

View File

@@ -0,0 +1,80 @@
/*
* Copyright 2002-2007 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.adapter;
import java.util.Collection;
import org.springframework.integration.MessageHandlingException;
import org.springframework.integration.bus.ConsumerPolicy;
import org.springframework.integration.bus.MessageDispatcher;
import org.springframework.integration.channel.MessageChannel;
import org.springframework.integration.message.MessageMapper;
import org.springframework.util.Assert;
/**
* A channel adapter that retrieves objects from a {@link PollableSource},
* delegates to a {@link MessageMapper} to create messages from those objects,
* and then sends the resulting messages to the provided {@link MessageChannel}.
*
* @author Mark Fisher
*/
public class PollingSourceAdapter<T> extends AbstractSourceAdapter<T> implements MessageDispatcher {
private static int DEFAULT_PERIOD = 1000;
private PollableSource<T> source;
private ConsumerPolicy policy = ConsumerPolicy.newPollingPolicy(DEFAULT_PERIOD);
public PollingSourceAdapter(PollableSource<T> source) {
Assert.notNull(source, "'source' must not be null");
this.source = source;
}
public void setPeriod(int period) {
Assert.isTrue(period > 0, "'period' must be a positive value");
this.policy.setPeriod(period);
}
public void setMaxMessagesPerTask(int maxMessagesPerTask) {
Assert.isTrue(maxMessagesPerTask > 0, "'maxMessagesPerTask' must be a positive value");
this.policy.setMaxMessagesPerTask(maxMessagesPerTask);
}
public ConsumerPolicy getConsumerPolicy() {
return this.policy;
}
public int dispatch() {
int messagesProcessed = 0;
int limit = this.policy.getMaxMessagesPerTask();
Collection<T> results = this.source.poll(limit);
if (results != null) {
if (results.size() > limit) {
throw new MessageHandlingException("source returned too many results, the limit is " + limit);
}
for (T next : results) {
if (this.sendToChannel(next)) {
messagesProcessed++;
}
}
}
return messagesProcessed;
}
}

View File

@@ -0,0 +1,30 @@
/*
* Copyright 2002-2007 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.adapter;
import org.springframework.integration.channel.MessageChannel;
/**
* Base interface for source adapters.
*
* @author Mark Fisher
*/
public interface SourceAdapter {
void setChannel(MessageChannel channel);
}

View File

@@ -0,0 +1,29 @@
/*
* Copyright 2002-2007 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.adapter;
/**
* Interface for any external target that may receive data from an outgoing
* channel adapter.
*
* @author Mark Fisher
*/
public interface Target<T> {
boolean send(T t);
}

View File

@@ -0,0 +1,36 @@
/*
* Copyright 2002-2007 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.adapter;
import org.springframework.integration.bus.ConsumerPolicy;
import org.springframework.integration.channel.MessageChannel;
import org.springframework.integration.message.MessageReceiver;
/**
* Base interface for target adapters.
*
* @author Mark Fisher
*/
public interface TargetAdapter<T> extends MessageReceiver<T> {
String getName();
void setChannel(MessageChannel channel);
ConsumerPolicy getConsumerPolicy();
}

View File

@@ -0,0 +1,63 @@
/*
* Copyright 2002-2007 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.adapter.event;
import java.util.ArrayList;
import java.util.List;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.integration.adapter.AbstractSourceAdapter;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
/**
* A source adapter for passing Spring
* {@link ApplicationEvent ApplicationEvents} within messages.
*
* @author Mark Fisher
*/
public class ApplicationEventSourceAdapter extends AbstractSourceAdapter<ApplicationEvent> implements
ApplicationListener {
private List<Class<? extends ApplicationEvent>> eventTypes = new ArrayList<Class<? extends ApplicationEvent>>();
/**
* Set the list of event types (classes that extend ApplicationEvent) that
* this adapter should send to the message channel. By default, all event
* types will be sent.
*/
public void setEventTypes(List<Class<? extends ApplicationEvent>> eventTypes) {
Assert.notEmpty(eventTypes, "at least one event type is required");
this.eventTypes = eventTypes;
}
public void onApplicationEvent(ApplicationEvent event) {
if (CollectionUtils.isEmpty(this.eventTypes)) {
this.sendToChannel(event);
return;
}
for (Class<? extends ApplicationEvent> eventType : this.eventTypes) {
if (eventType.isAssignableFrom(event.getClass())) {
this.sendToChannel(event);
return;
}
}
}
}

View File

@@ -0,0 +1,51 @@
/*
* Copyright 2002-2007 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.adapter.event;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware;
import org.springframework.integration.adapter.AbstractTargetAdapter;
/**
* A target adapter for publishing {@link MessagingEvent MessagingEvents}. The
* {@link MessagingEvent} is a subclass of Spring's {@link ApplicationEvent}
* used by this adapter to wrap any {@link Message} received on its channel.
*
* @author Mark Fisher
*/
public class ApplicationEventTargetAdapter extends AbstractTargetAdapter<MessagingEvent> implements
ApplicationEventPublisherAware {
private ApplicationEventPublisher applicationEventPublisher;
public ApplicationEventTargetAdapter() {
this.setMessageMapper(new MessagingEventMapper());
}
public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
this.applicationEventPublisher = applicationEventPublisher;
}
@Override
protected boolean sendToTarget(MessagingEvent event) {
this.applicationEventPublisher.publishEvent(event);
return true;
}
}

View File

@@ -0,0 +1,37 @@
/*
* Copyright 2002-2007 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.adapter.event;
import org.springframework.context.ApplicationEvent;
import org.springframework.integration.message.Message;
/**
* A subclass of {@link ApplicationEvent} that wraps a {@link Message}.
*
* @author Mark Fisher
*/
public class MessagingEvent<T> extends ApplicationEvent {
public MessagingEvent(Message<T> message) {
super(message);
}
public Message<T> getMessage() {
return (Message<T>) this.getSource();
}
}

View File

@@ -0,0 +1,38 @@
/*
* Copyright 2002-2007 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.adapter.event;
import org.springframework.integration.message.Message;
import org.springframework.integration.message.MessageMapper;
/**
* A {@link MessageMapper} implementation for mapping to and from
* {@link MessagingEvent MessagingEvents}.
*
* @author Mark Fisher
*/
public class MessagingEventMapper<T> implements MessageMapper<T, MessagingEvent<T>> {
public MessagingEvent<T> fromMessage(Message<T> message) {
return new MessagingEvent<T>(message);
}
public Message<T> toMessage(MessagingEvent<T> event) {
return event.getMessage();
}
}

View File

@@ -0,0 +1,101 @@
/*
* Copyright 2002-2007 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.adapter.file;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.integration.MessageHandlingException;
import org.springframework.integration.message.AbstractMessageMapper;
import org.springframework.integration.message.GenericMessage;
import org.springframework.integration.message.Message;
import org.springframework.util.Assert;
import org.springframework.util.FileCopyUtils;
/**
* Base class providing common behavior for file-based message mappers.
*
* @author Mark Fisher
*/
public abstract class AbstractFileMapper<T> extends AbstractMessageMapper<T, File> {
protected Log logger = LogFactory.getLog(this.getClass());
private File parentDirectory;
private File backupDirectory;
private FileNameGenerator fileNameGenerator = new DefaultFileNameGenerator();
public AbstractFileMapper(File parentDirectory) {
this.parentDirectory = parentDirectory;
}
public void setBackupDirectory(File backupDirectory) {
this.backupDirectory = backupDirectory;
}
public void setFileNameGenerator(FileNameGenerator fileNameGenerator) {
Assert.notNull(fileNameGenerator, "'fileNameGenerator' must not be null");
this.fileNameGenerator = fileNameGenerator;
}
public File fromMessage(Message<T> message) {
try {
File file = new File(parentDirectory, this.fileNameGenerator.generateFileName(message));
this.writeToFile(file, message.getPayload());
return file;
}
catch (Exception e) {
throw new MessageHandlingException("failure occurred mapping file to message", e);
}
}
public Message<T> toMessage(File file) {
try {
T payload = this.readMessagePayload(file);
if (payload == null) {
return null;
}
Message<T> message = new GenericMessage<T>(this.getUidGenerator().generateUid(), payload);
if (this.backupDirectory != null) {
FileWriter writer = new FileWriter(this.backupDirectory.getAbsolutePath() +
File.separator + file.getName());
FileCopyUtils.copy(new FileReader(file), writer);
}
file.delete();
return message;
}
catch (Exception e) {
String errorMessage = "failure occurred mapping file to message";
if (logger.isWarnEnabled()) {
logger.warn(errorMessage, e);
}
throw new MessageHandlingException(errorMessage, e);
}
}
protected abstract T readMessagePayload(File file) throws Exception;
protected abstract void writeToFile(File file, T payload) throws Exception;
}

View File

@@ -0,0 +1,46 @@
/*
* Copyright 2002-2007 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.adapter.file;
import java.io.File;
import org.springframework.util.FileCopyUtils;
/**
* A {@link org.springframework.integration.message.MessageMapper}
* implementation for messages with a byte array payload.
*
* @author Mark Fisher
*/
public class ByteArrayFileMapper extends AbstractFileMapper<byte[]> {
public ByteArrayFileMapper(File parentDirectory) {
super(parentDirectory);
}
@Override
protected byte[] readMessagePayload(File file) throws Exception {
return FileCopyUtils.copyToByteArray(file);
}
@Override
protected void writeToFile(File file, byte[] payload) throws Exception {
FileCopyUtils.copy(payload, file);
}
}

View File

@@ -0,0 +1,36 @@
/*
* Copyright 2002-2007 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.adapter.file;
import org.springframework.integration.message.Message;
import org.springframework.util.StringUtils;
/**
* Default implementation of the filename generator strategy. Concatenates the
* message id and the current timestamp.
*
* @author Mark Fisher
*/
public class DefaultFileNameGenerator implements FileNameGenerator {
public String generateFileName(Message<?> message) {
String filenameProperty = message.getHeader().getProperty(FILENAME_PROPERTY_KEY);
return StringUtils.hasText(filenameProperty) ?
filenameProperty : message.getId() + "-" + System.currentTimeMillis() + ".msg";
}
}

View File

@@ -0,0 +1,33 @@
/*
* Copyright 2002-2007 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.adapter.file;
import org.springframework.integration.message.Message;
/**
* Strategy interface for generating a file name from a message.
*
* @author Mark Fisher
*/
public interface FileNameGenerator {
String FILENAME_PROPERTY_KEY = "filename";
String generateFileName(Message<?> message);
}

View File

@@ -0,0 +1,80 @@
/*
* Copyright 2002-2007 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.adapter.file;
import java.io.File;
import java.io.FileFilter;
import java.io.FilenameFilter;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import org.springframework.integration.MessageHandlingException;
import org.springframework.integration.adapter.PollableSource;
import org.springframework.util.Assert;
/**
* A messaging source that polls a directory to retrieve files.
*
* @author Mark Fisher
*/
public class FileSource implements PollableSource<File> {
private File directory;
private FileFilter fileFilter;
private FilenameFilter filenameFilter;
public FileSource(File directory) {
Assert.notNull("directory must not be null");
this.directory = directory;
}
public void setFileFilter(FileFilter fileFilter) {
this.fileFilter = fileFilter;
}
public void setFilenameFilter(FilenameFilter filenameFilter) {
this.filenameFilter = filenameFilter;
}
public Collection<File> poll(int limit) {
File[] files = null;
if (this.fileFilter != null) {
files = this.directory.listFiles(fileFilter);
}
else if (this.filenameFilter != null) {
files = this.directory.listFiles(filenameFilter);
}
else {
files = this.directory.listFiles();
}
if (files == null) {
throw new MessageHandlingException("Problem occurred while polling for files. " +
"Is '" + directory.getAbsolutePath() + "' a directory?");
}
int size = Math.min(limit, files.length);
List<File> results = new ArrayList<File>(size);
for (int i = 0; i < size; i++) {
results.add(files[i]);
}
return results;
}
}

View File

@@ -0,0 +1,65 @@
/*
* Copyright 2002-2007 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.adapter.file;
import java.io.File;
import org.springframework.integration.adapter.PollingSourceAdapter;
import org.springframework.integration.channel.MessageChannel;
import org.springframework.integration.message.MessageMapper;
import org.springframework.util.Assert;
/**
* Channel adapter for polling a directory and creating messages from its files.
*
* @author Mark Fisher
*/
public class FileSourceAdapter extends PollingSourceAdapter<File> {
public FileSourceAdapter(File directory, MessageChannel channel, int period) {
this(directory, channel, period, true);
}
public FileSourceAdapter(File directory, MessageChannel channel, int period, boolean isTextBased) {
super(new FileSource(directory));
this.setChannel(channel);
this.setPeriod(period);
if (isTextBased) {
this.setMessageMapper(new TextFileMapper(directory));
}
else {
this.setMessageMapper(new ByteArrayFileMapper(directory));
}
}
public void setFileNameGenerator(FileNameGenerator fileNameGenerator) {
Assert.notNull(fileNameGenerator, "'fileNameGenerator' must not be null");
MessageMapper<?,?> mapper = this.getMessageMapper();
if (mapper instanceof AbstractFileMapper<?>) {
((AbstractFileMapper<?>) mapper).setFileNameGenerator(fileNameGenerator);
}
}
public void setBackupDirectory(File backupDirectory) {
Assert.notNull(backupDirectory, "'backupDirectory' must not be null");
MessageMapper<?, File> mapper = this.getMessageMapper();
if (mapper != null && (mapper instanceof AbstractFileMapper<?>)) {
((AbstractFileMapper<?>) mapper).setBackupDirectory(backupDirectory);
}
}
}

View File

@@ -0,0 +1,59 @@
/*
* Copyright 2002-2007 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.adapter.file;
import java.io.File;
import org.springframework.integration.adapter.AbstractTargetAdapter;
import org.springframework.integration.message.MessageMapper;
import org.springframework.util.Assert;
/**
* A convenience adapter for writing files. The actual file writing occurs in
* the message mapper ({@link TextFileMapper} or {@link ByteArrayFileMapper}).
*
* @author Mark Fisher
*/
public class FileTargetAdapter extends AbstractTargetAdapter<File> {
public FileTargetAdapter(File directory) {
this(directory, true);
}
public FileTargetAdapter(File directory, boolean isTextBased) {
if (isTextBased) {
this.setMessageMapper(new TextFileMapper(directory));
}
else {
this.setMessageMapper(new ByteArrayFileMapper(directory));
}
}
public void setFileNameGenerator(FileNameGenerator fileNameGenerator) {
Assert.notNull(fileNameGenerator, "'fileNameGenerator' must not be null");
MessageMapper<?,?> mapper = this.getMessageMapper();
if (mapper instanceof AbstractFileMapper<?>) {
((AbstractFileMapper<?>) mapper).setFileNameGenerator(fileNameGenerator);
}
}
@Override
protected boolean sendToTarget(File file) {
return file.exists();
}
}

View File

@@ -0,0 +1,48 @@
/*
* Copyright 2002-2007 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.adapter.file;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import org.springframework.util.FileCopyUtils;
/**
* A {@link org.springframework.integration.message.MessageMapper}
* implementation for messages with a String payload.
*
* @author Mark Fisher
*/
public class TextFileMapper extends AbstractFileMapper<String> {
public TextFileMapper(File parentDirectory) {
super(parentDirectory);
}
@Override
protected String readMessagePayload(File file) throws Exception {
return FileCopyUtils.copyToString(new FileReader(file));
}
@Override
protected void writeToFile(File file, String payload) throws Exception {
FileCopyUtils.copy(payload, new FileWriter(file));
}
}

View File

@@ -0,0 +1,49 @@
/*
* Copyright 2002-2007 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.adapter.file.config;
import org.w3c.dom.Element;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser;
import org.springframework.integration.adapter.file.FileSourceAdapter;
/**
* Parser for the &lt;file-source/&gt; element.
*
* @author Mark Fisher
*/
public class FileSourceAdapterParser extends AbstractSingleBeanDefinitionParser {
protected Class getBeanClass(Element element) {
return FileSourceAdapter.class;
}
protected boolean shouldGenerateId() {
return true;
}
protected void doParse(Element element, BeanDefinitionBuilder builder) {
String directory = element.getAttribute("directory");
String channel = element.getAttribute("channel");
String pollPeriod = element.getAttribute("poll-period");
builder.addConstructorArg(directory);
builder.addConstructorArgReference(channel);
builder.addConstructorArg(pollPeriod);
}
}

View File

@@ -0,0 +1,47 @@
/*
* Copyright 2002-2007 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.adapter.file.config;
import org.w3c.dom.Element;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser;
import org.springframework.integration.adapter.file.FileTargetAdapter;
/**
* Parser for the &lt;file-target/&gt; element.
*
* @author Mark Fisher
*/
public class FileTargetAdapterParser extends AbstractSingleBeanDefinitionParser {
protected Class getBeanClass(Element element) {
return FileTargetAdapter.class;
}
protected boolean shouldGenerateId() {
return true;
}
protected void doParse(Element element, BeanDefinitionBuilder builder) {
String directory = element.getAttribute("directory");
String channel = element.getAttribute("channel");
builder.addConstructorArg(directory);
builder.addPropertyReference("channel", channel);
}
}

View File

@@ -0,0 +1,96 @@
/*
* Copyright 2002-2007 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.adapter.jms;
import java.util.Arrays;
import java.util.Collection;
import javax.jms.ConnectionFactory;
import javax.jms.Destination;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.integration.MessagingConfigurationException;
import org.springframework.integration.adapter.PollableSource;
import org.springframework.jms.core.JmsTemplate;
/**
* A source for receiving JMS Messages with a polling listener. This source is
* only recommended for very low message volume. Otherwise, an event-driven
* option that uses one of Spring's MessageListener containers is highly
* recommended.
*
* @author Mark Fisher
*/
public class JmsPollableSource implements PollableSource<Object>, InitializingBean {
private ConnectionFactory connectionFactory;
private Destination destination;
private JmsTemplate jmsTemplate;
public JmsPollableSource(JmsTemplate jmsTemplate) {
this.jmsTemplate = jmsTemplate;
}
public JmsPollableSource(ConnectionFactory connectionFactory, Destination destination) {
this.connectionFactory = connectionFactory;
this.destination = destination;
this.initJmsTemplate();
}
/**
* No-arg constructor provided for convenience when configuring with
* setters. Note that the initialization callback will validate.
*/
public JmsPollableSource() {
}
public void setConnectionFactory(ConnectionFactory connectionFactory) {
this.connectionFactory = connectionFactory;
}
public void setDestination(Destination destination) {
this.destination = destination;
}
public void setJmsTemplate(JmsTemplate jmsTemplate) {
this.jmsTemplate = jmsTemplate;
}
public void afterPropertiesSet() {
if (this.jmsTemplate == null) {
if (this.connectionFactory == null || this.destination == null) {
throw new MessagingConfigurationException("Either a 'jmsTemplate' or "
+ "*both* 'connectionFactory' and 'destination' are required.");
}
this.initJmsTemplate();
}
}
private void initJmsTemplate() {
this.jmsTemplate = new JmsTemplate();
this.jmsTemplate.setConnectionFactory(this.connectionFactory);
this.jmsTemplate.setDefaultDestination(this.destination);
}
public Collection<Object> poll(int limit) {
return Arrays.asList(this.jmsTemplate.receiveAndConvert());
}
}

View File

@@ -0,0 +1,40 @@
/*
* Copyright 2002-2007 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.adapter.jms;
import javax.jms.ConnectionFactory;
import javax.jms.Destination;
import org.springframework.integration.adapter.PollingSourceAdapter;
import org.springframework.jms.core.JmsTemplate;
/**
* A convenience adapter that wraps a {@link JmsPollableSource}.
*
* @author Mark Fisher
*/
public class JmsPollingSourceAdapter extends PollingSourceAdapter<Object> {
public JmsPollingSourceAdapter(ConnectionFactory connectionFactory, Destination destination) {
super(new JmsPollableSource(connectionFactory, destination));
}
public JmsPollingSourceAdapter(JmsTemplate jmsTemplate) {
super(new JmsPollableSource(jmsTemplate));
}
}

View File

@@ -0,0 +1,93 @@
/*
* Copyright 2002-2007 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.adapter.jms;
import javax.jms.ConnectionFactory;
import javax.jms.Destination;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.integration.MessagingConfigurationException;
import org.springframework.integration.adapter.AbstractTargetAdapter;
import org.springframework.jms.core.JmsTemplate;
/**
* A target adapter for sending JMS Messages.
*
* @author Mark Fisher
*/
public class JmsTargetAdapter extends AbstractTargetAdapter<Object> implements InitializingBean {
private ConnectionFactory connectionFactory;
private Destination destination;
private JmsTemplate jmsTemplate;
public JmsTargetAdapter(JmsTemplate jmsTemplate) {
this.jmsTemplate = jmsTemplate;
}
public JmsTargetAdapter(ConnectionFactory connectionFactory, Destination destination) {
this.connectionFactory = connectionFactory;
this.destination = destination;
this.initJmsTemplate();
}
/**
* No-arg constructor provided for convenience when configuring with
* setters. Note that the initialization callback will validate.
*/
public JmsTargetAdapter() {
}
public void setConnectionFactory(ConnectionFactory connectionFactory) {
this.connectionFactory = connectionFactory;
}
public void setDestination(Destination destination) {
this.destination = destination;
}
public void setJmsTemplate(JmsTemplate jmsTemplate) {
this.jmsTemplate = jmsTemplate;
}
public void afterPropertiesSet() {
if (this.jmsTemplate == null) {
if (this.connectionFactory == null || this.destination == null) {
throw new MessagingConfigurationException("Either a 'jmsTemplate' or " +
"*both* 'connectionFactory' and 'destination' are required.");
}
this.initJmsTemplate();
}
}
private void initJmsTemplate() {
this.jmsTemplate = new JmsTemplate();
this.jmsTemplate.setConnectionFactory(this.connectionFactory);
this.jmsTemplate.setDefaultDestination(this.destination);
}
@Override
protected boolean sendToTarget(Object object) {
this.jmsTemplate.convertAndSend(object);
return true;
}
}

View File

@@ -0,0 +1,82 @@
/*
* Copyright 2002-2007 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.adapter.jms.config;
import org.w3c.dom.Element;
import org.springframework.beans.factory.BeanCreationException;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser;
import org.springframework.integration.adapter.jms.JmsTargetAdapter;
import org.springframework.util.StringUtils;
/**
* Parser for the &lt;jms-target/&gt; element.
*
* @author Mark Fisher
*/
public class JmsTargetAdapterParser extends AbstractSingleBeanDefinitionParser {
private static final String JMS_TEMPLATE_ATTRIBUTE = "jms-template";
private static final String JMS_TEMPLATE_PROPERTY = "jmsTemplate";
private static final String CONNECTION_FACTORY_ATTRIBUTE = "connection-factory";
private static final String CONNECTION_FACTORY_PROPERTY = "connectionFactory";
private static final String DESTINATION_ATTRIBUTE = "destination";
private static final String DESTINATION_PROPERTY = "destination";
private static final String CHANNEL_ATTRIBUTE = "channel";
private static final String CHANNEL_PROPERTY = "channel";
protected Class<?> getBeanClass(Element element) {
return JmsTargetAdapter.class;
}
protected boolean shouldGenerateId() {
return true;
}
protected void doParse(Element element, BeanDefinitionBuilder builder) {
String jmsTemplate = element.getAttribute(JMS_TEMPLATE_ATTRIBUTE);
String connectionFactory = element.getAttribute(CONNECTION_FACTORY_ATTRIBUTE);
String destination = element.getAttribute(DESTINATION_ATTRIBUTE);
if (StringUtils.hasText(jmsTemplate)) {
if (StringUtils.hasText(connectionFactory) || StringUtils.hasText(destination)) {
throw new BeanCreationException("when providing a 'jms-template' reference, neither " +
"'connection-factory' or 'destination' should be provided.");
}
builder.addPropertyReference(JMS_TEMPLATE_PROPERTY, jmsTemplate);
}
else if (StringUtils.hasText(connectionFactory) && StringUtils.hasText(destination)) {
builder.addPropertyReference(CONNECTION_FACTORY_PROPERTY, connectionFactory);
builder.addPropertyReference(DESTINATION_PROPERTY, destination);
}
else {
throw new BeanCreationException("either a 'jms-template' reference or both " +
"'connection-factory' and 'destination' references must be provided.");
}
String channel = element.getAttribute(CHANNEL_ATTRIBUTE);
builder.addPropertyReference(CHANNEL_PROPERTY, channel);
}
}

View File

@@ -0,0 +1,41 @@
/*
* Copyright 2002-2007 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 org.springframework.integration.message.Message;
/**
* Indicates that a method is capable of sending messages. The method must
* accept a single parameter that is either a {@link Message} or an Object to
* be passed as a message payload. The enclosing class should be annotated with
* {@link MessageEndpoint @MessageEndpoint}.
*
* @author Mark Fisher
*/
@java.lang.annotation.Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface DefaultOutput {
}

View File

@@ -0,0 +1,40 @@
/*
* Copyright 2002-2007 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 handling a message or message payload.
* The method may only accept a single parameter, and the enclosing class should
* be annotated with {@link MessageEndpoint @MessageEndpoint}.
*
* @author Mark Fisher
*/
@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Handler {
}

View File

@@ -0,0 +1,46 @@
/*
* Copyright 2002-2007 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;
import org.springframework.stereotype.Component;
/**
* Indicates that a class is capable of serving as a message endpoint.
*
* @author Mark Fisher
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
@Component
public @interface MessageEndpoint {
String input() default "";
String defaultOutput() default "";
int pollPeriod() default 0;
}

View File

@@ -0,0 +1,42 @@
/*
* Copyright 2002-2007 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 providing messages. The method must not
* accept any parameters but can return either a single object or collection.
* The enclosing class should be annotated with
* {@link MessageEndpoint @MessageEndpoint}.
*
* @author Mark Fisher
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Polled {
int period() default 1000;
}

View File

@@ -0,0 +1,40 @@
/*
* Copyright 2002-2007 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 the method's return value should be published to the specified
* channel. The value will only be published if non-null.
*
* @author Mark Fisher
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Publisher {
String channel();
}

View File

@@ -0,0 +1,51 @@
/*
* Copyright 2002-2007 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 resolving to a channel or channel name
* based on a message, message payload, message attribute, or message property.
*
* @author Mark Fisher
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
@Handler
public @interface Router {
/**
* String value representing the name of the property that should be passed
* into the router method. This and 'attribute' should not both be provided.
*/
String property() default "";
/**
* String value representing the name of the attribute that should be passed
* into the router method. This and 'property' should not both be provided.
*/
String attribute() default "";
}

View File

@@ -0,0 +1,40 @@
/*
* Copyright 2002-2007 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.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Indicates that a method is capable of splitting a single message or message
* payload to produce multiple messages which are then sent to the channel whose
* name is provided with the 'channel' attribute.
*
* @author Mark Fisher
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Handler
public @interface Splitter {
String channel();
}

View File

@@ -0,0 +1,40 @@
/*
* Copyright 2002-2007 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-invoking handler adapter should delegate to this
* method.
*
* @author Mark Fisher
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Subscriber {
String channel();
}

View File

@@ -0,0 +1,73 @@
/*
* Copyright 2002-2007 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.aop;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import org.aopalliance.intercept.MethodInvocation;
import org.springframework.aop.support.AopUtils;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.integration.channel.ChannelRegistry;
import org.springframework.integration.channel.MessageChannel;
import org.springframework.util.Assert;
/**
* {@link MessagePublishingInterceptor} that resolves the channel from the
* publisher annotation of the invoked method.
*
* @author Mark Fisher
*/
public class AnnotationAwareMessagePublishingInterceptor extends MessagePublishingInterceptor {
private Class<? extends Annotation> publisherAnnotationType;
private String channelAttributeName;
private ChannelRegistry channelRegistry;
public AnnotationAwareMessagePublishingInterceptor(Class<? extends Annotation> publisherAnnotationType,
String channelAttributeName, ChannelRegistry channelRegistry) {
Assert.notNull(publisherAnnotationType, "'publisherAnnotationType' must not be null");
Assert.notNull(channelAttributeName, "'channelAttributeName' must not be null");
Assert.notNull(channelRegistry, "'channelRegistry' must not be null");
this.publisherAnnotationType = publisherAnnotationType;
this.channelAttributeName = channelAttributeName;
this.channelRegistry = channelRegistry;
}
@Override
protected MessageChannel resolveChannel(MethodInvocation invocation) {
Class<?> targetClass = AopUtils.getTargetClass(invocation.getThis());
Method method = AopUtils.getMostSpecificMethod(invocation.getMethod(), targetClass);
Annotation annotation = AnnotationUtils.getAnnotation(method, this.publisherAnnotationType);
if (annotation != null) {
String channelName = (String) AnnotationUtils.getValue(annotation, this.channelAttributeName);
if (channelName != null) {
MessageChannel channel = this.channelRegistry.lookupChannel(channelName);
if (channel != null) {
return channel;
}
}
}
return super.resolveChannel(invocation);
}
}

View File

@@ -0,0 +1,86 @@
/*
* Copyright 2002-2007 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.aop;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.integration.channel.MessageChannel;
import org.springframework.integration.message.MessageMapper;
import org.springframework.integration.message.SimplePayloadMessageMapper;
import org.springframework.util.Assert;
/**
* Interceptor that publishes a target method's return value to a channel.
*
* @author Mark Fisher
*/
public class MessagePublishingInterceptor implements MethodInterceptor {
protected Log logger = LogFactory.getLog(getClass());
private MessageMapper mapper = new SimplePayloadMessageMapper();
private MessageChannel defaultChannel;
public void setDefaultChannel(MessageChannel defaultChannel) {
this.defaultChannel = defaultChannel;
}
/**
* Specify the {@link MessageMapper} to use when creating a message from the
* return value Object. The default is a {@link SimplePayloadMessageMapper}.
*
* @param mapper the mapper to use
*/
public void setMessageMapper(MessageMapper mapper) {
Assert.notNull(mapper, "mapper must not be null");
this.mapper = mapper;
}
/**
* Invoke the target method and publish its return value.
*/
public Object invoke(MethodInvocation invocation) throws Throwable {
Object retval = invocation.proceed();
if (retval != null) {
MessageChannel channel = this.resolveChannel(invocation);
if (channel == null) {
if (logger.isWarnEnabled()) {
logger.warn("unable to resolve channel for intercepted method '" +
invocation.getMethod().getName() + "'");
}
}
else {
channel.send(mapper.toMessage(retval));
}
}
return retval;
}
/**
* Subclasses may override this method to provide custom behavior.
*/
protected MessageChannel resolveChannel(MethodInvocation invocation) {
return this.defaultChannel;
}
}

View File

@@ -0,0 +1,69 @@
/*
* Copyright 2002-2007 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.aop;
import java.lang.annotation.Annotation;
import org.aopalliance.aop.Advice;
import org.springframework.aop.Pointcut;
import org.springframework.aop.support.AbstractPointcutAdvisor;
import org.springframework.aop.support.annotation.AnnotationMatchingPointcut;
import org.springframework.integration.annotation.Publisher;
import org.springframework.integration.channel.ChannelRegistry;
import org.springframework.util.Assert;
/**
* Advisor whose pointcut matches a method annotation and whose advice will
* publish a message to the channel provided by that annotation.
*
* @author Mark Fisher
* @see Publisher
* @see AnnotationAwareMessagePublishingInterceptor
*/
@SuppressWarnings("serial")
public class PublisherAnnotationAdvisor extends AbstractPointcutAdvisor {
private AnnotationAwareMessagePublishingInterceptor advice;
private AnnotationMatchingPointcut pointcut;
public PublisherAnnotationAdvisor(ChannelRegistry channelRegistry) {
this(Publisher.class, "channel", channelRegistry);
}
public PublisherAnnotationAdvisor(Class<? extends Annotation> publisherAnnotationType, String channelNameAttribute,
ChannelRegistry channelRegistry) {
Assert.notNull(publisherAnnotationType, "'publisherAnnotationType' must not be null");
Assert.notNull(channelNameAttribute, "'channelNameAttribute' must not be null");
Assert.notNull(channelRegistry, "'channelRegistry' must not be null");
this.pointcut = AnnotationMatchingPointcut.forMethodAnnotation(publisherAnnotationType);
this.advice = new AnnotationAwareMessagePublishingInterceptor(publisherAnnotationType, channelNameAttribute,
channelRegistry);
}
public Pointcut getPointcut() {
return this.pointcut;
}
public Advice getAdvice() {
return this.advice;
}
}

View File

@@ -0,0 +1,79 @@
/*
* Copyright 2002-2007 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.bus;
import java.util.Collection;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.integration.message.Message;
/**
* Abstract base class for message dispatchers. Delegates to a
* {@link MessageRetriever} strategy.
*
* @author Mark Fisher
*/
public abstract class AbstractMessageDispatcher implements MessageDispatcher {
protected Log logger = LogFactory.getLog(this.getClass());
private MessageRetriever retriever;
private List<MessageReceivingExecutor> executors = new CopyOnWriteArrayList<MessageReceivingExecutor>();
public AbstractMessageDispatcher(MessageRetriever retriever) {
this.retriever = retriever;
}
public void addExecutor(MessageReceivingExecutor executor) {
executor.start();
this.executors.add(executor);
}
protected List<MessageReceivingExecutor> getExecutors() {
return this.executors;
}
/**
* Retrieves messages and dispatches to the executors.
*
* @return the number of messages processed
*/
public int dispatch() {
int messagesProcessed = 0;
Collection<Message<?>> messages = this.retriever.retrieveMessages();
if (messages == null) {
return 0;
}
for (Message<?> message : messages) {
if (dispatchMessage(message)) {
messagesProcessed++;
}
}
return messagesProcessed;
}
protected abstract boolean dispatchMessage(Message<?> message);
}

View File

@@ -0,0 +1,63 @@
/*
* Copyright 2002-2007 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.bus;
import java.util.Collection;
import java.util.LinkedList;
import java.util.List;
import org.springframework.integration.channel.MessageChannel;
import org.springframework.integration.message.Message;
/**
* Message retriever that polls a {@link MessageChannel}. The number of
* messages retrieved per poll is limited by the '<em>maxMessagesPerTask</em>'
* property of the provided {@link ConsumerPolicy}, and the timeout for each
* receive call is determined by the policy's '<em>receiveTimeout</em>'
* property. In general, it is recommended to use a value of 1 for
* 'maxMessagesPerTask' whenever a non-zero timeout is provided. Otherwise the
* retriever may be holding on to available messages while waiting for
* additional messages.
*
* @author Mark Fisher
*/
public class ChannelPollingMessageRetriever implements MessageRetriever {
private MessageChannel channel;
private ConsumerPolicy policy;
public ChannelPollingMessageRetriever(MessageChannel channel, ConsumerPolicy policy) {
this.channel = channel;
this.policy = policy;
}
public Collection<Message<?>> retrieveMessages() {
List<Message<?>> messages = new LinkedList<Message<?>>();
while (messages.size() < this.policy.getMaxMessagesPerTask()) {
Message<?> message = this.channel.receive(this.policy.getReceiveTimeout());
if (message == null) {
return messages;
}
messages.add(message);
}
return messages;
}
}

View File

@@ -0,0 +1,170 @@
/*
* Copyright 2002-2007 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.bus;
import java.util.concurrent.TimeUnit;
import org.springframework.util.Assert;
/**
* A container for Message consumer configuration metadata.
*
* @author Mark Fisher
*/
public class ConsumerPolicy {
private static final int DEFAULT_CONCURRENCY = 1;
private static final int DEFAULT_MAX_CONCURRENCY = 10;
private static final int DEFAULT_MAX_MESSAGES_PER_TASK = 1;
private static final int DEFAULT_REJECTION_LIMIT = 10;
private static final int DEFAULT_REJECTION_LIMIT_WAIT = 1000;
private static final long DEFAULT_RECEIVE_TIMEOUT = 1000;
private int concurrency = DEFAULT_CONCURRENCY;
private int maxConcurrency = DEFAULT_MAX_CONCURRENCY;
private int maxMessagesPerTask = DEFAULT_MAX_MESSAGES_PER_TASK;
private int rejectionLimit = DEFAULT_REJECTION_LIMIT;
private int rejectionLimitWait = DEFAULT_REJECTION_LIMIT_WAIT;
private int initialDelay = 0;
private int period = 5;
private TimeUnit timeUnit = TimeUnit.MILLISECONDS;
private boolean fixedRate = false;
private long receiveTimeout = DEFAULT_RECEIVE_TIMEOUT;
/**
* Factory method for a basic polling policy.
*
* @param period the polling interval
*/
public static ConsumerPolicy newPollingPolicy(int period) {
Assert.isTrue(period > 0, "'period' must be a positive value");
ConsumerPolicy policy = new ConsumerPolicy();
policy.setPeriod(period);
policy.setConcurrency(1);
policy.setMaxConcurrency(1);
return policy;
}
public int getInitialDelay() {
return this.initialDelay;
}
public void setInitialDelay(int initialDelay) {
this.initialDelay = initialDelay;
}
public int getPeriod() {
return this.period;
}
public void setPeriod(int period) {
this.period = period;
}
public TimeUnit getTimeUnit() {
return this.timeUnit;
}
public void setTimeUnit(TimeUnit timeUnit) {
this.timeUnit = timeUnit;
}
public boolean isFixedRate() {
return this.fixedRate;
}
public void setFixedRate(boolean fixedRate) {
this.fixedRate = fixedRate;
}
public int getConcurrency() {
return this.concurrency;
}
public void setConcurrency(int concurrency) {
if (concurrency < 1) {
throw new IllegalArgumentException("'concurrency' value must be at least 1");
}
this.concurrency = concurrency;
}
public int getMaxConcurrency() {
return this.maxConcurrency;
}
public void setMaxConcurrency(int maxConcurrency) {
if (maxConcurrency < 1) {
throw new IllegalArgumentException("'maxConcurrency' value must be at least 1");
}
this.maxConcurrency = maxConcurrency;
}
public int getMaxMessagesPerTask() {
return this.maxMessagesPerTask;
}
public void setMaxMessagesPerTask(int maxMessagesPerTask) {
if (maxMessagesPerTask == 0) {
throw new IllegalArgumentException("'maxMessagesPerTask' must not be 0");
}
this.maxMessagesPerTask = maxMessagesPerTask;
}
public int getRejectionLimit() {
return this.rejectionLimit;
}
public void setRejectionLimit(int rejectionLimit) {
if (rejectionLimit < 1) {
throw new IllegalArgumentException("'idleTaskExecutionLimit' must be at least 1");
}
this.rejectionLimit = rejectionLimit;
}
public int getRejectionLimitWait() {
return this.rejectionLimitWait;
}
public void setRejectionLimitWait(int rejectionLimitWait) {
this.rejectionLimitWait = rejectionLimitWait;
}
public long getReceiveTimeout() {
return this.receiveTimeout;
}
public void setReceiveTimeout(long receiveTimeout) {
this.receiveTimeout = receiveTimeout;
}
}

View File

@@ -0,0 +1,366 @@
/*
* Copyright 2002-2007 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.bus;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.Lifecycle;
import org.springframework.integration.MessagingException;
import org.springframework.integration.adapter.AbstractTargetAdapter;
import org.springframework.integration.adapter.SourceAdapter;
import org.springframework.integration.adapter.TargetAdapter;
import org.springframework.integration.channel.ChannelRegistry;
import org.springframework.integration.channel.DefaultChannelRegistry;
import org.springframework.integration.channel.MessageChannel;
import org.springframework.integration.channel.PointToPointChannel;
import org.springframework.integration.endpoint.MessageEndpoint;
import org.springframework.integration.message.MessageReceiver;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
/**
* The messaging bus. Serves as a registry for channels and endpoints, manages their lifecycle,
* and activates subscriptions.
*
* @author Mark Fisher
*/
public class MessageBus implements ChannelRegistry, ApplicationContextAware, Lifecycle {
private Log logger = LogFactory.getLog(this.getClass());
private ChannelRegistry channelRegistry = new DefaultChannelRegistry();
private Map<String, MessageEndpoint<?>> endpoints = new ConcurrentHashMap<String, MessageEndpoint<?>>();
private Map<String, TargetAdapter<?>> targetAdapters = new ConcurrentHashMap<String, TargetAdapter<?>>();
private List<DispatcherTask> dispatcherTasks = new CopyOnWriteArrayList<DispatcherTask>();
private Map<MessageReceiver<?>, MessageReceivingExecutor> receiverExecutors = new ConcurrentHashMap<MessageReceiver<?>, MessageReceivingExecutor>();
private ScheduledThreadPoolExecutor dispatcherExecutor;
private boolean autoCreateChannels;
private boolean running;
private Object lifecycleMonitor = new Object();
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
Assert.notNull(applicationContext, "applicationContext must not be null");
this.registerChannels(applicationContext);
this.registerEndpoints(applicationContext);
this.registerSourceAdapters(applicationContext);
this.registerTargetAdapters(applicationContext);
this.activateSubscriptions(applicationContext);
}
public void setAutoCreateChannels(boolean autoCreateChannels) {
this.autoCreateChannels = autoCreateChannels;
}
@SuppressWarnings("unchecked")
private void registerChannels(ApplicationContext context) {
Map<String, MessageChannel> channelBeans =
(Map<String, MessageChannel>) context.getBeansOfType(MessageChannel.class);
for (Map.Entry<String, MessageChannel> entry : channelBeans.entrySet()) {
this.registerChannel(entry.getKey(), entry.getValue());
}
}
@SuppressWarnings("unchecked")
private void registerEndpoints(ApplicationContext context) {
Map<String, MessageEndpoint> endpointBeans =
(Map<String, MessageEndpoint>) context.getBeansOfType(MessageEndpoint.class);
for (Map.Entry<String, MessageEndpoint> entry : endpointBeans.entrySet()) {
this.registerEndpoint(entry.getKey(), entry.getValue());
}
}
@SuppressWarnings("unchecked")
private void registerSourceAdapters(ApplicationContext context) {
Map<String, SourceAdapter> sourceAdapterBeans =
(Map<String, SourceAdapter>) context.getBeansOfType(SourceAdapter.class);
for (Map.Entry<String, SourceAdapter> entry : sourceAdapterBeans.entrySet()) {
this.registerSourceAdapter(entry.getKey(), entry.getValue());
}
}
@SuppressWarnings("unchecked")
private void registerTargetAdapters(ApplicationContext context) {
Map<String, TargetAdapter> targetAdapterBeans =
(Map<String, TargetAdapter>) context.getBeansOfType(TargetAdapter.class);
for (Map.Entry<String, TargetAdapter> entry : targetAdapterBeans.entrySet()) {
this.registerTargetAdapter(entry.getKey(), entry.getValue());
}
}
@SuppressWarnings("unchecked")
private void activateSubscriptions(ApplicationContext context) {
Map<String, Subscription> subscriptionBeans =
(Map<String, Subscription>) context.getBeansOfType(Subscription.class);
for (Subscription subscription : subscriptionBeans.values()) {
this.activateSubscription(subscription);
if (logger.isInfoEnabled()) {
logger.info("activated subscription to channel '" + subscription.getChannel() +
"' for endpoint '" + subscription.getEndpoint() + "'");
}
}
}
public void initialize() {
this.dispatcherExecutor = new ScheduledThreadPoolExecutor(this.dispatcherTasks.size() > 0 ? this.dispatcherTasks.size() : 1);
}
public MessageChannel getInvalidMessageChannel() {
return this.channelRegistry.getInvalidMessageChannel();
}
public void setInvalidMessageChannel(MessageChannel invalidMessageChannel) {
this.channelRegistry.setInvalidMessageChannel(invalidMessageChannel);
}
public MessageChannel lookupChannel(String channelName) {
return this.channelRegistry.lookupChannel(channelName);
}
public void registerChannel(String name, MessageChannel channel) {
this.channelRegistry.registerChannel(name, channel);
}
public void registerEndpoint(String name, MessageEndpoint<?> endpoint) {
Assert.notNull(name, "'name' must not be null");
Assert.notNull(endpoint, "'endpoint' must not be null");
this.endpoints.put(name, endpoint);
if (logger.isInfoEnabled()) {
logger.info("registered endpoint '" + name + "'");
}
endpoint.setChannelRegistry(this);
if (endpoint.getInputChannelName() != null && endpoint.getConsumerPolicy() != null) {
Subscription subscription = new Subscription();
subscription.setChannel(endpoint.getInputChannelName());
subscription.setEndpoint(name);
subscription.setPolicy(endpoint.getConsumerPolicy());
this.activateSubscription(subscription);
}
if (this.autoCreateChannels) {
String defaultOutputChannelName = endpoint.getDefaultOutputChannelName();
if (StringUtils.hasText(defaultOutputChannelName) && this.lookupChannel(defaultOutputChannelName) == null) {
this.registerChannel(defaultOutputChannelName, new PointToPointChannel());
}
}
}
public void registerSourceAdapter(String name, SourceAdapter adapter) {
// TODO: use the name
if (adapter instanceof MessageDispatcher) {
MessageDispatcher dispatcher = (MessageDispatcher) adapter;
ConsumerPolicy policy = dispatcher.getConsumerPolicy();
DispatcherTask dispatcherTask = new DispatcherTask(dispatcher, policy);
this.addDispatcherTask(dispatcherTask);
if (logger.isInfoEnabled()) {
logger.info("registered source adapter '" + name + "'");
}
}
}
public void registerTargetAdapter(String name, TargetAdapter<?> targetAdapter) {
if (targetAdapter instanceof AbstractTargetAdapter) {
AbstractTargetAdapter<?> adapter = (AbstractTargetAdapter<?>) targetAdapter;
adapter.setName(name);
this.targetAdapters.put(name, targetAdapter);
MessageChannel channel = adapter.getChannel();
ConsumerPolicy policy = adapter.getConsumerPolicy();
MessageRetriever retriever = new ChannelPollingMessageRetriever(channel, policy);
UnicastMessageDispatcher dispatcher = new UnicastMessageDispatcher(retriever, policy);
dispatcher.addExecutor(new MessageReceivingExecutor(adapter, policy.getConcurrency(), policy.getMaxConcurrency()));
this.addDispatcherTask(new DispatcherTask(dispatcher, policy));
if (logger.isInfoEnabled()) {
logger.info("registered target adapter '" + name + "'");
}
}
}
public void activateSubscription(Subscription subscription) {
String channelName = subscription.getChannel();
String endpointName = subscription.getEndpoint();
ConsumerPolicy policy = subscription.getPolicy();
MessageChannel channel = this.lookupChannel(channelName);
if (channel == null) {
if (this.autoCreateChannels == false) {
throw new MessagingException("Cannot activate subscription, unknown channel '" + channelName +
"'. Consider enabling the 'autoCreateChannels' option for the message bus.");
}
if (this.logger.isInfoEnabled()) {
logger.info("auto-creating channel '" + channelName + "'");
}
channel = new PointToPointChannel();
this.registerChannel(channelName, channel);
}
MessageEndpoint<?> endpoint = this.endpoints.get(endpointName);
if (endpoint == null) {
throw new MessagingException("Cannot activate subscription, unknown endpoint '" + endpointName + "'");
}
if (logger.isInfoEnabled()) {
logger.info("activated subscription to channel '" + channelName +
"' for endpoint '" + endpointName + "'");
}
MessageReceivingExecutor executor = new MessageReceivingExecutor(endpoint, policy.getConcurrency(), policy.getMaxConcurrency());
receiverExecutors.put(endpoint, executor);
MessageRetriever retriever = new ChannelPollingMessageRetriever(channel, policy);
UnicastMessageDispatcher dispatcher = new UnicastMessageDispatcher(retriever, policy);
dispatcher.addExecutor(executor);
DispatcherTask dispatcherTask = new DispatcherTask(dispatcher, policy);
if (this.isRunning()) {
executor.start();
}
this.addDispatcherTask(dispatcherTask);
if (this.logger.isInfoEnabled()) {
logger.info("registered dispatcher task: channel='" +
channelName + "' receiver='" + endpointName + "'");
}
}
private void addDispatcherTask(DispatcherTask dispatcherTask) {
this.dispatcherTasks.add(dispatcherTask);
if (this.isRunning()) {
scheduleDispatcherTask(dispatcherTask);
if (this.logger.isInfoEnabled()) {
logger.info("scheduled dispatcher task");
}
}
}
public int getActiveCountForReceiver(String receiverName) {
MessageReceiver<?> receiver = this.endpoints.get(receiverName);
if (receiver == null) {
receiver = this.targetAdapters.get(receiverName);
}
if (receiver != null) {
MessageReceivingExecutor executor = this.receiverExecutors.get(receiver);
if (executor != null) {
return executor.getActiveCount();
}
}
return 0;
}
private void scheduleDispatcherTask(DispatcherTask task) {
ConsumerPolicy policy = task.getPolicy();
if (policy.getPeriod() <= 0) {
if (policy.getReceiveTimeout() <= 0) {
if (logger.isWarnEnabled()) {
logger.warn("Scheduling a repeating task with no receive timeout is not recommended! " +
"Consider providing a positive value for either 'period' or 'receiveTimeout'");
}
}
dispatcherExecutor.schedule(new RepeatingDispatcherTask(task), policy.getInitialDelay(), policy.getTimeUnit());
}
else if (policy.isFixedRate()) {
dispatcherExecutor.scheduleAtFixedRate(task, policy.getInitialDelay(), policy.getPeriod(), policy.getTimeUnit());
}
else {
dispatcherExecutor.scheduleWithFixedDelay(task, policy.getInitialDelay(), policy.getPeriod(), policy.getTimeUnit());
}
}
public boolean isRunning() {
synchronized (this.lifecycleMonitor) {
return this.running;
}
}
public void start() {
if (this.dispatcherExecutor == null) {
this.initialize();
}
synchronized (this.lifecycleMonitor) {
if (!this.isRunning()) {
this.running = true;
for (MessageReceivingExecutor executor : receiverExecutors.values()) {
executor.start();
}
for (DispatcherTask task : this.dispatcherTasks) {
scheduleDispatcherTask(task);
}
}
}
}
public void stop() {
synchronized (this.lifecycleMonitor) {
if (this.isRunning()) {
this.running = false;
for (MessageReceivingExecutor executor : receiverExecutors.values()) {
executor.stop();
}
this.dispatcherExecutor.shutdownNow();
}
}
}
private static class DispatcherTask implements Runnable {
private MessageDispatcher dispatcher;
private ConsumerPolicy policy;
public DispatcherTask(MessageDispatcher dispatcher, ConsumerPolicy policy) {
this.dispatcher = dispatcher;
this.policy = policy;
}
public ConsumerPolicy getPolicy() {
return this.policy;
}
public void run() {
dispatcher.dispatch();
}
}
private class RepeatingDispatcherTask implements Runnable {
private DispatcherTask task;
RepeatingDispatcherTask(DispatcherTask task) {
this.task = task;
}
public void run() {
task.run();
dispatcherExecutor.execute(new RepeatingDispatcherTask(task));
}
}
}

View File

@@ -0,0 +1,30 @@
/*
* Copyright 2002-2007 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.bus;
/**
* Strategy interface for dispatching messages.
*
* @author Mark Fisher
*/
public interface MessageDispatcher {
ConsumerPolicy getConsumerPolicy();
int dispatch();
}

View File

@@ -0,0 +1,201 @@
/*
* Copyright 2002-2007 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.bus;
import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.context.Lifecycle;
import org.springframework.integration.MessageHandlingException;
import org.springframework.integration.message.Message;
import org.springframework.integration.message.MessageReceiver;
import org.springframework.scheduling.concurrent.CustomizableThreadFactory;
import org.springframework.util.Assert;
/**
* Encapsulates a {@link ThreadPoolExecutor} with configurable error thresholds.
*
* @author Mark Fisher
*/
public class MessageReceivingExecutor implements Lifecycle {
private Log logger = LogFactory.getLog(this.getClass());
private MessageReceiver receiver;
private ThreadPoolExecutor threadPoolExecutor;
private int corePoolSize;
private int maxPoolSize;
private volatile boolean running;
private Object lifecycleMonitor = new Object();
private int successiveErrorCount;
private int successiveErrorThreshold = -1;
private int totalErrorCount;
private int totalErrorThreshold = -1;
public MessageReceivingExecutor(MessageReceiver receiver, int corePoolSize, int maxPoolSize) {
Assert.notNull(receiver, "'receiver' must not be null");
Assert.isTrue(corePoolSize > 0, "'corePoolSize' must be at least 1");
Assert.isTrue(maxPoolSize > 0, "'maxPoolSize' must be at least 1");
Assert.isTrue(maxPoolSize >= corePoolSize, "'corePoolSize' cannot exceed 'maxPoolSize'");
this.receiver = receiver;
this.corePoolSize = corePoolSize;
this.maxPoolSize = maxPoolSize;
}
public void setCorePoolSize(int corePoolSize) {
this.corePoolSize = corePoolSize;
}
public void setMaxPoolSize(int maxPoolSize) {
this.maxPoolSize = maxPoolSize;
}
public boolean isRunning() {
return this.running;
}
public void start() {
synchronized (this.lifecycleMonitor) {
if (!this.running) {
this.threadPoolExecutor = new MessageReceivingThreadPoolExecutor(this.corePoolSize, this.maxPoolSize);
}
this.running = true;
}
}
public void stop() {
synchronized (this.lifecycleMonitor) {
if (this.isRunning()) {
this.threadPoolExecutor.shutdown();
this.threadPoolExecutor = null;
}
this.running = false;
}
}
public void processMessage(Message<?> message) {
if (threadPoolExecutor == null) {
throw new MessageHandlingException("executor is not running");
}
this.threadPoolExecutor.execute(new MessageReceivingTask(this.receiver, message));
}
/**
* Set the maximum number of errors allowed in <em>successive</em>
* executions. If this threshold is ever exceeded, the executor
* will shutdown.
*/
public void setSuccessiveErrorThreshold(int successiveErrorThreshold) {
this.successiveErrorThreshold = successiveErrorThreshold;
}
/**
* Set the maximum number of <em>total</em> errors allowed in executions
* If this threshold is ever exceeded, the executor will shutdown.
*/
public void setTotalErrorThreshold(int totalErrorThreshold) {
this.totalErrorThreshold = totalErrorThreshold;
}
public int getActiveCount() {
if (this.threadPoolExecutor == null) {
return 0;
}
return this.threadPoolExecutor.getActiveCount();
}
public boolean isShutdown() {
return this.threadPoolExecutor.isShutdown();
}
private static class MessageReceivingTask implements Runnable {
private MessageReceiver receiver;
private Message<?> message;
private Throwable error;
MessageReceivingTask(MessageReceiver receiver, Message<?> message) {
this.receiver = receiver;
this.message = message;
}
public Throwable getError() {
return this.error;
}
public void run() {
try {
this.receiver.messageReceived(this.message);
}
catch (Throwable t) {
this.error = t;
}
}
}
private class MessageReceivingThreadPoolExecutor extends ThreadPoolExecutor {
public MessageReceivingThreadPoolExecutor(int corePoolSize, int maximumPoolSize) {
super(corePoolSize, maximumPoolSize, 0, TimeUnit.MILLISECONDS, new SynchronousQueue<Runnable>());
CustomizableThreadFactory threadFactory = new CustomizableThreadFactory();
threadFactory.setThreadNamePrefix("endpoint-executor-");
this.setThreadFactory(threadFactory);
}
@Override
protected void afterExecute(Runnable r, Throwable t) {
MessageReceivingTask task = (MessageReceivingTask) r;
if (task.getError() != null) {
if (logger.isWarnEnabled()) {
logger.warn("Exception occurred during task execution", task.getError());
}
successiveErrorCount++;
totalErrorCount++;
if ((successiveErrorThreshold >= 0 && successiveErrorCount > successiveErrorThreshold)
|| (totalErrorThreshold >= 0 && totalErrorCount > totalErrorThreshold)) {
if (logger.isInfoEnabled()) {
logger.info("error threshold exceeded, shutting down now");
}
this.shutdownNow();
}
}
else {
successiveErrorCount = 0;
}
}
}
}

View File

@@ -0,0 +1,32 @@
/*
* Copyright 2002-2007 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.bus;
import java.util.Collection;
import org.springframework.integration.message.Message;
/**
* Strategy interface for retrieving messages.
*
* @author Mark Fisher
*/
public interface MessageRetriever {
Collection<Message<?>> retrieveMessages();
}

View File

@@ -0,0 +1,57 @@
/*
* Copyright 2002-2007 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.bus;
/**
* Configuration metadata for activating a subscription.
*
* @author Mark Fisher
*/
public class Subscription {
private String channel;
private String endpoint;
private ConsumerPolicy policy = new ConsumerPolicy();
public String getChannel() {
return this.channel;
}
public void setChannel(String channel) {
this.channel = channel;
}
public String getEndpoint() {
return this.endpoint;
}
public void setEndpoint(String endpoint) {
this.endpoint = endpoint;
}
public ConsumerPolicy getPolicy() {
return this.policy;
}
public void setPolicy(ConsumerPolicy policy) {
this.policy = policy;
}
}

View File

@@ -0,0 +1,92 @@
/*
* Copyright 2002-2007 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.bus;
import java.util.Iterator;
import java.util.concurrent.RejectedExecutionException;
import org.springframework.integration.message.Message;
/**
* A {@link MessageDispatcher} implementation that dispatches each retrieved
* {@link Message} to a single {@link MessageReceivingExecutor}.
*
* @author Mark Fisher
*/
public class UnicastMessageDispatcher extends AbstractMessageDispatcher {
private ConsumerPolicy policy;
public UnicastMessageDispatcher(MessageRetriever retriever, ConsumerPolicy policy) {
super(retriever);
this.policy = policy;
}
public ConsumerPolicy getConsumerPolicy() {
return this.policy;
}
@Override
protected boolean dispatchMessage(Message<?> message) {
int attempts = 0;
Iterator<MessageReceivingExecutor> iter = this.getExecutors().iterator();
if (!iter.hasNext()) {
if (logger.isWarnEnabled()) {
logger.warn("dispatcher has no active executors");
}
return false;
}
while (iter.hasNext()) {
MessageReceivingExecutor executor = iter.next();
try {
if (executor == null || !executor.isRunning()) {
if (logger.isInfoEnabled()) {
logger.info("removing inactive executor");
}
iter.remove();
continue;
}
executor.processMessage(message);
return true;
}
catch (RejectedExecutionException rex) {
attempts++;
if (attempts == policy.getRejectionLimit()) {
attempts = 0;
if (logger.isDebugEnabled()) {
logger.debug("reached rejected execution limit");
}
try {
Thread.sleep(policy.getRejectionLimitWait());
}
catch (InterruptedException iex) {
Thread.currentThread().interrupt();
}
}
}
catch (Exception e) {
if (logger.isWarnEnabled()) {
logger.warn("error occurred during dispatch", e);
}
}
}
return false;
}
}

View File

@@ -0,0 +1,34 @@
/*
* Copyright 2002-2007 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.channel;
/**
* A strategy interface for registration and lookup of message channels by name.
*
* @author Mark Fisher
*/
public interface ChannelRegistry {
void registerChannel(String name, MessageChannel channel);
MessageChannel lookupChannel(String channelName);
void setInvalidMessageChannel(MessageChannel invalidMessageChannel);
MessageChannel getInvalidMessageChannel();
}

View File

@@ -0,0 +1,29 @@
/*
* Copyright 2002-2007 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.channel;
/**
* Interface to be implemented by components that need access to the
* {@link ChannelRegistry}.
*
* @author Mark Fisher
*/
public interface ChannelRegistryAware {
void setChannelRegistry(ChannelRegistry channelRegistry);
}

View File

@@ -0,0 +1,34 @@
/*
* Copyright 2002-2007 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.channel;
/**
* Enumeration of the different types of message consumer.
*
* @author Mark Fisher
*/
public enum ConsumerType {
EVENT_DRIVEN,
FIXED_RATE,
FIXED_DELAY,
SCHEDULED
}

View File

@@ -0,0 +1,63 @@
/*
* Copyright 2002-2007 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.channel;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.util.Assert;
/**
* A simple map-backed implementation of {@link ChannelRegistry}.
*
* @author Mark Fisher
*/
public class DefaultChannelRegistry implements ChannelRegistry {
private Log logger = LogFactory.getLog(this.getClass());
private Map<String, MessageChannel> channels = new ConcurrentHashMap<String, MessageChannel>();
private MessageChannel invalidMessageChannel;
public void setInvalidMessageChannel(MessageChannel invalidMessageChannel) {
this.invalidMessageChannel = invalidMessageChannel;
}
public MessageChannel getInvalidMessageChannel() {
return this.invalidMessageChannel;
}
public MessageChannel lookupChannel(String channelName) {
return this.channels.get(channelName);
}
public void registerChannel(String name, MessageChannel channel) {
Assert.notNull(name, "'name' must not be null");
Assert.notNull(channel, "'channel' must not be null");
channel.setName(name);
this.channels.put(name, channel);
if (logger.isInfoEnabled()) {
logger.info("registered channel '" + name + "'");
}
}
}

View File

@@ -0,0 +1,80 @@
/*
* Copyright 2002-2007 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.channel;
import org.springframework.integration.message.Message;
/**
* Base channel interface defining common behavior for message sending and receiving.
*
* @author Mark Fisher
*/
public interface MessageChannel {
/**
* Set the name of this channel. Must be unique within a context.
*/
void setName(String name);
/**
* Return the name of this channel.
*/
String getName();
/**
* Send a message, blocking indefinitely if necessary.
*
* @param message the {@link Message} to send
*
* @return <code>true</code> if the message is sent successfully,
* <code>false</false> if interrupted
*/
boolean send(Message message);
/**
* Send a message, blocking until either the message is accepted or the
* specified timeout period elapses.
*
* @param message the {@link Message} to send
* @param timeout the timeout in milliseconds
*
* @return <code>true</code> if the message is sent successfully,
* <code>false</false> if the specified timeout period elapses or
* the send is interrupted
*/
boolean send(Message message, long timeout);
/**
* Receive a message, blocking indefinitely if necessary.
*
* @return the next available {@link Message} or <code>null</code> if
* interrupted
*/
Message receive();
/**
* Receive a message, blocking until either a message is available or the
* specified timeout period elapses.
*
* @param timeout the timeout in milliseconds
*
* @return the next available {@link Message} or <code>null</code> if the
* specified timeout period elapses or the message reception is interrupted
*/
Message receive(long timeout);
}

View File

@@ -0,0 +1,213 @@
/*
* Copyright 2002-2007 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.channel;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.integration.message.Message;
import org.springframework.integration.message.MessageSelector;
/**
* Simple implementation of a point-to-point message channel. Each Messages is
* placed in a queue whose capacity may be specified upon construction. If no
* capacity is specified, the {@link #DEFAULT_CAPACITY} will be used.
*
* @author Mark Fisher
*/
public class PointToPointChannel implements MessageChannel, BeanNameAware {
private static final int DEFAULT_CAPACITY = 25;
private String name;
private BlockingQueue<Message<?>> queue;
/**
* Create a channel with the specified queue capacity.
*/
public PointToPointChannel(int capacity) {
queue = new LinkedBlockingQueue<Message<?>>(capacity);
}
/**
* Create a channel with the default queue capacity.
*/
public PointToPointChannel() {
this(DEFAULT_CAPACITY);
}
/**
* Set the name of this channel.
*/
public void setName(String name) {
this.name = name;
}
/**
* Return the name of this channel.
*/
public String getName() {
return this.name;
}
/**
* Set the name of this channel to its bean name. This will be invoked
* automatically whenever the channel is configured explicitly with a bean
* definition.
*/
public void setBeanName(String beanName) {
this.setName(beanName);
}
/**
* Send a message on this channel. If the queue is full, this method will
* block until either space becomes available or the sending thread is
* interrupted.
*
* @param message the Message to send
*
* @return <code>true</code> if the message is sent successfully or
* <code>false</code> if the sending thread is interrupted.
*/
public boolean send(Message message) {
try {
queue.put(message);
return true;
}
catch (InterruptedException e) {
Thread.currentThread().interrupt();
return false;
}
}
/**
* Send a message on this channel. If the queue is full, this method will
* block until either the timeout occurs or the sending thread is
* interrupted. If the specified timeout is less than 1, the method will
* return immediately.
*
* @param message the Message to send
* @param timeout the timeout in milliseconds
*
* @return <code>true</code> if the message is sent successfully,
* <code>false</code> if the message cannot be sent within the allotted
* time or the sending thread is interrupted.
*/
public boolean send(Message message, long timeout) {
try {
if (timeout > 0) {
return this.queue.offer(message, timeout, TimeUnit.MILLISECONDS);
}
return this.queue.offer(message);
}
catch (InterruptedException e) {
Thread.currentThread().interrupt();
return false;
}
}
/**
* Receive the message at the head of the queue. If the queue is empty, this
* method will block.
*
* @return the Message at the head of the queue or <code>null</code> if
* the receiving thread is interrupted.
*/
public Message receive() {
try {
return queue.take();
}
catch (InterruptedException e) {
Thread.currentThread().interrupt();
return null;
}
}
/**
* Receive the message at the head of the queue. If the queue is empty, this
* method will block until the allotted timeout elapses. If the specified
* timeout is less than 1, the method will return immediately.
*
* @param timeout the timeout in milliseconds
*
* @return the message at the head of the queue or <code>null</code> in
* case no message is available within the allotted time or the receiving
* thread is interrupted.
*/
public Message receive(long timeout) {
try {
if (timeout > 0) {
return queue.poll(timeout, TimeUnit.MILLISECONDS);
}
return queue.poll();
}
catch (InterruptedException e) {
Thread.currentThread().interrupt();
return null;
}
}
/**
* Receive the first message that is accepted by the specified selector
* starting from the head of the queue. If the queue is empty, this method
* will block until the allotted timeout elapses. If the specified timeout
* is less than 1, the method will return immediately.
*
* @param selector the selector to use
* @param timeout the timeout in milliseconds
*
* @return the first accepted message or <code>null</code> in case the
* selector does not accept any message within the allotted time or the
* receiving thread is interrupted.
*/
public Message receive(MessageSelector selector, long timeout) {
long start = System.currentTimeMillis();
while (timeout <= 0 || System.currentTimeMillis() - start < timeout) {
Object[] elements = this.queue.toArray();
for (int i = (elements.length - 1); i >= 0; i--) {
Message<?> m = (Message<?>) elements[i];
if (selector.accept(m) && this.queue.remove(m)) {
return m;
}
}
if (timeout == 0) {
return null;
}
}
return null;
}
/**
* Receive the first message that is accepted by the specified selector
* starting from the head of the queue. If the queue is empty, this method
* will block.
*
* @param selector the selector to use
*
* @return the first accepted message or <code>null</code> in case the
* selector does not accept any message or the receiving thread is
* interrupted.
*/
public Message receive(MessageSelector selector) {
return this.receive(selector, -1);
}
}

View File

@@ -0,0 +1,80 @@
/*
* Copyright 2002-2007 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.config;
import org.w3c.dom.Element;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.RuntimeBeanReference;
import org.springframework.beans.factory.parsing.BeanComponentDefinition;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.beans.factory.xml.BeanDefinitionParser;
import org.springframework.beans.factory.xml.ParserContext;
/**
* Parser for the <em>annotation-driven</em> element of the integration
* namespace. Registers the annotation-driven post-processors.
*
* @author Mark Fisher
*/
public class AnnotationDrivenParser implements BeanDefinitionParser {
private static final String PUBLISHER_ANNOTATION_POST_PROCESSOR_BEAN_NAME =
"internal.PublisherAnnotationPostProcessor";
private static final String SUBSCRIBER_ANNOTATION_POST_PROCESSOR_BEAN_NAME =
"internal.SubscriberAnnotationPostProcessor";
private static final String MESSAGE_ENDPOINT_ANNOTATION_POST_PROCESSOR_BEAN_NAME =
"internal.MessageEndpointAnnotationPostProcessor";
public BeanDefinition parse(Element element, ParserContext parserContext) {
this.createPublisherPostProcessor(parserContext);
this.createSubscriberPostProcessor(parserContext);
this.createMessageEndpointPostProcessor(parserContext);
return null;
}
private void createPublisherPostProcessor(ParserContext parserContext) {
BeanDefinition bd = new RootBeanDefinition(PublisherAnnotationPostProcessor.class);
bd.getPropertyValues().addPropertyValue("channelRegistry",
new RuntimeBeanReference(MessageBusParser.MESSAGE_BUS_BEAN_NAME));
BeanComponentDefinition bcd = new BeanComponentDefinition(
bd, PUBLISHER_ANNOTATION_POST_PROCESSOR_BEAN_NAME);
parserContext.registerBeanComponent(bcd);
}
private void createSubscriberPostProcessor(ParserContext parserContext) {
BeanDefinition bd = new RootBeanDefinition(SubscriberAnnotationPostProcessor.class);
bd.getPropertyValues().addPropertyValue("messageBus",
new RuntimeBeanReference(MessageBusParser.MESSAGE_BUS_BEAN_NAME));
BeanComponentDefinition bcd = new BeanComponentDefinition(
bd, SUBSCRIBER_ANNOTATION_POST_PROCESSOR_BEAN_NAME);
parserContext.registerBeanComponent(bcd);
}
private void createMessageEndpointPostProcessor(ParserContext parserContext) {
BeanDefinition bd = new RootBeanDefinition(MessageEndpointAnnotationPostProcessor.class);
bd.getPropertyValues().addPropertyValue("messageBus",
new RuntimeBeanReference(MessageBusParser.MESSAGE_BUS_BEAN_NAME));
BeanComponentDefinition bcd = new BeanComponentDefinition(
bd, MESSAGE_ENDPOINT_ANNOTATION_POST_PROCESSOR_BEAN_NAME);
parserContext.registerBeanComponent(bcd);
}
}

View File

@@ -0,0 +1,102 @@
/*
* Copyright 2002-2007 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.config;
import org.w3c.dom.Element;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.RuntimeBeanReference;
import org.springframework.beans.factory.parsing.BeanComponentDefinition;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.beans.factory.xml.BeanDefinitionParser;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.integration.MessagingConfigurationException;
import org.springframework.integration.adapter.DefaultTargetAdapter;
import org.springframework.integration.adapter.MethodInvokingSource;
import org.springframework.integration.adapter.MethodInvokingTarget;
import org.springframework.integration.adapter.PollingSourceAdapter;
import org.springframework.util.StringUtils;
/**
* Parser for inbound and outbound channel adapters.
*
* @author Mark Fisher
*/
public class ChannelAdapterParser implements BeanDefinitionParser {
private static final String ID_ATTRIBUTE = "id";
private static final String REF_ATTRIBUTE = "ref";
private static final String METHOD_ATTRIBUTE = "method";
private static final String CHANNEL_ATTRIBUTE = "channel";
private static final String PERIOD_ATTRIBUTE = "period";
private final boolean isInbound;
public ChannelAdapterParser(boolean isInbound) {
this.isInbound = isInbound;
}
public BeanDefinition parse(Element element, ParserContext parserContext) {
String ref = element.getAttribute(REF_ATTRIBUTE);
String method = element.getAttribute(METHOD_ATTRIBUTE);
String channel = element.getAttribute(CHANNEL_ATTRIBUTE);
if (!StringUtils.hasText(ref)) {
throw new MessagingConfigurationException("'ref' is required");
}
if (!StringUtils.hasText(method)) {
throw new MessagingConfigurationException("'method' is required");
}
if (!StringUtils.hasText(channel)) {
throw new MessagingConfigurationException("'channel' is required");
}
RootBeanDefinition adapterDef = null;
RootBeanDefinition invokerDef = null;
if (this.isInbound) {
adapterDef = new RootBeanDefinition(PollingSourceAdapter.class);
invokerDef = new RootBeanDefinition(MethodInvokingSource.class);
String period = element.getAttribute(PERIOD_ATTRIBUTE);
if (StringUtils.hasText(period)) {
adapterDef.getPropertyValues().addPropertyValue("period", period);
}
}
else {
adapterDef = new RootBeanDefinition(DefaultTargetAdapter.class);
invokerDef = new RootBeanDefinition(MethodInvokingTarget.class);
}
invokerDef.getPropertyValues().addPropertyValue("object", new RuntimeBeanReference(ref));
invokerDef.getPropertyValues().addPropertyValue("method", method);
String invokerBeanName = parserContext.getReaderContext().generateBeanName(invokerDef);
parserContext.registerBeanComponent(new BeanComponentDefinition(invokerDef, invokerBeanName));
adapterDef.getConstructorArgumentValues().addGenericArgumentValue(new RuntimeBeanReference(invokerBeanName));
adapterDef.getPropertyValues().addPropertyValue("channel", new RuntimeBeanReference(channel));
adapterDef.setSource(parserContext.extractSource(element));
String beanName = element.getAttribute(ID_ATTRIBUTE);
if (!StringUtils.hasText(beanName)) {
beanName = parserContext.getReaderContext().generateBeanName(adapterDef);
}
parserContext.registerBeanComponent(new BeanComponentDefinition(adapterDef, beanName));
return adapterDef;
}
}

View File

@@ -0,0 +1,56 @@
/*
* Copyright 2002-2007 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.config;
import org.w3c.dom.Element;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.parsing.BeanComponentDefinition;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.beans.factory.xml.BeanDefinitionParser;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.integration.channel.PointToPointChannel;
import org.springframework.util.StringUtils;
/**
* Parser for the <em>channel</em> element of the integration namespace.
*
* @author Mark Fisher
*/
public class ChannelParser implements BeanDefinitionParser {
private static final String ID_ATTRIBUTE = "id";
private static final String CAPACITY_ATTRIBUTE = "capacity";
public BeanDefinition parse(Element element, ParserContext parserContext) {
RootBeanDefinition channelDef = new RootBeanDefinition(PointToPointChannel.class);
channelDef.setSource(parserContext.extractSource(element));
String capacity = element.getAttribute(CAPACITY_ATTRIBUTE);
if (StringUtils.hasText(capacity)) {
channelDef.getConstructorArgumentValues().addGenericArgumentValue(Integer.parseInt(capacity));
}
String beanName = element.getAttribute(ID_ATTRIBUTE);
if (!StringUtils.hasText(beanName)) {
beanName = parserContext.getReaderContext().generateBeanName(channelDef);
}
parserContext.registerBeanComponent(new BeanComponentDefinition(channelDef, beanName));
return channelDef;
}
}

View File

@@ -0,0 +1,173 @@
/*
* Copyright 2002-2007 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.config;
import java.util.ArrayList;
import java.util.List;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.RuntimeBeanReference;
import org.springframework.beans.factory.parsing.BeanComponentDefinition;
import org.springframework.beans.factory.support.ManagedList;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.beans.factory.xml.BeanDefinitionParser;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.integration.MessagingConfigurationException;
import org.springframework.integration.bus.ConsumerPolicy;
import org.springframework.integration.endpoint.GenericMessageEndpoint;
import org.springframework.integration.handler.DefaultMessageHandlerAdapter;
import org.springframework.integration.handler.MessageHandlerChain;
import org.springframework.util.StringUtils;
/**
* Parser for the <em>endpoint</em> element of the integration namespace.
*
* @author Mark Fisher
*/
public class EndpointParser implements BeanDefinitionParser {
private static final String ID_ATTRIBUTE = "id";
private static final String INPUT_CHANNEL_ATTRIBUTE = "input-channel";
private static final String INPUT_CHANNEL_PROPERTY = "inputChannelName";
private static final String DEFAULT_OUTPUT_CHANNEL_ATTRIBUTE = "default-output-channel";
private static final String DEFAULT_OUTPUT_CHANNEL_PROPERTY = "defaultOutputChannelName";
private static final String HANDLER_ELEMENT = "handler";
private static final String REF_ATTRIBUTE = "ref";
private static final String METHOD_ATTRIBUTE = "method";
private static final String HANDLERS_PROPERTY = "handlers";
private static final String HANDLER_REF_ATTRIBUTE = "handler-ref";
private static final String HANDLER_METHOD_ATTRIBUTE = "handler-method";
private static final String HANDLER_PROPERTY = "handler";
private static final String OBJECT_PROPERTY = "object";
private static final String METHOD_NAME_PROPERTY = "methodName";
private static final String PERIOD_ATTRIBUTE = "period";
private static final String PERIOD_PROPERTY = "period";
private static final String CONSUMER_ELEMENT = "consumer";
private static final String CONSUMER_POLICY_PROPERTY = "consumerPolicy";
public BeanDefinition parse(Element element, ParserContext parserContext) {
RootBeanDefinition endpointDef = new RootBeanDefinition(GenericMessageEndpoint.class);
endpointDef.setSource(parserContext.extractSource(element));
String inputChannel = element.getAttribute(INPUT_CHANNEL_ATTRIBUTE);
if (StringUtils.hasText(inputChannel)) {
endpointDef.getPropertyValues().addPropertyValue(INPUT_CHANNEL_PROPERTY, inputChannel);
}
String defaultOutputChannel = element.getAttribute(DEFAULT_OUTPUT_CHANNEL_ATTRIBUTE);
if (StringUtils.hasText(defaultOutputChannel)) {
endpointDef.getPropertyValues().addPropertyValue(DEFAULT_OUTPUT_CHANNEL_PROPERTY, defaultOutputChannel);
}
List<String> childHandlerRefs = new ArrayList<String>();
NodeList childNodes = element.getChildNodes();
for (int i = 0; i < childNodes.getLength(); i++) {
Node child = childNodes.item(i);
if (child.getNodeType() == Node.ELEMENT_NODE) {
String localName = child.getLocalName();
if (CONSUMER_ELEMENT.equals(localName)) {
String consumerBeanName = parseConsumer((Element) child, parserContext);
endpointDef.getPropertyValues().addPropertyValue(
CONSUMER_POLICY_PROPERTY, new RuntimeBeanReference(consumerBeanName));
}
else if (HANDLER_ELEMENT.equals(localName)) {
String ref = ((Element) child).getAttribute(REF_ATTRIBUTE);
String method = ((Element) child).getAttribute(METHOD_ATTRIBUTE);
childHandlerRefs.add(this.parseHandlerAdapter(ref, method, parserContext));
}
}
}
if (childHandlerRefs.size() > 0) {
if (childHandlerRefs.size() == 1) {
endpointDef.getPropertyValues().addPropertyValue(
HANDLER_PROPERTY, new RuntimeBeanReference(childHandlerRefs.get(0)));
}
else {
RootBeanDefinition handlerChainDef = new RootBeanDefinition(MessageHandlerChain.class);
List handlerList = new ManagedList();
for (String ref : childHandlerRefs) {
handlerList.add(new RuntimeBeanReference(ref));
}
handlerChainDef.getPropertyValues().addPropertyValue(HANDLERS_PROPERTY, handlerList);
String chainBeanName = parserContext.getReaderContext().generateBeanName(handlerChainDef);
parserContext.registerBeanComponent(new BeanComponentDefinition(handlerChainDef, chainBeanName));
endpointDef.getPropertyValues().addPropertyValue(HANDLER_PROPERTY, new RuntimeBeanReference(chainBeanName));
}
}
String handlerRef = element.getAttribute(HANDLER_REF_ATTRIBUTE);
if (StringUtils.hasText(handlerRef)) {
if (childHandlerRefs.size() > 0) {
throw new MessagingConfigurationException(
"The 'handler-ref' attribute is only supported when no 'handler' child elements are present");
}
String handlerMethod = element.getAttribute(HANDLER_METHOD_ATTRIBUTE);
if (StringUtils.hasText(handlerMethod)) {
String adapterBeanName = this.parseHandlerAdapter(handlerRef, handlerMethod, parserContext);
endpointDef.getPropertyValues().addPropertyValue(HANDLER_PROPERTY, new RuntimeBeanReference(adapterBeanName));
}
else {
endpointDef.getPropertyValues().addPropertyValue(HANDLER_PROPERTY, new RuntimeBeanReference(handlerRef));
}
}
String beanName = element.getAttribute(ID_ATTRIBUTE);
if (!StringUtils.hasText(beanName)) {
beanName = parserContext.getReaderContext().generateBeanName(endpointDef);
}
parserContext.registerBeanComponent(new BeanComponentDefinition(endpointDef, beanName));
return endpointDef;
}
private String parseConsumer(Element element, ParserContext parserContext) {
RootBeanDefinition consumerDef = new RootBeanDefinition(ConsumerPolicy.class);
String period = element.getAttribute(PERIOD_ATTRIBUTE);
if (StringUtils.hasText(period)) {
consumerDef.getPropertyValues().addPropertyValue(PERIOD_PROPERTY, Integer.parseInt(period));
}
String beanName = parserContext.getReaderContext().generateBeanName(consumerDef);
parserContext.registerBeanComponent(new BeanComponentDefinition(consumerDef, beanName));
return beanName;
}
private String parseHandlerAdapter(String handlerRef, String handlerMethod, ParserContext parserContext) {
BeanDefinition handlerAdapterDef = new RootBeanDefinition(DefaultMessageHandlerAdapter.class);
handlerAdapterDef.getPropertyValues().addPropertyValue(OBJECT_PROPERTY, new RuntimeBeanReference(handlerRef));
handlerAdapterDef.getPropertyValues().addPropertyValue(METHOD_NAME_PROPERTY, handlerMethod);
String adapterBeanName = parserContext.getReaderContext().generateBeanName(handlerAdapterDef);
parserContext.registerBeanComponent(new BeanComponentDefinition(handlerAdapterDef, adapterBeanName));
return adapterBeanName;
}
}

View File

@@ -0,0 +1,43 @@
/*
* Copyright 2002-2007 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.config;
import org.springframework.beans.factory.xml.NamespaceHandlerSupport;
import org.springframework.integration.adapter.file.config.FileSourceAdapterParser;
import org.springframework.integration.adapter.file.config.FileTargetAdapterParser;
import org.springframework.integration.adapter.jms.config.JmsTargetAdapterParser;
/**
* Namespace handler for the integration namespace.
*
* @author Mark Fisher
*/
public class IntegrationNamespaceHandler extends NamespaceHandlerSupport {
public void init() {
registerBeanDefinitionParser("message-bus", new MessageBusParser());
registerBeanDefinitionParser("annotation-driven", new AnnotationDrivenParser());
registerBeanDefinitionParser("channel", new ChannelParser());
registerBeanDefinitionParser("source-adapter", new ChannelAdapterParser(true));
registerBeanDefinitionParser("target-adapter", new ChannelAdapterParser(false));
registerBeanDefinitionParser("endpoint", new EndpointParser());
registerBeanDefinitionParser("file-source", new FileSourceAdapterParser());
registerBeanDefinitionParser("file-target", new FileTargetAdapterParser());
registerBeanDefinitionParser("jms-target", new JmsTargetAdapterParser());
}
}

View File

@@ -0,0 +1,47 @@
/*
* Copyright 2002-2007 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.config;
import org.w3c.dom.Element;
import org.springframework.beans.factory.BeanDefinitionStoreException;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.xml.AbstractSimpleBeanDefinitionParser;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.integration.bus.MessageBus;
/**
* Parser for the <em>message-bus</em> element of the integration namespace.
*
* @author Mark Fisher
*/
public class MessageBusParser extends AbstractSimpleBeanDefinitionParser {
public static final String MESSAGE_BUS_BEAN_NAME = "org.springframework.integration.bus.internalMessageBus";
@Override
protected String resolveId(Element element, AbstractBeanDefinition definition, ParserContext parserContext)
throws BeanDefinitionStoreException {
return MESSAGE_BUS_BEAN_NAME;
}
@Override
protected Class<?> getBeanClass(Element element) {
return MessageBus.class;
}
}

View File

@@ -0,0 +1,241 @@
/*
* Copyright 2002-2007 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.config;
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.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.core.OrderComparator;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.integration.MessagingConfigurationException;
import org.springframework.integration.adapter.DefaultTargetAdapter;
import org.springframework.integration.adapter.MethodInvokingSource;
import org.springframework.integration.adapter.MethodInvokingTarget;
import org.springframework.integration.adapter.PollingSourceAdapter;
import org.springframework.integration.annotation.DefaultOutput;
import org.springframework.integration.annotation.Handler;
import org.springframework.integration.annotation.MessageEndpoint;
import org.springframework.integration.annotation.Polled;
import org.springframework.integration.annotation.Router;
import org.springframework.integration.annotation.Splitter;
import org.springframework.integration.bus.ConsumerPolicy;
import org.springframework.integration.bus.MessageBus;
import org.springframework.integration.channel.ChannelRegistryAware;
import org.springframework.integration.channel.MessageChannel;
import org.springframework.integration.channel.PointToPointChannel;
import org.springframework.integration.endpoint.GenericMessageEndpoint;
import org.springframework.integration.handler.MessageHandler;
import org.springframework.integration.handler.MessageHandlerChain;
import org.springframework.integration.handler.config.DefaultMessageHandlerCreator;
import org.springframework.integration.handler.config.MessageHandlerCreator;
import org.springframework.integration.handler.config.RouterMessageHandlerCreator;
import org.springframework.integration.handler.config.SplitterMessageHandlerCreator;
import org.springframework.util.Assert;
import org.springframework.util.ReflectionUtils;
import org.springframework.util.StringUtils;
/**
* A {@link BeanPostProcessor} implementation that generates endpoints for
* classes annotated with {@link MessageEndpoint @MessageEndpoint}.
*
* @author Mark Fisher
*/
public class MessageEndpointAnnotationPostProcessor implements BeanPostProcessor, InitializingBean {
private Log logger = LogFactory.getLog(this.getClass());
private Map<Class<? extends Annotation>, MessageHandlerCreator> handlerCreators =
new ConcurrentHashMap<Class<? extends Annotation>, MessageHandlerCreator>();
private MessageBus messageBus;
public void setMessageBus(MessageBus messageBus) {
Assert.notNull(messageBus, "messageBus must not be null");
this.messageBus = messageBus;
}
public void setCustomHandlerCreators(
Map<Class<? extends Annotation>, MessageHandlerCreator> customHandlerCreators) {
for (Map.Entry<Class<? extends Annotation>, MessageHandlerCreator> entry : customHandlerCreators.entrySet()) {
this.handlerCreators.put(entry.getKey(), entry.getValue());
}
}
public void afterPropertiesSet() {
Assert.notNull(this.messageBus, "messageBus is required");
this.handlerCreators.put(Handler.class, new DefaultMessageHandlerCreator());
this.handlerCreators.put(Router.class, new RouterMessageHandlerCreator());
this.handlerCreators.put(Splitter.class, new SplitterMessageHandlerCreator());
}
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
MessageEndpoint endpointAnnotation = bean.getClass().getAnnotation(MessageEndpoint.class);
if (endpointAnnotation == null) {
return bean;
}
GenericMessageEndpoint endpoint = new GenericMessageEndpoint();
this.configureInputChannel(bean, beanName, endpointAnnotation, endpoint);
this.configureDefaultOutputChannel(bean, beanName, endpointAnnotation, endpoint);
MessageHandlerChain handlerChain = this.createHandlerChain(bean);
if (handlerChain != null) {
endpoint.setHandler(handlerChain);
}
this.messageBus.registerEndpoint(beanName, endpoint);
return endpoint;
}
private void configureInputChannel(final Object bean, final String beanName,
MessageEndpoint annotation, final GenericMessageEndpoint endpoint) {
String channelName = annotation.input();
if (StringUtils.hasText(channelName)) {
endpoint.setInputChannelName(channelName);
ConsumerPolicy consumerPolicy = new ConsumerPolicy();
consumerPolicy.setPeriod(annotation.pollPeriod());
endpoint.setConsumerPolicy(consumerPolicy);
return;
}
ReflectionUtils.doWithMethods(bean.getClass(), new ReflectionUtils.MethodCallback() {
public void doWith(Method method) throws IllegalArgumentException, IllegalAccessException {
Annotation annotation = AnnotationUtils.getAnnotation(method, Polled.class);
if (annotation != null) {
int period = ((Polled) annotation).period();
MethodInvokingSource<Object> source = new MethodInvokingSource<Object>();
source.setObject(bean);
source.setMethod(method.getName());
PollingSourceAdapter<Object> adapter = new PollingSourceAdapter<Object>(source);
MessageChannel channel = new PointToPointChannel();
adapter.setChannel(channel);
adapter.setPeriod(period);
String channelName = beanName + "-inputChannel";
messageBus.registerChannel(channelName, channel);
messageBus.registerSourceAdapter(beanName + "-sourceAdapter", adapter);
endpoint.setInputChannelName(channelName);
endpoint.getConsumerPolicy().setPeriod(period);
if (period > 0) {
endpoint.getConsumerPolicy().setConcurrency(1);
endpoint.getConsumerPolicy().setMaxConcurrency(1);
endpoint.getConsumerPolicy().setMaxMessagesPerTask(1);
}
return;
}
}
});
}
private void configureDefaultOutputChannel(final Object bean, final String beanName,
final MessageEndpoint annotation, final GenericMessageEndpoint endpoint) {
String channelName = annotation.defaultOutput();
if (StringUtils.hasText(channelName)) {
endpoint.setDefaultOutputChannelName(channelName);
return;
}
ReflectionUtils.doWithMethods(bean.getClass(), new ReflectionUtils.MethodCallback() {
boolean foundDefaultOutput = false;
public void doWith(Method method) throws IllegalArgumentException, IllegalAccessException {
Annotation annotation = AnnotationUtils.getAnnotation(method, DefaultOutput.class);
if (annotation != null) {
if (foundDefaultOutput) {
throw new MessagingConfigurationException("only one @DefaultOutput allowed per endpoint");
}
MethodInvokingTarget<Object> target = new MethodInvokingTarget<Object>();
target.setObject(bean);
target.setMethod(method.getName());
target.afterPropertiesSet();
DefaultTargetAdapter adapter = new DefaultTargetAdapter(target);
PointToPointChannel channel = new PointToPointChannel();
String channelName = beanName + "-defaultOutputChannel";
messageBus.registerChannel(channelName, channel);
messageBus.registerTargetAdapter(beanName + "-targetAdapter", adapter);
endpoint.setDefaultOutputChannelName(channelName);
foundDefaultOutput = true;
return;
}
}
});
}
@SuppressWarnings("unchecked")
private MessageHandlerChain createHandlerChain(final Object bean) {
final List<MessageHandler> handlers = new ArrayList<MessageHandler>();
ReflectionUtils.doWithMethods(bean.getClass(), new ReflectionUtils.MethodCallback() {
public void doWith(Method method) throws IllegalArgumentException, IllegalAccessException {
Annotation[] annotations = AnnotationUtils.getAnnotations(method);
for (Annotation annotation : annotations) {
if (isHandlerAnnotation(annotation)) {
Map<String, ?> attributes = AnnotationUtils.getAnnotationAttributes(annotation);
MessageHandlerCreator handlerCreator = handlerCreators.get(annotation.annotationType());
if (handlerCreator == null) {
if (logger.isWarnEnabled()) {
logger.warn("No handler creator has been registered for handler annotation '" +
annotation.annotationType() + "'");
}
}
else {
MessageHandler handler = handlerCreator.createHandler(bean, method, attributes);
if (handler instanceof ChannelRegistryAware) {
((ChannelRegistryAware) handler).setChannelRegistry(messageBus);
}
if (handler instanceof InitializingBean) {
try {
((InitializingBean) handler).afterPropertiesSet();
}
catch (Exception e) {
throw new MessagingConfigurationException("failed to create handler", e);
}
}
if (handler != null) {
handlers.add(handler);
}
}
}
}
}
});
if (handlers.size() > 0) {
MessageHandlerChain handlerChain = new MessageHandlerChain();
Collections.sort(handlers, new OrderComparator());
for (MessageHandler handler : handlers) {
handlerChain.add(handler);
}
return handlerChain;
}
return null;
}
private boolean isHandlerAnnotation(Annotation annotation) {
return annotation.annotationType().equals(Handler.class)
|| annotation.annotationType().isAnnotationPresent(Handler.class)
|| this.handlerCreators.keySet().contains(annotation.annotationType());
}
}

View File

@@ -0,0 +1,109 @@
/*
* Copyright 2002-2007 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.config;
import java.lang.annotation.Annotation;
import org.springframework.aop.Advisor;
import org.springframework.aop.framework.Advised;
import org.springframework.aop.framework.ProxyFactory;
import org.springframework.aop.support.AopUtils;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanClassLoaderAware;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.integration.annotation.Publisher;
import org.springframework.integration.aop.PublisherAnnotationAdvisor;
import org.springframework.integration.channel.ChannelRegistry;
import org.springframework.util.Assert;
/**
* A {@link BeanPostProcessor} that adds a message publishing interceptor when
* it discovers annotated methods.
*
* @author Mark Fisher
*/
public class PublisherAnnotationPostProcessor implements BeanPostProcessor, BeanClassLoaderAware {
private Class<? extends Annotation> publisherAnnotationType = Publisher.class;
private String channelNameAttribute = "channel";
private ChannelRegistry channelRegistry;
private Advisor advisor;
private ClassLoader beanClassLoader;
public void setBeanClassLoader(ClassLoader beanClassLoader) {
Assert.notNull(beanClassLoader, "'beanClassLoader' must not be null");
this.beanClassLoader = beanClassLoader;
}
public void setPublisherAnnotationType(Class<? extends Annotation> publisherAnnotationType) {
Assert.notNull(publisherAnnotationType, "'publisherAnnotationType' must not be null");
this.publisherAnnotationType = publisherAnnotationType;
}
public void setChannelNameAttribute(String channelNameAttribute) {
Assert.notNull(channelNameAttribute, "'channelNameAttribute' must not be null");
this.channelNameAttribute = channelNameAttribute;
}
public void setChannelRegistry(ChannelRegistry channelRegistry) {
Assert.notNull(channelRegistry, "'channelRegistry' must not be null");
this.channelRegistry = channelRegistry;
}
private void createAdvisor() {
if (this.channelRegistry == null) {
throw new IllegalStateException("'channelRegistry' is required");
}
this.advisor = new PublisherAnnotationAdvisor(this.publisherAnnotationType, this.channelNameAttribute,
this.channelRegistry);
}
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
Class<?> targetClass = bean instanceof Advised ?
((Advised) bean).getTargetSource().getTargetClass() : bean.getClass();
if (targetClass == null) {
return bean;
}
if (advisor == null) {
createAdvisor();
}
if (AopUtils.canApply(this.advisor, targetClass)) {
if (bean instanceof Advised) {
((Advised) bean).addAdvisor(this.advisor);
return bean;
}
else {
ProxyFactory pf = new ProxyFactory(bean);
pf.addAdvisor(this.advisor);
return pf.getProxy(this.beanClassLoader);
}
}
else {
return bean;
}
}
}

View File

@@ -0,0 +1,101 @@
/*
* Copyright 2002-2007 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.config;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.aop.framework.Advised;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.integration.annotation.Subscriber;
import org.springframework.integration.bus.MessageBus;
import org.springframework.integration.endpoint.GenericMessageEndpoint;
import org.springframework.integration.handler.DefaultMessageHandlerAdapter;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.ReflectionUtils;
/**
* A {@link BeanPostProcessor} that creates a method-invoking handler adapter
* when it discovers methods annotated with {@link Subscriber @Subscriber}.
*
* @author Mark Fisher
*/
public class SubscriberAnnotationPostProcessor implements BeanPostProcessor {
private Log logger = LogFactory.getLog(this.getClass());
private Class<? extends Annotation> subscriberAnnotationType = Subscriber.class;
private String channelNameAttribute = "channel";
private MessageBus messageBus;
public void setSubscriberAnnotationType(Class<? extends Annotation> subscriberAnnotationType) {
Assert.notNull(subscriberAnnotationType, "'subscriberAnnotationType' must not be null");
this.subscriberAnnotationType = subscriberAnnotationType;
}
public void setChannelNameAttribute(String channelNameAttribute) {
Assert.notNull(channelNameAttribute, "'channelNameAttribute' must not be null");
this.channelNameAttribute = channelNameAttribute;
}
public void setMessageBus(MessageBus messageBus) {
Assert.notNull(messageBus, "'messageBus' must not be null");
this.messageBus = messageBus;
}
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
public Object postProcessAfterInitialization(final Object bean, String beanName) throws BeansException {
final Class<?> targetClass = bean instanceof Advised ?
((Advised) bean).getTargetSource().getTargetClass() : bean.getClass();
if (targetClass == null) {
return bean;
}
ReflectionUtils.doWithMethods(targetClass, new ReflectionUtils.MethodCallback() {
public void doWith(Method method) throws IllegalArgumentException, IllegalAccessException {
Annotation annotation = method.getAnnotation(subscriberAnnotationType);
if (annotation != null) {
String channelName = (String) AnnotationUtils.getValue(annotation, channelNameAttribute);
DefaultMessageHandlerAdapter adapter = new DefaultMessageHandlerAdapter();
adapter.setMethodName(method.getName());
adapter.setObject(bean);
adapter.afterPropertiesSet();
GenericMessageEndpoint endpoint = new GenericMessageEndpoint();
endpoint.setInputChannelName(channelName);
endpoint.setChannelRegistry(messageBus);
endpoint.setHandler(adapter);
String endpointName = ClassUtils.getShortNameAsProperty(targetClass) +
"-" + method.getName() + "-endpoint";
messageBus.registerEndpoint(endpointName, endpoint);
}
}
});
return bean;
}
}

View File

@@ -0,0 +1,176 @@
<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema xmlns="http://www.springframework.org/schema/integration"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:tool="http://www.springframework.org/schema/tool"
targetNamespace="http://www.springframework.org/schema/integration"
elementFormDefault="qualified"
attributeFormDefault="unqualified">
<xsd:import namespace="http://www.springframework.org/schema/beans"/>
<xsd:import namespace="http://www.springframework.org/schema/tool"/>
<xsd:annotation>
<xsd:documentation><![CDATA[
Defines the configuration elements for Spring Integration.
]]></xsd:documentation>
</xsd:annotation>
<xsd:element name="message-bus">
<xsd:complexType>
<xsd:annotation>
<xsd:documentation>
Defines a message bus.
</xsd:documentation>
</xsd:annotation>
<xsd:attribute name="auto-create-channels" type="xsd:boolean"/>
<xsd:attribute name="invalid-message-channel" type="xsd:string"/>
</xsd:complexType>
</xsd:element>
<xsd:element name="annotation-driven">
<xsd:complexType>
<xsd:annotation>
<xsd:documentation>
Enables the annotation-driven post-processors.
</xsd:documentation>
</xsd:annotation>
</xsd:complexType>
</xsd:element>
<xsd:element name="channel">
<xsd:complexType>
<xsd:annotation>
<xsd:documentation>
Defines a message channel.
</xsd:documentation>
</xsd:annotation>
<xsd:complexContent>
<xsd:extension base="beans:identifiedType">
<xsd:attribute name="capacity" type="xsd:integer"/>
</xsd:extension>
</xsd:complexContent>
</xsd:complexType>
</xsd:element>
<xsd:element name="source-adapter">
<xsd:complexType>
<xsd:annotation>
<xsd:documentation>
Defines a source (inbound) channel adapter.
</xsd:documentation>
</xsd:annotation>
<xsd:complexContent>
<xsd:extension base="beans:identifiedType">
<xsd:attribute name="ref" type="xsd:string" use="required"/>
<xsd:attribute name="method" type="xsd:string" use="required"/>
<xsd:attribute name="channel" type="xsd:string" use="required"/>
<xsd:attribute name="period" type="xsd:int"/>
</xsd:extension>
</xsd:complexContent>
</xsd:complexType>
</xsd:element>
<xsd:element name="target-adapter">
<xsd:complexType>
<xsd:annotation>
<xsd:documentation>
Defines a target (outbound) channel adapter.
</xsd:documentation>
</xsd:annotation>
<xsd:complexContent>
<xsd:extension base="beans:identifiedType">
<xsd:attribute name="ref" type="xsd:string" use="required"/>
<xsd:attribute name="method" type="xsd:string" use="required"/>
<xsd:attribute name="channel" type="xsd:string" use="required"/>
</xsd:extension>
</xsd:complexContent>
</xsd:complexType>
</xsd:element>
<xsd:element name="endpoint">
<xsd:complexType>
<xsd:annotation>
<xsd:documentation>
Defines a message endpoint.
</xsd:documentation>
</xsd:annotation>
<xsd:complexContent>
<xsd:extension base="beans:identifiedType">
<xsd:sequence>
<xsd:element ref="consumer" minOccurs="0" maxOccurs="1"/>
<xsd:element ref="handler" minOccurs="0" maxOccurs="unbounded"/>
</xsd:sequence>
<xsd:attribute name="input-channel" type="xsd:string"/>
<xsd:attribute name="default-output-channel" type="xsd:string"/>
<xsd:attribute name="handler-ref" type="xsd:string"/>
<xsd:attribute name="handler-method" type="xsd:string"/>
</xsd:extension>
</xsd:complexContent>
</xsd:complexType>
</xsd:element>
<xsd:element name="consumer">
<xsd:complexType>
<xsd:annotation>
<xsd:documentation>
Defines a consumer policy.
</xsd:documentation>
</xsd:annotation>
<xsd:attribute name="period" type="xsd:int"/>
</xsd:complexType>
</xsd:element>
<xsd:element name="handler">
<xsd:complexType>
<xsd:annotation>
<xsd:documentation>
Defines a handler.
</xsd:documentation>
</xsd:annotation>
<xsd:attribute name="ref" type="xsd:string" use="required"/>
<xsd:attribute name="method" type="xsd:string"/>
</xsd:complexType>
</xsd:element>
<xsd:element name="file-source">
<xsd:complexType>
<xsd:annotation>
<xsd:documentation>
Defines a file-based source channel adapter.
</xsd:documentation>
</xsd:annotation>
<xsd:attribute name="directory" type="xsd:string" use="required"/>
<xsd:attribute name="channel" type="xsd:string" use="required"/>
<xsd:attribute name="poll-period" type="xsd:int" use="required"/>
</xsd:complexType>
</xsd:element>
<xsd:element name="file-target">
<xsd:complexType>
<xsd:annotation>
<xsd:documentation>
Defines a file-based target channel adapter.
</xsd:documentation>
</xsd:annotation>
<xsd:attribute name="directory" type="xsd:string" use="required"/>
<xsd:attribute name="channel" type="xsd:string" use="required"/>
</xsd:complexType>
</xsd:element>
<xsd:element name="jms-target">
<xsd:complexType>
<xsd:annotation>
<xsd:documentation>
Defines a jms-based target channel adapter.
</xsd:documentation>
</xsd:annotation>
<xsd:attribute name="jms-template" type="xsd:string"/>
<xsd:attribute name="connection-factory" type="xsd:string"/>
<xsd:attribute name="destination" type="xsd:string"/>
<xsd:attribute name="channel" type="xsd:string" use="required"/>
</xsd:complexType>
</xsd:element>
</xsd:schema>

View File

@@ -0,0 +1,137 @@
/*
* Copyright 2002-2007 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.endpoint;
import org.springframework.integration.MessageHandlingException;
import org.springframework.integration.MessagingConfigurationException;
import org.springframework.integration.bus.ConsumerPolicy;
import org.springframework.integration.channel.ChannelRegistry;
import org.springframework.integration.channel.MessageChannel;
import org.springframework.integration.handler.MessageHandler;
import org.springframework.integration.message.Message;
/**
* A generic endpoint implementation designed to accommodate a variety of
* strategies including:
* <ul>
* <li><i>source channel-adapter:</i> source adapter + target channel</li>
* <li><i>target channel-adapter:</i> source channel + target adapter</li>
* <li><i>one-way:</i> source + handler that returns null and no target</li>
* <li><i>request-reply:</i> source + handler and either a reply channel
* specified on the request message or a default target on the endpoint</i>
* </ul>
*
* @author Mark Fisher
*/
public class GenericMessageEndpoint<T> implements MessageEndpoint<T> {
private String inputChannelName;
private String defaultOutputChannelName;
private MessageHandler handler;
private ChannelRegistry channelRegistry;
private ConsumerPolicy consumerPolicy = new ConsumerPolicy();
/**
* Set the name of the channel from which this endpoint receives messages.
*/
public void setInputChannelName(String inputChannelName) {
this.inputChannelName = inputChannelName;
}
/**
* Return the name of the channel from which this endpoint receives messages.
*/
public String getInputChannelName() {
return this.inputChannelName;
}
public void setConsumerPolicy(ConsumerPolicy consumerPolicy) {
this.consumerPolicy = consumerPolicy;
}
public ConsumerPolicy getConsumerPolicy() {
return this.consumerPolicy;
}
/**
* Set the name of the channel to which this endpoint can send reply messages by default.
*/
public void setDefaultOutputChannelName(String defaultOutputChannelName) {
this.defaultOutputChannelName = defaultOutputChannelName;
}
public String getDefaultOutputChannelName() {
return this.defaultOutputChannelName;
}
/**
* Set a handler to be invoked for each consumed message.
*/
public void setHandler(MessageHandler handler) {
this.handler = handler;
}
/**
* Set the channel registry to use for looking up channels by name.
*/
public void setChannelRegistry(ChannelRegistry channelRegistry) {
this.channelRegistry = channelRegistry;
}
public void messageReceived(Message<T> message) {
if (this.handler == null) {
if (this.defaultOutputChannelName == null) {
throw new MessagingConfigurationException(
"endpoint must have either a 'handler' or 'defaultOutputChannelName'");
}
MessageChannel replyChannel = this.channelRegistry.lookupChannel(this.defaultOutputChannelName);
replyChannel.send(message);
return;
}
Message<?> replyMessage = handler.handle(message);
if (replyMessage != null) {
MessageChannel replyChannel = this.resolveReplyChannel(message);
if (replyChannel == null) {
throw new MessageHandlingException("Unable to determine reply channel for message. "
+ "Provide a 'replyChannelName' in the message header or a 'defaultOutputChannelName' "
+ "on the message endpoint.");
}
replyChannel.send(replyMessage);
}
}
private MessageChannel resolveReplyChannel(Message<?> message) {
if (this.channelRegistry == null) {
return null;
}
String replyChannelName = message.getHeader().getReplyChannelName();
if (replyChannelName != null && replyChannelName.trim().length() > 0) {
return this.channelRegistry.lookupChannel(replyChannelName);
}
if (this.defaultOutputChannelName != null) {
return this.channelRegistry.lookupChannel(this.defaultOutputChannelName);
}
return null;
}
}

View File

@@ -0,0 +1,42 @@
/*
* Copyright 2002-2007 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.endpoint;
import org.springframework.integration.bus.ConsumerPolicy;
import org.springframework.integration.channel.ChannelRegistry;
import org.springframework.integration.message.MessageReceiver;
/**
* Base interface for message endpoints.
*
* @author Mark Fisher
*/
public interface MessageEndpoint<T> extends MessageReceiver<T> {
void setInputChannelName(String inputChannelName);
String getInputChannelName();
void setDefaultOutputChannelName(String defaultOutputChannelName);
String getDefaultOutputChannelName();
ConsumerPolicy getConsumerPolicy();
void setChannelRegistry(ChannelRegistry channelRegistry);
}

View File

@@ -0,0 +1,132 @@
/*
* Copyright 2002-2007 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 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.message.Message;
import org.springframework.integration.message.MessageMapper;
import org.springframework.integration.message.SimplePayloadMessageMapper;
import org.springframework.integration.util.SimpleMethodInvoker;
import org.springframework.util.Assert;
/**
* Base implementation of the {@link MessageHandler} interface that creates an
* invoker for the specified method and target object. It also accepts an
* implementation of the {@link MessageMapper} strategy which it exposes to
* subclasses for converting the {@link Message} to an object. Likewise, if the
* method has a non-null return value, a reply message will be generated by the
* mapper.
*
* @author Mark Fisher
*/
public abstract class AbstractMessageHandlerAdapter<T> implements MessageHandler, Ordered, InitializingBean {
protected Log logger = LogFactory.getLog(this.getClass());
private T object;
private String methodName;
private MessageMapper mapper = new SimplePayloadMessageMapper();
private SimpleMethodInvoker<T> invoker;
private int order = Integer.MAX_VALUE;
private volatile boolean initialized;
private Object lifecycleMonitor = new Object();
public void setObject(T object) {
Assert.notNull(object, "'object' must not be null");
this.object = object;
}
protected Object getObject() {
return this.object;
}
public void setMethodName(String methodName) {
Assert.notNull(methodName, "'methodName' must not be null");
this.methodName = methodName;
}
public String getMethodName() {
return this.methodName;
}
public void setMapper(MessageMapper mapper) {
Assert.notNull(mapper, "'mapper' must not be null");
this.mapper = mapper;
}
protected MessageMapper getMapper() {
return this.mapper;
}
public void setOrder(int order) {
this.order = order;
}
public int getOrder() {
return this.order;
}
public final void afterPropertiesSet() {
this.validate();
synchronized (this.lifecycleMonitor) {
this.invoker = new SimpleMethodInvoker<T>(this.object, this.methodName);
this.initialized = true;
}
}
public final boolean isInitialized() {
synchronized (this.lifecycleMonitor) {
return this.initialized;
}
}
public final Message<?> handle(Message<?> message) {
Object result = this.doHandle(message, invoker);
if (result != null) {
if (result instanceof Message) {
return (Message<?>) result;
}
return this.mapper.toMessage(result);
}
return null;
}
/**
* Subclasses may override this method to provide validation upon initialization.
*/
protected void validate() {
}
/**
* Subclasses must implement this method. The invoker has been created for
* the provided target object and method. May return an object of type
* {@link Message}, else rely on the message mapper to convert.
*/
protected abstract Object doHandle(Message message, SimpleMethodInvoker invoker);
}

View File

@@ -0,0 +1,40 @@
/*
* Copyright 2002-2007 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 org.springframework.beans.factory.InitializingBean;
import org.springframework.core.Ordered;
import org.springframework.integration.message.Message;
import org.springframework.integration.message.MessageMapper;
import org.springframework.integration.util.SimpleMethodInvoker;
/**
* An implementation of {@link MessageHandler} that invokes the specified method
* on the provided target object. It then uses a {@link MessageMapper} strategy
* for converting the object to a {@link Message}. If the method has a non-null
* return value, a reply message will be generated by the mapper.
*
* @author Mark Fisher
*/
public class DefaultMessageHandlerAdapter<T> extends AbstractMessageHandlerAdapter<T>
implements Ordered, InitializingBean {
public Object doHandle(Message message, SimpleMethodInvoker invoker) {
return invoker.invokeMethod(this.getMapper().fromMessage(message));
}
}

View File

@@ -0,0 +1,51 @@
/*
* Copyright 2002-2007 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 org.springframework.integration.message.Message;
import org.springframework.util.Assert;
/**
* A message handler implementation that intercepts calls to another handler.
*
* @author Mark Fisher
*/
public abstract class InterceptingMessageHandler implements MessageHandler {
private MessageHandler target;
public InterceptingMessageHandler(MessageHandler target) {
Assert.notNull(target, "target must not be null");
this.target = target;
}
public Message handle(Message message) {
return handle(message, this.target);
}
/**
* The handler method for subclasses to implement.
*
* @param message the message to handle
* @param target the intercepted handler
* @return a reply message or null
*/
public abstract Message handle(Message message, MessageHandler target);
}

View File

@@ -0,0 +1,32 @@
/*
* Copyright 2002-2007 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 org.springframework.integration.message.Message;
/**
* Generic message handler interface. Typical implementations will translate
* between the generic Messages of the integration framework and the domain
* objects that are passed-to and returned-from business components.
*
* @author Mark Fisher
*/
public interface MessageHandler {
Message<?> handle(Message<?> message);
}

View File

@@ -0,0 +1,64 @@
/*
* Copyright 2002-2007 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.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import org.springframework.integration.message.Message;
/**
* A message handler implementation that passes incoming messages through a
* chain of handlers.
*
* @author Mark Fisher
*/
public class MessageHandlerChain implements MessageHandler {
private List<MessageHandler> handlers = new CopyOnWriteArrayList<MessageHandler>();
/**
* Add a handler to the end of the chain.
*/
public void add(MessageHandler handler) {
this.handlers.add(handler);
}
/**
* Add a handler to the chain at the specified index.
*/
public void add(int index, MessageHandler handler) {
this.handlers.add(index, handler);
}
public void setHandlers(List<MessageHandler> handlers) {
this.handlers.clear();
this.handlers.addAll(handlers);
}
public Message handle(Message message) {
for (MessageHandler next : handlers) {
message = next.handle(message);
if (message == null) {
return null;
}
}
return message;
}
}

View File

@@ -0,0 +1,51 @@
/*
* Copyright 2002-2007 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.config;
import java.lang.reflect.Method;
import java.util.Map;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.core.annotation.Order;
import org.springframework.integration.handler.AbstractMessageHandlerAdapter;
import org.springframework.integration.handler.MessageHandler;
/**
* Base class for handler creators that generate a {@link MessageHandler}
* adapter for the provided object and method.
*
* @author Mark Fisher
*/
public abstract class AbstractMessageHandlerCreator implements MessageHandlerCreator {
public final MessageHandler createHandler(Object object, Method method, Map<String, ?> attributes) {
MessageHandler handler = this.doCreateHandler(object, method, attributes);
if (handler instanceof AbstractMessageHandlerAdapter<?>) {
AbstractMessageHandlerAdapter adapter = ((AbstractMessageHandlerAdapter) handler);
adapter.setObject(object);
adapter.setMethodName(method.getName());
Order orderAnnotation = (Order) AnnotationUtils.getAnnotation(method, Order.class);
if (orderAnnotation != null) {
adapter.setOrder(orderAnnotation.value());
}
}
return handler;
}
protected abstract MessageHandler doCreateHandler(Object object, Method method, Map<String, ?> attributes);
}

View File

@@ -0,0 +1,40 @@
/*
* Copyright 2002-2007 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.config;
import java.lang.reflect.Method;
import java.util.Map;
import org.springframework.core.annotation.Order;
import org.springframework.integration.handler.DefaultMessageHandlerAdapter;
import org.springframework.integration.handler.MessageHandler;
/**
* Default implementation of the handler creator strategy that creates a
* {@link DefaultMessageHandlerAdapter} for the provided object and method.
* This version does not even consider the attributes. It does however respect
* an {@link Order} annotation if present.
*
* @author Mark Fisher
*/
public class DefaultMessageHandlerCreator extends AbstractMessageHandlerCreator {
public MessageHandler doCreateHandler(Object object, Method method, Map<String, ?> attributes) {
return new DefaultMessageHandlerAdapter<Object>();
}
}

View File

@@ -0,0 +1,33 @@
/*
* Copyright 2002-2007 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.config;
import java.lang.reflect.Method;
import java.util.Map;
import org.springframework.integration.handler.MessageHandler;
/**
* Strategy interface for creating {@link MessageHandler MessageHandlers}.
*
* @author Mark Fisher
*/
public interface MessageHandlerCreator {
MessageHandler createHandler(Object object, Method method, Map<String, ?> attributes);
}

View File

@@ -0,0 +1,36 @@
/*
* Copyright 2002-2007 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.config;
import java.lang.reflect.Method;
import java.util.Map;
import org.springframework.integration.handler.MessageHandler;
import org.springframework.integration.router.RouterMessageHandlerAdapter;
/**
* Creates a {@link MessageHandler} adapter for router methods.
*
* @author Mark Fisher
*/
public class RouterMessageHandlerCreator extends AbstractMessageHandlerCreator {
public MessageHandler doCreateHandler(Object object, Method method, Map<String, ?> attributes) {
return new RouterMessageHandlerAdapter(object, method, attributes);
}
}

View File

@@ -0,0 +1,35 @@
/*
* Copyright 2002-2007 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.config;
import java.lang.reflect.Method;
import java.util.Map;
import org.springframework.integration.handler.MessageHandler;
import org.springframework.integration.router.SplitterMessageHandlerAdapter;
/**
* Creates a {@link MessageHandler} adapter for splitter methods.
*
* @author Mark Fisher
*/
public class SplitterMessageHandlerCreator extends AbstractMessageHandlerCreator {
public MessageHandler doCreateHandler(Object object, Method method, Map<String, ?> attributes) {
return new SplitterMessageHandlerAdapter(object, method, attributes);
}
}

View File

@@ -0,0 +1,43 @@
/*
* Copyright 2002-2007 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.message;
import org.springframework.integration.util.RandomGuidUidGenerator;
import org.springframework.integration.util.UidGenerator;
import org.springframework.util.Assert;
/**
* Base class that provides the default {@link UidGenerator} as well as a setter
* for providing a custom id generator implementation.
*
* @author Mark Fisher
*/
public abstract class AbstractMessageMapper<M, O> implements MessageMapper<M, O> {
private UidGenerator uidGenerator = new RandomGuidUidGenerator();
public void setUidGenerator(UidGenerator uidGenerator) {
Assert.notNull(uidGenerator, "'uidGenerator' must not be null");
this.uidGenerator = uidGenerator;
}
public UidGenerator getUidGenerator() {
return this.uidGenerator;
}
}

View File

@@ -0,0 +1,84 @@
/*
* Copyright 2002-2007 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.message;
import java.util.concurrent.locks.ReentrantLock;
import org.springframework.integration.SystemInterruptedException;
import org.springframework.util.Assert;
/**
* Base Message class defining common properties such as id, header, and lock.
*
* @author Mark Fisher
*/
public class GenericMessage<T> implements Message<T> {
private Object id;
private MessageHeader header = new MessageHeader();
private T payload;
private ReentrantLock lock;
public GenericMessage(Object id, T payload) {
Assert.notNull(id, "id must not be null");
Assert.notNull(payload, "payload must not be null");
this.id = id;
this.payload = payload;
}
public Object getId() {
return this.id;
}
public MessageHeader getHeader() {
return this.header;
}
protected void setHeader(MessageHeader header) {
this.header = header;
}
public T getPayload() {
return this.payload;
}
protected void setPayload(T newPayload) {
this.payload = newPayload;
}
public void lock() {
this.lock.lock();
}
public void lockInterruptibly() {
try {
lock.lockInterruptibly();
}
catch (InterruptedException e) {
throw new SystemInterruptedException("Unable to obtain lock for message", e);
}
}
public void unlock() {
lock.unlock();
}
}

View File

@@ -0,0 +1,36 @@
/*
* Copyright 2002-2007 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.message;
/**
* The central interface that any Message type must implement.
*
* @author Mark Fisher
*/
public interface Message<T> {
Object getId();
MessageHeader getHeader();
T getPayload();
void lock();
void unlock();
}

View File

@@ -0,0 +1,114 @@
/*
* Copyright 2002-2007 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.message;
import java.util.Date;
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.ConcurrentHashMap;
/**
* A holder for Message metadata. This includes information that is used by the
* messaging system (such <i>correlationId</i>) as well as information that is
* relevant for specific messaging endpoints. For the latter, String values may
* be stored as <i>properties</i> and Object values may be stored as
* <i>attributes</i>.
*
* @author Mark Fisher
*/
public class MessageHeader {
private Object correlationId;
private String replyChannelName;
private Date expiration;
private int sequenceNumber = 1;
private int sequenceSize = 1;
private Properties properties = new Properties();
private Map<String, Object> attributes = new ConcurrentHashMap<String, Object>();
public Object getCorrelationId() {
return this.correlationId;
}
public void setCorrelationId(Object correlationId) {
this.correlationId = correlationId;
}
public String getReplyChannelName() {
return this.replyChannelName;
}
public void setReplyChannelName(String replyChannelName) {
this.replyChannelName = replyChannelName;
}
public int getSequenceNumber() {
return this.sequenceNumber;
}
/**
* Set the expiration date for this message or <code>null</code> to
* indicate 'never expire'. The default is <code>null</code>.
*/
public void setExpiration(Date expiration) {
this.expiration = expiration;
}
/**
* Return the expiration date for this message or <code>null</code> to
* indicate 'never expire'.
*/
public Date getExpiration() {
return this.expiration;
}
public void setSequenceNumber(int sequenceNumber) {
this.sequenceNumber = sequenceNumber;
}
public int getSequenceSize() {
return this.sequenceSize;
}
public void setSequenceSize(int sequenceSize) {
this.sequenceSize = sequenceSize;
}
public String getProperty(String key) {
return this.properties.getProperty(key);
}
public void setProperty(String key, String value) {
this.properties.setProperty(key, value);
}
public Object getAttribute(String key) {
return this.attributes.get(key);
}
public void setAttribute(String key, Object value) {
this.attributes.put(key, value);
}
}

View File

@@ -0,0 +1,36 @@
/*
* Copyright 2002-2007 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.message;
/**
* Strategy interface for mapping between messages and objects.
*
* @author Mark Fisher
*/
public interface MessageMapper<M,O> {
/**
* Map to a {@link Message} from the given object.
*/
Message<M> toMessage(O source);
/**
* Map from the given {@link Message} to an object.
*/
O fromMessage(Message<M> message);
}

View File

@@ -0,0 +1,29 @@
/*
* Copyright 2002-2007 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.message;
/**
* The primary callback interface for any component capable of receiving
* messages. This includes message endpoints as well as target adapters.
*
* @author Mark Fisher
*/
public interface MessageReceiver<T> {
void messageReceived(Message<T> message);
}

View File

@@ -0,0 +1,28 @@
/*
* Copyright 2002-2007 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.message;
/**
* Strategy interface for message selection.
*
* @author Mark Fisher
*/
public interface MessageSelector {
boolean accept(Message<?> message);
}

Some files were not shown because too many files have changed in this diff Show More