Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
1.1k views
in Technique[技术] by (71.8m points)

email - Spring multiple imapAdapter

I am novice in Spring and I don't like code duplication. I wrote one ImapAdapter that works fine:

@Component
public class GeneralImapAdapter {

    private Logger logger = LoggerFactory.getLogger(getClass());

    @Autowired
    private EmailReceiverService emailReceiverService;

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

    @Bean
    @Value("imaps://<login>:<pass>@<url>:993/inbox")
    public MailReceiver imapMailReceiver(String imapUrl) {
        ImapMailReceiver imapMailReceiver = new ImapMailReceiver(imapUrl);
        imapMailReceiver.setShouldMarkMessagesAsRead(true);
        imapMailReceiver.setShouldDeleteMessages(false);
        // other setters here
        return imapMailReceiver;
    }

    @ServiceActivator(inputChannel = "emailChannel",  poller = @Poller(fixedDelay = "10000", taskExecutor = "asyncTaskExecutor"))
    public void emailMessageSource(javax.mail.Message message) {
        emailReceiverService.receive(message);
    }
}

But I want about 20 adapters like that, the only difference is imapUrl.

How to do that without code duplication?

Question&Answers:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

Use multiple application contexts, configured with properties.

This sample is an example; it uses XML for its configuration, but the same techniques apply with Java configuration.

If you need them to feed into a common emailReceiverService; make the individual adapter contexts child contexts; see the sample readme for pointers about how to do that.

EDIT:

Here's an example, with the service (and channel) in a shared parent context...

@Configuration
@EnableIntegration
public class MultiImapAdapter {

    public static void main(String[] args) throws Exception {
        AnnotationConfigApplicationContext parent = new AnnotationConfigApplicationContext(MultiImapAdapter.class);
        parent.setId("parent");
        String[] urls = { "imap://foo", "imap://bar" };
        List<ConfigurableApplicationContext> children = new ArrayList<ConfigurableApplicationContext>();
        int n = 0;
        for (String url : urls) {
            AnnotationConfigApplicationContext child = new AnnotationConfigApplicationContext();
            child.setId("child" + ++n);
            children.add(child);
            child.setParent(parent);
            child.register(GeneralImapAdapter.class);
            StandardEnvironment env = new StandardEnvironment();
            Properties props = new Properties();
            // populate properties for this adapter
            props.setProperty("imap.url", url);
            PropertiesPropertySource pps = new PropertiesPropertySource("imapprops", props);
            env.getPropertySources().addLast(pps);
            child.setEnvironment(env);
            child.refresh();
        }
        System.out.println("Hit enter to terminate");
        System.in.read();
        for (ConfigurableApplicationContext child : children) {
            child.close();
        }
        parent.close();
    }

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

    @Bean
    public EmailReceiverService emailReceiverService() {
        return new EmailReceiverService();
    }

}

and

@Configuration
@EnableIntegration
public class GeneralImapAdapter {

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

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

    @Bean
    @Value("${imap.url}")
    public MailReceiver imapMailReceiver(String imapUrl) {
//      ImapMailReceiver imapMailReceiver = new ImapMailReceiver(imapUrl);
//      imapMailReceiver.setShouldMarkMessagesAsRead(true);
//      imapMailReceiver.setShouldDeleteMessages(false);
//      // other setters here
//      return imapMailReceiver;
        MailReceiver receiver = mock(MailReceiver.class);
        Message message = mock(Message.class);
        when(message.toString()).thenReturn("Message from " + imapUrl);
        Message[] messages = new Message[] {message};
        try {
            when(receiver.receive()).thenReturn(messages);
        }
        catch (MessagingException e) {
            e.printStackTrace();
        }
        return receiver;
    }

}

and

@MessageEndpoint
public class EmailReceiverService {

    @ServiceActivator(inputChannel="emailChannel")
    public void handleMessage(javax.mail.Message message) {
        System.out.println(message);
    }

}

Hope that helps.

Notice that you don't need a poller on the service activator - use a DirectChannel and the service will be invoked on the poller executor thread - no need for another async handoff.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...