diff --git a/org.springframework.integration.http/src/main/java/org/springframework/integration/http/CommonsHttpRequestExecutor.java b/org.springframework.integration.http/src/main/java/org/springframework/integration/http/CommonsHttpRequestExecutor.java index 92a3caa795..92f2e795a7 100644 --- a/org.springframework.integration.http/src/main/java/org/springframework/integration/http/CommonsHttpRequestExecutor.java +++ b/org.springframework.integration.http/src/main/java/org/springframework/integration/http/CommonsHttpRequestExecutor.java @@ -189,7 +189,7 @@ public class CommonsHttpRequestExecutor extends AbstractHttpRequestExecutor { /** * Set the given byte stream as the request body. - *

The default implementation simply sets the byte stream as the + *

This implementation simply sets the byte stream as the * EntityEnclosingMethod's request body. This can be overridden, for * example, to write a specific encoding and potentially set appropriate * HTTP request headers. @@ -201,7 +201,7 @@ public class CommonsHttpRequestExecutor extends AbstractHttpRequestExecutor { * @see org.apache.commons.httpclient.methods.PostMethod#setRequestEntity * @see org.apache.commons.httpclient.methods.InputStreamRequestEntity */ - protected void setRequestBody( + private void setRequestBody( EntityEnclosingMethod httpMethod, ByteArrayOutputStream baos, String contentType) throws IOException { httpMethod.setRequestEntity(new ByteArrayRequestEntity(baos.toByteArray(), contentType)); diff --git a/org.springframework.integration.http/src/main/java/org/springframework/integration/http/config/HttpNamespaceHandler.java b/org.springframework.integration.http/src/main/java/org/springframework/integration/http/config/HttpNamespaceHandler.java index e57c538fc6..dd15135997 100644 --- a/org.springframework.integration.http/src/main/java/org/springframework/integration/http/config/HttpNamespaceHandler.java +++ b/org.springframework.integration.http/src/main/java/org/springframework/integration/http/config/HttpNamespaceHandler.java @@ -29,6 +29,7 @@ public class HttpNamespaceHandler extends NamespaceHandlerSupport { public void init() { this.registerBeanDefinitionParser("inbound-channel-adapter", new HttpInboundEndpointParser(false)); this.registerBeanDefinitionParser("inbound-gateway", new HttpInboundEndpointParser(true)); + this.registerBeanDefinitionParser("outbound-gateway", new HttpOutboundGatewayParser()); } } diff --git a/org.springframework.integration.http/src/main/java/org/springframework/integration/http/config/HttpOutboundGatewayParser.java b/org.springframework.integration.http/src/main/java/org/springframework/integration/http/config/HttpOutboundGatewayParser.java new file mode 100644 index 0000000000..452f63d03b --- /dev/null +++ b/org.springframework.integration.http/src/main/java/org/springframework/integration/http/config/HttpOutboundGatewayParser.java @@ -0,0 +1,92 @@ +/* + * Copyright 2002-2009 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.integration.http.config; + +import org.w3c.dom.Element; + +import org.springframework.beans.factory.support.BeanDefinitionBuilder; +import org.springframework.beans.factory.support.BeanDefinitionReaderUtils; +import org.springframework.beans.factory.xml.ParserContext; +import org.springframework.integration.config.xml.AbstractConsumerEndpointParser; +import org.springframework.integration.config.xml.IntegrationNamespaceUtils; +import org.springframework.util.StringUtils; + +/** + * Parser for the 'outbound-gateway' element of the http namespace. + * + * @author Mark Fisher + */ +public class HttpOutboundGatewayParser extends AbstractConsumerEndpointParser { + + private static final String PACKAGE_PATH = "org.springframework.integration.http"; + + + @Override + protected String getInputChannelAttributeName() { + return "request-channel"; + } + + @Override + protected BeanDefinitionBuilder parseHandler(Element element, ParserContext parserContext) { + String defaultUrl = element.getAttribute("default-url"); + String charset = element.getAttribute("charset"); + String extractPayload = element.getAttribute("extract-request-payload"); + String requestMapperRef = element.getAttribute("request-mapper"); + if (StringUtils.hasText(requestMapperRef)) { + if (StringUtils.hasText(defaultUrl)) { + this.requestMapperConflictError("default-url", parserContext, element); + return null; + } + else if (StringUtils.hasText(charset)) { + this.requestMapperConflictError("charset", parserContext, element); + return null; + } + else if (StringUtils.hasText(extractPayload)) { + this.requestMapperConflictError("extract-request-payload", parserContext, element); + return null; + } + } + BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition( + PACKAGE_PATH + ".HttpOutboundEndpoint"); + if (!StringUtils.hasText(requestMapperRef)) { + BeanDefinitionBuilder mapperBuilder = BeanDefinitionBuilder.genericBeanDefinition( + PACKAGE_PATH + ".DefaultOutboundRequestMapper"); + if (StringUtils.hasText(defaultUrl)) { + mapperBuilder.addConstructorArgValue(defaultUrl); + } + if (StringUtils.hasText(charset)) { + mapperBuilder.addPropertyValue("charset", charset); + } + if (StringUtils.hasText(extractPayload)) { + mapperBuilder.addPropertyValue("extractPayload", extractPayload); + } + requestMapperRef = BeanDefinitionReaderUtils.registerWithGeneratedName( + mapperBuilder.getBeanDefinition(), parserContext.getRegistry()); + } + builder.addPropertyReference("requestMapper", requestMapperRef); + IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "request-timeout", "sendTimeout"); + IntegrationNamespaceUtils.setReferenceIfAttributeDefined(builder, element, "request-executor"); + IntegrationNamespaceUtils.setReferenceIfAttributeDefined(builder, element, "reply-channel", "outputChannel"); + return builder; + } + + private void requestMapperConflictError(String nameForGateway, ParserContext parserContext, Element element) { + parserContext.getReaderContext().error("The '" + nameForGateway + "' and 'request-mapper' are mutually exclusive. " + + "When providing an OutboundRequestMapper, set any corresponding property on the mapper directly.", element); + } + +} diff --git a/org.springframework.integration.http/src/main/java/org/springframework/integration/http/config/spring-integration-http-1.0.xsd b/org.springframework.integration.http/src/main/java/org/springframework/integration/http/config/spring-integration-http-1.0.xsd index 723cc84366..b315361706 100644 --- a/org.springframework.integration.http/src/main/java/org/springframework/integration/http/config/spring-integration-http-1.0.xsd +++ b/org.springframework.integration.http/src/main/java/org/springframework/integration/http/config/spring-integration-http-1.0.xsd @@ -69,6 +69,7 @@ + @@ -91,6 +92,42 @@ + + + + + + + + + + + Defines an outbound HTTP-based Messaging Gateway. + + + + + + + + + + + + + + + + + + + + + + + + + @@ -103,7 +140,6 @@ - @@ -123,7 +159,6 @@ - \ No newline at end of file diff --git a/org.springframework.integration.http/src/test/java/org/springframework/integration/http/config/HttpOutboundGatewayParserTests-context.xml b/org.springframework.integration.http/src/test/java/org/springframework/integration/http/config/HttpOutboundGatewayParserTests-context.xml new file mode 100644 index 0000000000..92f3248ae5 --- /dev/null +++ b/org.springframework.integration.http/src/test/java/org/springframework/integration/http/config/HttpOutboundGatewayParserTests-context.xml @@ -0,0 +1,45 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/org.springframework.integration.http/src/test/java/org/springframework/integration/http/config/HttpOutboundGatewayParserTests.java b/org.springframework.integration.http/src/test/java/org/springframework/integration/http/config/HttpOutboundGatewayParserTests.java new file mode 100644 index 0000000000..08db16a551 --- /dev/null +++ b/org.springframework.integration.http/src/test/java/org/springframework/integration/http/config/HttpOutboundGatewayParserTests.java @@ -0,0 +1,142 @@ +/* + * Copyright 2002-2009 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.integration.http.config; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNotSame; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; + +import java.net.URL; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import org.springframework.beans.DirectFieldAccessor; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.context.ApplicationContext; +import org.springframework.integration.core.MessageChannel; +import org.springframework.integration.endpoint.AbstractEndpoint; +import org.springframework.integration.http.DefaultOutboundRequestMapper; +import org.springframework.integration.http.HttpOutboundEndpoint; +import org.springframework.integration.http.HttpRequestExecutor; +import org.springframework.integration.http.OutboundRequestMapper; +import org.springframework.integration.http.SimpleHttpRequestExecutor; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +/** + * @author Mark Fisher + */ +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration +public class HttpOutboundGatewayParserTests { + + @Autowired @Qualifier("minimalConfig") + private AbstractEndpoint minimalConfigEndpoint; + + @Autowired @Qualifier("fullConfigWithMapper") + private AbstractEndpoint fullConfigWithMapperEndpoint; + + @Autowired @Qualifier("fullConfigWithoutMapper") + private AbstractEndpoint fullConfigWithoutMapperEndpoint; + + @Autowired + private ApplicationContext applicationContext; + + + @Test + public void minimalConfig() { + HttpOutboundEndpoint gateway = (HttpOutboundEndpoint) new DirectFieldAccessor( + this.minimalConfigEndpoint).getPropertyValue("handler"); + MessageChannel requestChannel = (MessageChannel) new DirectFieldAccessor( + this.minimalConfigEndpoint).getPropertyValue("inputChannel"); + assertEquals(this.applicationContext.getBean("requests"), requestChannel); + DirectFieldAccessor accessor = new DirectFieldAccessor(gateway); + Object replyChannel = accessor.getPropertyValue("outputChannel"); + assertNull(replyChannel); + OutboundRequestMapper mapper = (OutboundRequestMapper) accessor.getPropertyValue("requestMapper"); + HttpRequestExecutor executor = (HttpRequestExecutor) accessor.getPropertyValue("requestExecutor"); + assertTrue(mapper instanceof DefaultOutboundRequestMapper); + assertTrue(executor instanceof SimpleHttpRequestExecutor); + Object mapperBean = this.applicationContext.getBean("mapper"); + assertNotSame(mapperBean, mapper); + DirectFieldAccessor mapperAccessor = new DirectFieldAccessor(mapper); + assertNull(mapperAccessor.getPropertyValue("defaultUrl")); + assertEquals("UTF-8", mapperAccessor.getPropertyValue("charset")); + assertEquals(true, mapperAccessor.getPropertyValue("extractPayload")); + } + + @Test + public void fullConfigWithMapper() throws Exception { + HttpOutboundEndpoint gateway = (HttpOutboundEndpoint) new DirectFieldAccessor( + this.fullConfigWithMapperEndpoint).getPropertyValue("handler"); + MessageChannel requestChannel = (MessageChannel) new DirectFieldAccessor( + this.fullConfigWithMapperEndpoint).getPropertyValue("inputChannel"); + assertEquals(this.applicationContext.getBean("requests"), requestChannel); + DirectFieldAccessor accessor = new DirectFieldAccessor(gateway); + Object replyChannel = accessor.getPropertyValue("outputChannel"); + assertNotNull(replyChannel); + assertEquals(this.applicationContext.getBean("replies"), replyChannel); + OutboundRequestMapper mapper = (OutboundRequestMapper) accessor.getPropertyValue("requestMapper"); + HttpRequestExecutor executor = (HttpRequestExecutor) accessor.getPropertyValue("requestExecutor"); + assertTrue(mapper instanceof DefaultOutboundRequestMapper); + assertTrue(executor instanceof SimpleHttpRequestExecutor); + Object mapperBean = this.applicationContext.getBean("mapper"); + assertEquals(mapperBean, mapper); + DirectFieldAccessor mapperAccessor = new DirectFieldAccessor(mapper); + assertEquals(new URL("http://localhost/test"), mapperAccessor.getPropertyValue("defaultUrl")); + assertEquals("UTF-8", mapperAccessor.getPropertyValue("charset")); + assertEquals(false, mapperAccessor.getPropertyValue("extractPayload")); + Object executorBean = this.applicationContext.getBean("executor"); + assertEquals(executorBean, executor); + Object sendTimeout = new DirectFieldAccessor( + accessor.getPropertyValue("channelTemplate")).getPropertyValue("sendTimeout"); + assertEquals(new Long("1234"), sendTimeout); + } + + @Test + public void fullConfigWithoutMapper() throws Exception { + HttpOutboundEndpoint gateway = (HttpOutboundEndpoint) new DirectFieldAccessor( + this.fullConfigWithoutMapperEndpoint).getPropertyValue("handler"); + MessageChannel requestChannel = (MessageChannel) new DirectFieldAccessor( + this.fullConfigWithoutMapperEndpoint).getPropertyValue("inputChannel"); + assertEquals(this.applicationContext.getBean("requests"), requestChannel); + DirectFieldAccessor accessor = new DirectFieldAccessor(gateway); + Object replyChannel = accessor.getPropertyValue("outputChannel"); + assertNotNull(replyChannel); + assertEquals(this.applicationContext.getBean("replies"), replyChannel); + OutboundRequestMapper mapper = (OutboundRequestMapper) accessor.getPropertyValue("requestMapper"); + HttpRequestExecutor executor = (HttpRequestExecutor) accessor.getPropertyValue("requestExecutor"); + assertTrue(mapper instanceof DefaultOutboundRequestMapper); + assertTrue(executor instanceof SimpleHttpRequestExecutor); + Object mapperBean = this.applicationContext.getBean("mapper"); + assertNotSame(mapperBean, mapper); + DirectFieldAccessor mapperAccessor = new DirectFieldAccessor(mapper); + assertEquals(new URL("http://localhost/test"), mapperAccessor.getPropertyValue("defaultUrl")); + assertEquals("UTF-8", mapperAccessor.getPropertyValue("charset")); + assertEquals(false, mapperAccessor.getPropertyValue("extractPayload")); + Object executorBean = this.applicationContext.getBean("executor"); + assertEquals(executorBean, executor); + Object sendTimeout = new DirectFieldAccessor( + accessor.getPropertyValue("channelTemplate")).getPropertyValue("sendTimeout"); + assertEquals(new Long("1234"), sendTimeout); + } + +} diff --git a/org.springframework.integration/src/main/java/org/springframework/integration/config/xml/AbstractConsumerEndpointParser.java b/org.springframework.integration/src/main/java/org/springframework/integration/config/xml/AbstractConsumerEndpointParser.java index 853e7e05d8..4dfba049a7 100644 --- a/org.springframework.integration/src/main/java/org/springframework/integration/config/xml/AbstractConsumerEndpointParser.java +++ b/org.springframework.integration/src/main/java/org/springframework/integration/config/xml/AbstractConsumerEndpointParser.java @@ -66,7 +66,7 @@ public abstract class AbstractConsumerEndpointParser extends AbstractBeanDefinit if (!element.hasAttribute(inputChannelAttributeName)) { if (!parserContext.isNested()) { parserContext.getReaderContext().error("The '" + inputChannelAttributeName - + "' attribute is required for top-level endpoint elements.", element); + + "' attribute is required for this top-level endpoint element.", element); } return handlerBeanDefinition; }