From 4b5bbb6412420031b4cb11868d3fb4e18d504ef8 Mon Sep 17 00:00:00 2001 From: Artem Bilan Date: Wed, 27 Aug 2014 14:08:37 +0300 Subject: [PATCH] DSL: Add `enrichHeaders(Map)` EIP-method * Introduce `MapBuilder` and its custom inheritor - `MailHeadersBuilder` * Add `HeaderEnricherSpec.headers(MapBuilder)` and `.headers(Map)` * Change `MailTests` to use new `Mail.headers()` and new `IntegrationFlowDefinition.enrichHeaders(MapBuilder)` * Change `mailapi` dependency to the IO's `javax.mail` Polishing - Add headerExpressions() More Polishing - Add Configurer Polishing - PR Comments - Move MapBuilderConfigurer to superclass. - Move PropertiesBuilderConfigurer into PropertiesBuilder. --- spring-integration-java-dsl/build.gradle | 2 +- .../integration/dsl/HeaderEnricherSpec.java | 43 +++++++ .../dsl/IntegrationFlowDefinition.java | 34 ++++++ .../dsl/mail/ImapIdleChannelAdapterSpec.java | 2 +- .../integration/dsl/mail/Mail.java | 6 +- .../dsl/mail/MailHeadersBuilder.java | 112 ++++++++++++++++++ .../mail/MailInboundChannelAdapterSpec.java | 2 +- .../mail/MailSendingMessageHandlerSpec.java | 2 +- .../integration/dsl/support/MapBuilder.java | 53 +++++++++ .../dsl/support/PropertiesBuilder.java | 7 ++ ...gurer.java => StringStringMapBuilder.java} | 10 +- .../integration/dsl/test/mail/MailTests.java | 15 ++- 12 files changed, 270 insertions(+), 18 deletions(-) create mode 100644 spring-integration-java-dsl/src/main/java/org/springframework/integration/dsl/mail/MailHeadersBuilder.java create mode 100644 spring-integration-java-dsl/src/main/java/org/springframework/integration/dsl/support/MapBuilder.java rename spring-integration-java-dsl/src/main/java/org/springframework/integration/dsl/support/{PropertiesConfigurer.java => StringStringMapBuilder.java} (78%) diff --git a/spring-integration-java-dsl/build.gradle b/spring-integration-java-dsl/build.gradle index 8af910a..1626b3b 100644 --- a/spring-integration-java-dsl/build.gradle +++ b/spring-integration-java-dsl/build.gradle @@ -92,7 +92,7 @@ dependencies { testRuntime("org.apache.activemq:activemq-kahadb-store:$activeMqVersion") { exclude group: "org.springframework" } - testRuntime "com.sun.mail:mailapi:$mailVersion" + testRuntime "com.sun.mail:javax.mail:$mailVersion" testRuntime "com.sun.mail:smtp:$mailVersion" testRuntime "com.sun.mail:pop3:$mailVersion" testRuntime "com.sun.mail:imap:$mailVersion" diff --git a/spring-integration-java-dsl/src/main/java/org/springframework/integration/dsl/HeaderEnricherSpec.java b/spring-integration-java-dsl/src/main/java/org/springframework/integration/dsl/HeaderEnricherSpec.java index 1cca767..20d1ef8 100644 --- a/spring-integration-java-dsl/src/main/java/org/springframework/integration/dsl/HeaderEnricherSpec.java +++ b/spring-integration-java-dsl/src/main/java/org/springframework/integration/dsl/HeaderEnricherSpec.java @@ -18,11 +18,16 @@ package org.springframework.integration.dsl; import java.util.HashMap; import java.util.Map; +import java.util.Map.Entry; +import org.springframework.expression.Expression; import org.springframework.expression.spel.standard.SpelExpressionParser; import org.springframework.integration.context.IntegrationContextUtils; import org.springframework.integration.dsl.core.IntegrationComponentSpec; import org.springframework.integration.dsl.support.BeanNameMessageProcessor; +import org.springframework.integration.dsl.support.MapBuilder; +import org.springframework.integration.dsl.support.MapBuilder.MapBuilderConfigurer; +import org.springframework.integration.dsl.support.StringStringMapBuilder; import org.springframework.integration.handler.ExpressionEvaluatingMessageProcessor; import org.springframework.integration.handler.MessageProcessor; import org.springframework.integration.transformer.HeaderEnricher; @@ -34,6 +39,7 @@ import org.springframework.util.Assert; /** * @author Artem Bilan + * @author Gary Russell */ public class HeaderEnricherSpec extends IntegrationComponentSpec { @@ -70,6 +76,43 @@ public class HeaderEnricherSpec extends IntegrationComponentSpec(beanName, methodName)); } + public HeaderEnricherSpec headers(MapBuilder headers) { + return headers(headers.get()); + } + + public HeaderEnricherSpec headers(Map headers) { + Assert.notNull(headers); + for (Entry entry : headers.entrySet()) { + String name = entry.getKey(); + Object value = entry.getValue(); + if (value instanceof Expression) { + header(name, new ExpressionEvaluatingHeaderValueMessageProcessor((Expression) value, null)); + } + else { + header(name, value); + } + } + return this; + } + + public HeaderEnricherSpec headerExpressions(MapBuilder headers) { + return headerExpressions(headers.get()); + } + + public HeaderEnricherSpec headerExpressions(MapBuilderConfigurer configurer) { + StringStringMapBuilder builder = new StringStringMapBuilder(); + configurer.configure(builder); + return headerExpressions(builder.get()); + } + + public HeaderEnricherSpec headerExpressions(Map headers) { + Assert.notNull(headers); + for (Entry entry : headers.entrySet()) { + header(entry.getKey(), new ExpressionEvaluatingHeaderValueMessageProcessor(entry.getValue(), null)); + } + return this; + } + public HeaderEnricherSpec header(String name, V value) { return this.header(name, value, null); } diff --git a/spring-integration-java-dsl/src/main/java/org/springframework/integration/dsl/IntegrationFlowDefinition.java b/spring-integration-java-dsl/src/main/java/org/springframework/integration/dsl/IntegrationFlowDefinition.java index fc72b9c..a3123c9 100644 --- a/spring-integration-java-dsl/src/main/java/org/springframework/integration/dsl/IntegrationFlowDefinition.java +++ b/spring-integration-java-dsl/src/main/java/org/springframework/integration/dsl/IntegrationFlowDefinition.java @@ -18,6 +18,7 @@ package org.springframework.integration.dsl; import java.util.Collection; import java.util.LinkedHashSet; +import java.util.Map; import java.util.Set; import org.springframework.beans.factory.BeanCreationException; @@ -40,6 +41,7 @@ import org.springframework.integration.dsl.support.FixedSubscriberChannelPrototy import org.springframework.integration.dsl.support.GenericHandler; import org.springframework.integration.dsl.support.GenericRouter; import org.springframework.integration.dsl.support.GenericSplitter; +import org.springframework.integration.dsl.support.MapBuilder; import org.springframework.integration.dsl.support.MessageChannelReference; import org.springframework.integration.expression.ControlBusMethodFilter; import org.springframework.integration.filter.ExpressionEvaluatingSelector; @@ -76,6 +78,7 @@ import org.springframework.util.StringUtils; /** * @author Artem Bilan + * @author Gary Russell */ public abstract class IntegrationFlowDefinition> { @@ -286,6 +289,37 @@ public abstract class IntegrationFlowDefinition headers) { + return enrichHeaders(headers, null); + } + + public B enrichHeaders(MapBuilder headers, + EndpointConfigurer> endpointConfigurer) { + return enrichHeaders(headers.get(), endpointConfigurer); + } + + /** + * Accept a {@link Map} of values to be used for the + * {@link org.springframework.messaging.Message} header enrichment. + * {@code values} can apply an {@link org.springframework.expression.Expression} + * to be evaluated against a request {@link org.springframework.messaging.Message}. + * @param headers the Map of headers to enrich. + * @return this. + */ + public B enrichHeaders(Map headers) { + return enrichHeaders(headers, null); + } + + public B enrichHeaders(final Map headers, + EndpointConfigurer> endpointConfigurer) { + return enrichHeaders(new ComponentConfigurer() { + @Override + public void configure(HeaderEnricherSpec spec) { + spec.headers(headers); + } + }, endpointConfigurer); + } + public B enrichHeaders(ComponentConfigurer headerEnricherConfigurer) { return this.enrichHeaders(headerEnricherConfigurer, null); } diff --git a/spring-integration-java-dsl/src/main/java/org/springframework/integration/dsl/mail/ImapIdleChannelAdapterSpec.java b/spring-integration-java-dsl/src/main/java/org/springframework/integration/dsl/mail/ImapIdleChannelAdapterSpec.java index 8325876..79d0391 100644 --- a/spring-integration-java-dsl/src/main/java/org/springframework/integration/dsl/mail/ImapIdleChannelAdapterSpec.java +++ b/spring-integration-java-dsl/src/main/java/org/springframework/integration/dsl/mail/ImapIdleChannelAdapterSpec.java @@ -29,7 +29,7 @@ import org.aopalliance.aop.Advice; import org.springframework.integration.dsl.core.ComponentsRegistration; import org.springframework.integration.dsl.core.MessageProducerSpec; import org.springframework.integration.dsl.support.PropertiesBuilder; -import org.springframework.integration.dsl.support.PropertiesConfigurer; +import org.springframework.integration.dsl.support.PropertiesBuilder.PropertiesConfigurer; import org.springframework.integration.mail.ImapIdleChannelAdapter; import org.springframework.integration.mail.ImapMailReceiver; import org.springframework.integration.mail.SearchTermStrategy; diff --git a/spring-integration-java-dsl/src/main/java/org/springframework/integration/dsl/mail/Mail.java b/spring-integration-java-dsl/src/main/java/org/springframework/integration/dsl/mail/Mail.java index 21e5c9d..75707e9 100644 --- a/spring-integration-java-dsl/src/main/java/org/springframework/integration/dsl/mail/Mail.java +++ b/spring-integration-java-dsl/src/main/java/org/springframework/integration/dsl/mail/Mail.java @@ -19,7 +19,7 @@ import org.springframework.integration.mail.ImapMailReceiver; /** * @author Gary Russell - * + * @author Artem Bilan */ public class Mail { @@ -56,6 +56,10 @@ public class Mail { return imapIdleAdapter(new ImapMailReceiver(url)); } + public static MailHeadersBuilder headers() { + return new MailHeadersBuilder(); + } + private static ImapIdleChannelAdapterSpec imapIdleAdapter(ImapMailReceiver imapMailReceiver) { return new ImapIdleChannelAdapterSpec(imapMailReceiver); } diff --git a/spring-integration-java-dsl/src/main/java/org/springframework/integration/dsl/mail/MailHeadersBuilder.java b/spring-integration-java-dsl/src/main/java/org/springframework/integration/dsl/mail/MailHeadersBuilder.java new file mode 100644 index 0000000..8696e52 --- /dev/null +++ b/spring-integration-java-dsl/src/main/java/org/springframework/integration/dsl/mail/MailHeadersBuilder.java @@ -0,0 +1,112 @@ +/* + * Copyright 2014 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.dsl.mail; + +import org.springframework.integration.dsl.support.MapBuilder; +import org.springframework.integration.mail.MailHeaders; + +/** + * @author Artem Bilan + * @author Gary Russell + */ +public class MailHeadersBuilder extends MapBuilder { + + MailHeadersBuilder() { + } + + public MailHeadersBuilder subject(String subject) { + return put(MailHeaders.SUBJECT, subject); + } + + public MailHeadersBuilder subjectExpression(String subject) { + return putExpression(MailHeaders.SUBJECT, subject); + } + + public MailHeadersBuilder to(String to) { + return put(MailHeaders.TO, to); + } + + public MailHeadersBuilder toExpression(String to) { + return putExpression(MailHeaders.TO, to); + } + + public MailHeadersBuilder cc(String cc) { + return put(MailHeaders.CC, cc); + } + + public MailHeadersBuilder ccExpression(String cc) { + return putExpression(MailHeaders.CC, cc); + } + + public MailHeadersBuilder bcc(String bcc) { + return put(MailHeaders.BCC, bcc); + } + + public MailHeadersBuilder bccExpression(String bcc) { + return putExpression(MailHeaders.BCC, bcc); + } + + public MailHeadersBuilder from(String from) { + return put(MailHeaders.FROM, from); + } + + public MailHeadersBuilder fromExpression(String from) { + return putExpression(MailHeaders.FROM, from); + } + + public MailHeadersBuilder replyTo(String replyTo) { + return put(MailHeaders.REPLY_TO, replyTo); + } + + public MailHeadersBuilder replyToExpression(String replyTo) { + return putExpression(MailHeaders.REPLY_TO, replyTo); + } + + /** + * @param multipartMode header value + * @return this + * @see org.springframework.mail.javamail.MimeMessageHelper + */ + public MailHeadersBuilder multipartMode(int multipartMode) { + return put(MailHeaders.MULTIPART_MODE, multipartMode); + } + + public MailHeadersBuilder multipartModeExpression(String multipartMode) { + return putExpression(MailHeaders.MULTIPART_MODE, multipartMode); + } + + public MailHeadersBuilder attachmentFilename(String attachmentFilename) { + return put(MailHeaders.ATTACHMENT_FILENAME, attachmentFilename); + } + + public MailHeadersBuilder attachmentFilenameExpression(String attachmentFilename) { + return putExpression(MailHeaders.ATTACHMENT_FILENAME, attachmentFilename); + } + + public MailHeadersBuilder contentType(String contentType) { + return put(MailHeaders.CONTENT_TYPE, contentType); + } + + public MailHeadersBuilder contentTypeExpression(String contentType) { + return putExpression(MailHeaders.CONTENT_TYPE, contentType); + } + + private MailHeadersBuilder putExpression(String key, String expression) { + return put(key, PARSER.parseExpression(expression)); + } + +} diff --git a/spring-integration-java-dsl/src/main/java/org/springframework/integration/dsl/mail/MailInboundChannelAdapterSpec.java b/spring-integration-java-dsl/src/main/java/org/springframework/integration/dsl/mail/MailInboundChannelAdapterSpec.java index d2defb0..3a02519 100644 --- a/spring-integration-java-dsl/src/main/java/org/springframework/integration/dsl/mail/MailInboundChannelAdapterSpec.java +++ b/spring-integration-java-dsl/src/main/java/org/springframework/integration/dsl/mail/MailInboundChannelAdapterSpec.java @@ -25,7 +25,7 @@ import javax.mail.Session; import org.springframework.integration.dsl.core.ComponentsRegistration; import org.springframework.integration.dsl.core.MessageSourceSpec; import org.springframework.integration.dsl.support.PropertiesBuilder; -import org.springframework.integration.dsl.support.PropertiesConfigurer; +import org.springframework.integration.dsl.support.PropertiesBuilder.PropertiesConfigurer; import org.springframework.integration.mail.AbstractMailReceiver; import org.springframework.integration.mail.MailReceivingMessageSource; diff --git a/spring-integration-java-dsl/src/main/java/org/springframework/integration/dsl/mail/MailSendingMessageHandlerSpec.java b/spring-integration-java-dsl/src/main/java/org/springframework/integration/dsl/mail/MailSendingMessageHandlerSpec.java index 1cad97a..37514e6 100644 --- a/spring-integration-java-dsl/src/main/java/org/springframework/integration/dsl/mail/MailSendingMessageHandlerSpec.java +++ b/spring-integration-java-dsl/src/main/java/org/springframework/integration/dsl/mail/MailSendingMessageHandlerSpec.java @@ -21,7 +21,7 @@ import javax.activation.FileTypeMap; import org.springframework.integration.dsl.core.MessageHandlerSpec; import org.springframework.integration.dsl.support.PropertiesBuilder; -import org.springframework.integration.dsl.support.PropertiesConfigurer; +import org.springframework.integration.dsl.support.PropertiesBuilder.PropertiesConfigurer; import org.springframework.integration.mail.MailSendingMessageHandler; import org.springframework.mail.javamail.JavaMailSenderImpl; diff --git a/spring-integration-java-dsl/src/main/java/org/springframework/integration/dsl/support/MapBuilder.java b/spring-integration-java-dsl/src/main/java/org/springframework/integration/dsl/support/MapBuilder.java new file mode 100644 index 0000000..01715c1 --- /dev/null +++ b/spring-integration-java-dsl/src/main/java/org/springframework/integration/dsl/support/MapBuilder.java @@ -0,0 +1,53 @@ +/* + * Copyright 2014 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.dsl.support; + +import java.util.HashMap; +import java.util.Map; + +import org.springframework.expression.spel.standard.SpelExpressionParser; + +/** + * @author Artem Bilan + */ +public class MapBuilder, K, V> { + + protected final static SpelExpressionParser PARSER = new SpelExpressionParser(); + + private final Map map = new HashMap(); + + public B put(K key, V value) { + this.map.put(key, value); + return _this(); + } + + public Map get() { + return this.map; + } + + @SuppressWarnings("unchecked") + protected final B _this() { + return (B) this; + } + + public interface MapBuilderConfigurer, K, V> { + + void configure(MapBuilder builder); + + } + +} diff --git a/spring-integration-java-dsl/src/main/java/org/springframework/integration/dsl/support/PropertiesBuilder.java b/spring-integration-java-dsl/src/main/java/org/springframework/integration/dsl/support/PropertiesBuilder.java index 07bb020..2af207e 100644 --- a/spring-integration-java-dsl/src/main/java/org/springframework/integration/dsl/support/PropertiesBuilder.java +++ b/spring-integration-java-dsl/src/main/java/org/springframework/integration/dsl/support/PropertiesBuilder.java @@ -20,6 +20,7 @@ import java.util.Properties; /** * @author Gary Russell + * @author Artem Bilan * */ public class PropertiesBuilder { @@ -35,4 +36,10 @@ public class PropertiesBuilder { return this.properties; } + public interface PropertiesConfigurer { + + void configure(PropertiesBuilder propertiesBuilder); + + } + } diff --git a/spring-integration-java-dsl/src/main/java/org/springframework/integration/dsl/support/PropertiesConfigurer.java b/spring-integration-java-dsl/src/main/java/org/springframework/integration/dsl/support/StringStringMapBuilder.java similarity index 78% rename from spring-integration-java-dsl/src/main/java/org/springframework/integration/dsl/support/PropertiesConfigurer.java rename to spring-integration-java-dsl/src/main/java/org/springframework/integration/dsl/support/StringStringMapBuilder.java index 92562f1..b2bd375 100644 --- a/spring-integration-java-dsl/src/main/java/org/springframework/integration/dsl/support/PropertiesConfigurer.java +++ b/spring-integration-java-dsl/src/main/java/org/springframework/integration/dsl/support/StringStringMapBuilder.java @@ -13,14 +13,14 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package org.springframework.integration.dsl.support; /** - * @author Artem Bilan + * A map builder creating a map with String keys and values. + * + * @author Gary Russell + * */ -public interface PropertiesConfigurer { - - void configure(PropertiesBuilder propertiesBuilder); +public class StringStringMapBuilder extends MapBuilder { } diff --git a/spring-integration-java-dsl/src/test/java/org/springframework/integration/dsl/test/mail/MailTests.java b/spring-integration-java-dsl/src/test/java/org/springframework/integration/dsl/test/mail/MailTests.java index 3225fc4..dabfe97 100644 --- a/spring-integration-java-dsl/src/test/java/org/springframework/integration/dsl/test/mail/MailTests.java +++ b/spring-integration-java-dsl/src/test/java/org/springframework/integration/dsl/test/mail/MailTests.java @@ -129,18 +129,14 @@ public class MailTests { private ImapIdleChannelAdapter imapIdleAdapter; @Test - public void testOutbound() throws Exception { + public void testSmtp() throws Exception { assertEquals("localhost", TestUtils.getPropertyValue(this.sendMailHandler, "mailSender.host")); Properties javaMailProperties = TestUtils.getPropertyValue(this.sendMailHandler, "mailSender.javaMailProperties", Properties.class); assertEquals("true", javaMailProperties.getProperty("mail.debug")); - this.sendMailChannel.send(MessageBuilder.withPayload("foo") - .setHeader(MailHeaders.SUBJECT, "foo") - .setHeader(MailHeaders.FROM, "foo@bar") - .setHeader(MailHeaders.TO, "bar@baz") - .build()); + this.sendMailChannel.send(MessageBuilder.withPayload("foo").build()); int n = 0; while (n++ < 100 && smtpServer.getMessages().size() == 0) { @@ -163,8 +159,8 @@ public class MailTests { assertNotNull(message); MimeMessage mm = (MimeMessage) message.getPayload(); assertEquals("foo@bar", mm.getRecipients(RecipientType.TO)[0].toString()); - assertEquals("bar@baz", mm.getFrom()[0].toString()); - assertEquals("Test Email", mm.getSubject()); + assertEquals("bar@baz", message.getHeaders().get(MailHeaders.FROM)); + assertEquals("Test Email", message.getHeaders().get(MailHeaders.SUBJECT)); assertEquals("foo\r\n", mm.getContent()); } @@ -199,6 +195,7 @@ public class MailTests { @Bean public IntegrationFlow sendMailFlow() { return IntegrationFlows.from("sendMailChannel") + .enrichHeaders(Mail.headers().subject("foo").from("foo@bar").to("bar@baz")) .handle(Mail.outboundAdapter("localhost") .port(smtpPort) .credentials("user", "pw") @@ -215,6 +212,8 @@ public class MailTests { .javaMailProperties(p -> p.put("mail.debug", "true")), e -> e.autoStartup(true) .poller(Pollers.fixedDelay(1000))) + .enrichHeaders(s -> s.headerExpressions(c -> c.put(MailHeaders.SUBJECT, "payload.subject") + .put(MailHeaders.FROM, "payload.from[0].toString()"))) .channel(MessageChannels.queue("pop3Channel")) .get(); }