Message channels one or many?

ghz 1years ago ⋅ 2938 views

Question

I need to handle emails from about 30 addresses. I implement this in a way where all emails going to one DirectChannel and after to Receiver. In Receiver I can understand from what address is message comes, to do this I create CustomMessageSource that wraps javax.mail.Message to my own type that contains javax.mail.Message and some Enum. Looks like this is not a good decision, cause I can use @Transformer, but how can I use it if I have only 1 channel?

That was the first question.

Second question:

Should I use ONE channel and ONE receiver for all that addresses? Or better to have channel and receiver for each mail address? I don't understand Spring so deeply to feel the difference.

p.s. this question is continuation of [Spring multiple imapAdapter](https://stackoverflow.com/questions/32826864/spring-multiple- imapadapter/32827733#32827733)


Answer

In each child context, you can add a header enricher to set a custom header to the URL from the adapter; with the output channel being the shared channel to the shared service.

In the service, use void foo(Message emailMessage, @Header("myHeader") String url)

I would generally recommend using a single service unless the service needs to do radically different things based on the source.

EDIT :

I modified my answer to your previous question to enhance the original message with the url in a header; each instance has its own header enricher and they all route the enriched message to the common emailChannel.

@Configuration
@EnableIntegration
public class GeneralImapAdapter {

    @Value("${imap.url}")
    String imapUrl;

    @Bean
    public static PropertySourcesPlaceholderConfigurer pspc() {
        return new PropertySourcesPlaceholderConfigurer();
    }

    @Bean
    @InboundChannelAdapter(value = "enrichHeadersChannel", poller = @Poller(fixedDelay = "10000") )
    public MessageSource<javax.mail.Message> mailMessageSource(MailReceiver imapMailReceiver) {
        return new MailReceivingMessageSource(imapMailReceiver);
    }

    @Bean
    public MessageChannel enrichHeadersChannel() {
        return new DirectChannel();
    }

    @Bean
    @Transformer(inputChannel="enrichHeadersChannel", outputChannel="emailChannel")
    public HeaderEnricher enrichHeaders() {
        Map<String, ? extends HeaderValueMessageProcessor<?>> headersToAdd =
                Collections.singletonMap("emailUrl", new StaticHeaderValueMessageProcessor<>(this.imapUrl));
        HeaderEnricher enricher = new HeaderEnricher(headersToAdd);
        return enricher;
    }

    @Bean
    public MailReceiver imapMailReceiver() {
        MailReceiver receiver = mock(MailReceiver.class);
        Message message = mock(Message.class);
        when(message.toString()).thenReturn("Message from " + this.imapUrl);
        Message[] messages = new Message[] {message};
        try {
            when(receiver.receive()).thenReturn(messages);
        }
        catch (MessagingException e) {
            e.printStackTrace();
        }
        return receiver;
    }

}

...and I modified the receiving service so it gets access to the header...

@MessageEndpoint
public class EmailReceiverService {

    @ServiceActivator(inputChannel="emailChannel")
    public void handleMessage(Message message, @Header("emailUrl") String url) {
        System.out.println(message + " header:" + url);
    }

}

...hope that helps.

EDIT 2 :

And this one's a bit more sophisticated; it pulls the from from the payload and puts it in a header; not needed for your use case since you have the full message, but it illustrates the technique...

@Bean
@Transformer(inputChannel="enrichHeadersChannel", outputChannel="emailChannel")
public HeaderEnricher enrichHeaders() {
    Map<String, HeaderValueMessageProcessor<?>> headersToAdd = new HashMap<>();
    headersToAdd.put("emailUrl", new StaticHeaderValueMessageProcessor<String>(this.imapUrl));
    Expression expression = new SpelExpressionParser().parseExpression("payload.from[0].toString()");
    headersToAdd.put("from", new ExpressionEvaluatingHeaderValueMessageProcessor<>(expression, String.class));
    HeaderEnricher enricher = new HeaderEnricher(headersToAdd);
    return enricher;
}

and

@ServiceActivator(inputChannel="emailChannel")
public void handleMessage(Message message, @Header("emailUrl") String url,
                                           @Header("from") String from) {
    System.out.println(message + " header:" + url + " from:" + from);
}