diff --git a/spring-integration-adapters/.classpath b/spring-integration-adapters/.classpath index 28994fe72a..1f743c678d 100644 --- a/spring-integration-adapters/.classpath +++ b/spring-integration-adapters/.classpath @@ -6,6 +6,7 @@ + @@ -18,6 +19,7 @@ + diff --git a/spring-integration-adapters/ivy.xml b/spring-integration-adapters/ivy.xml index 8a6feb4314..902635a383 100644 --- a/spring-integration-adapters/ivy.xml +++ b/spring-integration-adapters/ivy.xml @@ -23,6 +23,7 @@ + @@ -30,6 +31,7 @@ + \ No newline at end of file diff --git a/spring-integration-adapters/src/main/java/org/springframework/integration/adapter/AbstractMessageHandlingSourceAdapter.java b/spring-integration-adapters/src/main/java/org/springframework/integration/adapter/AbstractMessageHandlingSourceAdapter.java index e180a45504..4f1e321f6a 100644 --- a/spring-integration-adapters/src/main/java/org/springframework/integration/adapter/AbstractMessageHandlingSourceAdapter.java +++ b/spring-integration-adapters/src/main/java/org/springframework/integration/adapter/AbstractMessageHandlingSourceAdapter.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2007 the original author or authors. + * Copyright 2002-2008 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -75,6 +75,10 @@ public abstract class AbstractMessageHandlingSourceAdapter implements SourceAdap } public final void afterPropertiesSet() throws Exception { + if (this.channel == null) { + throw new MessagingConfigurationException("The 'channel' property of '" + + this.getClass().getName() + "' must not be null."); + } synchronized (this.lifecycleMonitor) { if (this.initialized) { return; diff --git a/spring-integration-adapters/src/main/java/org/springframework/integration/adapter/httpinvoker/HttpInvokerSourceAdapter.java b/spring-integration-adapters/src/main/java/org/springframework/integration/adapter/httpinvoker/HttpInvokerSourceAdapter.java new file mode 100644 index 0000000000..2c5cfdabc9 --- /dev/null +++ b/spring-integration-adapters/src/main/java/org/springframework/integration/adapter/httpinvoker/HttpInvokerSourceAdapter.java @@ -0,0 +1,65 @@ +/* + * Copyright 2002-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.integration.adapter.httpinvoker; + +import java.io.IOException; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.springframework.integration.adapter.AbstractMessageHandlingSourceAdapter; +import org.springframework.integration.channel.MessageChannel; +import org.springframework.integration.handler.MessageHandler; +import org.springframework.integration.message.MessageHandlingException; +import org.springframework.remoting.httpinvoker.HttpInvokerServiceExporter; +import org.springframework.util.Assert; +import org.springframework.web.HttpRequestHandler; + +/** + * A source channel adapter for HttpInvoker-based remoting. + * + * @author Mark Fisher + */ +public class HttpInvokerSourceAdapter extends AbstractMessageHandlingSourceAdapter implements HttpRequestHandler { + + private volatile HttpInvokerServiceExporter exporter; + + + public HttpInvokerSourceAdapter(MessageChannel channel) { + Assert.notNull(channel, "'channel' must not be null"); + this.setChannel(channel); + } + + + public void initialize() { + HttpInvokerServiceExporter exporter = new HttpInvokerServiceExporter(); + exporter.setService(this); + exporter.setServiceInterface(MessageHandler.class); + exporter.afterPropertiesSet(); + this.exporter = exporter; + } + + public void handleRequest(HttpServletRequest request, HttpServletResponse response) + throws ServletException, IOException { + if (this.exporter == null) { + throw new MessageHandlingException("adapter has not been initialized"); + } + this.exporter.handleRequest(request, response); + } + +} diff --git a/spring-integration-adapters/src/test/java/org/springframework/integration/adapter/httpinvoker/HttpInvokerSourceAdapterTests.java b/spring-integration-adapters/src/test/java/org/springframework/integration/adapter/httpinvoker/HttpInvokerSourceAdapterTests.java new file mode 100644 index 0000000000..c4df56366e --- /dev/null +++ b/spring-integration-adapters/src/test/java/org/springframework/integration/adapter/httpinvoker/HttpInvokerSourceAdapterTests.java @@ -0,0 +1,108 @@ +/* + * Copyright 2002-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.integration.adapter.httpinvoker; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.util.concurrent.Executors; + +import org.junit.Test; + +import org.springframework.integration.channel.MessageChannel; +import org.springframework.integration.channel.SimpleChannel; +import org.springframework.integration.message.Message; +import org.springframework.integration.message.StringMessage; +import org.springframework.mock.web.MockHttpServletRequest; +import org.springframework.mock.web.MockHttpServletResponse; +import org.springframework.remoting.support.RemoteInvocation; +import org.springframework.remoting.support.RemoteInvocationResult; + +/** + * @author Mark Fisher + */ +public class HttpInvokerSourceAdapterTests { + + @Test + public void testRequestOnly() throws Exception { + MessageChannel channel = new SimpleChannel(); + HttpInvokerSourceAdapter adapter = new HttpInvokerSourceAdapter(channel); + adapter.setExpectReply(false); + adapter.afterPropertiesSet(); + MockHttpServletRequest request = new MockHttpServletRequest(); + MockHttpServletResponse response = new MockHttpServletResponse(); + request.setContent(createRequestContent(new StringMessage("test"))); + adapter.handleRequest(request, response); + Message message = channel.receive(500); + assertNotNull(message); + assertEquals("test", message.getPayload()); + } + + @Test + public void testRequestExpectingReply() throws Exception { + final MessageChannel channel = new SimpleChannel(); + Executors.newSingleThreadExecutor().execute(new Runnable() { + public void run() { + Message message = channel.receive(); + MessageChannel replyChannel = (MessageChannel) message.getHeader().getReturnAddress(); + replyChannel.send(new StringMessage(message.getPayload().toString().toUpperCase())); + } + }); + HttpInvokerSourceAdapter adapter = new HttpInvokerSourceAdapter(channel); + adapter.setExpectReply(true); + adapter.afterPropertiesSet(); + MockHttpServletRequest request = new MockHttpServletRequest(); + MockHttpServletResponse response = new MockHttpServletResponse(); + request.setContent(createRequestContent(new StringMessage("test"))); + adapter.handleRequest(request, response); + Message reply = extractMessageFromResponse(response); + assertEquals("TEST", reply.getPayload()); + } + + + private static byte[] createRequestContent(Message message) throws IOException { + RemoteInvocation invocation = new RemoteInvocation( + "handle", new Class[] { Message.class }, new Object[] { message }); + ByteArrayOutputStream baos = new ByteArrayOutputStream(1024); + ObjectOutputStream oos = new ObjectOutputStream(baos); + try { + oos.writeObject(invocation); + oos.flush(); + } + finally { + oos.close(); + } + return baos.toByteArray(); + } + + private static Message extractMessageFromResponse(MockHttpServletResponse response) throws IOException, ClassNotFoundException { + byte[] responseContent = response.getContentAsByteArray(); + ByteArrayInputStream bais = new ByteArrayInputStream(responseContent); + ObjectInputStream ois = new ObjectInputStream(bais); + RemoteInvocationResult remoteResult = (RemoteInvocationResult) ois.readObject(); + Object resultValue = remoteResult.getValue(); + assertTrue(resultValue instanceof Message); + return (Message) resultValue; + } + +}