mercoledì 12 dicembre 2007

Seam and asynchronous email send

Over the past 3 months I've ported a JSF 1.1 business application written last year to Seam.
I'll talk of the hurdles I met, expecially porting from myfaces 1.1 to JSF RI 1.2, but now I just want to share with you my few successes.
In seam you can send an email using facelets as template engine. You can do it in same thread that displays you page, but due to high latency of smtp servers and other reasons, it's better to send it asynchronously.
My webapp is a POJO webapp, built upon spring,hibernate and seam.
All you have to do to spawn a new thread is to annotate your method with @Asynchronous, but watch out !
If your code was already working when doing it inside the display thread, now it surely will break.
WHY:
1) when seam spawns a thread, you loose the previous event/page/conversation context, so you have to put the objects you use inside the email template in a new context:

@Asynchronous
public void send(Account account) {
try {
Contexts.getConversationContext().set("account", account);
Renderer.instance().render("/email/activatedaccount.jsf");
} catch (Exception e) {
e.printStackTrace();
}

2) you loose your webapp relative paths too: if inside a display thread seam uses the ServletContext to retrieve the full path to your email template (and the resources it uses). Inside a spawned thread seam replaces the servletContext with a mockContext which resamble a ResourceBundle strategy to find resources in the classpath. So you have to move /email dir in WEB-INF/classes, togheter with the resources it uses (logo images etc..).

3) I happened to use one backing bean to process the page action, and call a send(account) method of the same class. When I marked that method @Asynchronous and debugged inside Eclipse, I saw the thread was the tomcat's one, not a new spawned one. I solved it moving the send method in another class and calling it in a new istance:


public String approve(Account account) {
...
architectMailer.send(account);
...
}

4) There's a bug (fixed in next release, perhaps already in 2.0.1 CR of tonight) about inline images not being displayed in thunderbird, but only attached. Don't go crazy, it's not your fault: wait for next release.

My 2 cents

Hope this helps

7 commenti:

Anonimo ha detto...

Thanks a lot for your article!!! It saved me a lot of time :)
Especially the hint with the mocked application context and the classloader workaround!
Greetings from Berlin
Stefan

Suraj Chhetry ha detto...

Thanks for the post.I am running out a problem .I have written the MailProcess class as you have mention but what about compnent.xml.What we have to write there? I am using seam 2.1.1 on tomcat

Garidan ha detto...

This is what you need to put in component.xml, to enable quartz scheduler and configure which email smtp server to use (look at seam doc/google for details):
<async:quartz-dispatcher/>

<mail:mail-session host="localhost" />

Suraj Chhetry ha detto...

Thanks for quick response and with the hint you provided i solved my problem,thanks alot.

Unknown ha detto...

Thanks for this. This worked just great!

Anonimo ha detto...

Nice dispatch and this post helped me alot in my college assignement. Say thank you you for your information.

Anonimo ha detto...

Aw, this was a really quality post. In theory I' d like to write like this too - taking time and real effort to make a good article... but what can I say... I procrastinate alot and never seem to get something done.