-
1. Re: Conversation-scoped component's method annotated both @Destroy and @Asynchronous
kapitanpetko Aug 20, 2010 2:01 AM (in response to derekmd)Just call another component's async method, passing all the data you need to generate the email.
-
2. Re: Conversation-scoped component's method annotated both @Destroy and @Asynchronous
cash1981 Aug 20, 2010 3:47 AM (in response to derekmd)Its strange, but it seems to me that I have something similar. It only seems it is truly asynchronous when I use
Consider the following code:
mailService.sendOneTimepassword(user, theOnetimepass); Events.instance().raiseAsynchronousEvent("sendOneTimepassword", user, theOnetimepass); //mailService @Observer("sendOneTimepassword") @Asynchronous public void sendOneTimepassword(ProcessUser emailUser, String oneTimePassword) { Contexts.getEventContext().set(OnetimePasswordAction.EMAILUSER, emailUser); Contexts.getEventContext().set(OnetimePasswordAction.ONTIME_PW, oneTimePassword); renderer.render("/generic/email-template/onetimepassword-email-template.xhtml"); }
If I use the raiseAsynchronous method, it doesn't wait for the email to be sent. However, if I use the mailService.sendOneTimepassword it seems like it is synchronous. Any ideas why?
-
3. Re: Conversation-scoped component's method annotated both @Destroy and @Asynchronous
kapitanpetko Aug 20, 2010 4:54 AM (in response to derekmd)Yes, raising an async event is another idea that will work. When you call raiseAsynchronousEvent, what happens is that a one-off job that is executed immediately is scheduled. So the observer method is executed in this job's async context. As to why it doesn't work when called directly, I don't know, not enough info. As long as mailService is a Seam component and sendOneTimepassword is called from another component, the call should be intercepted and it should work. Are you calling it from @Destroy? Don't have the code now, but maybe there is some special handling for destroy methods.
-
4. Re: Conversation-scoped component's method annotated both @Destroy and @Asynchronous
cash1981 Aug 20, 2010 5:54 AM (in response to derekmd)
Nikolay Elenkov wrote on Aug 20, 2010 04:54:
Yes, raising an async event is another idea that will work. When you call raiseAsynchronousEvent, what happens is that a one-off job that is executed immediately is scheduled. So the observer method is executed in this job's async context. As to why it doesn't work when called directly, I don't know, not enough info. As long as mailService is a Seam component and sendOneTimepassword is called from another component, the call should be intercepted and it should work. Are you calling it from @Destroy? Don't have the code now, but maybe there is some special handling for destroy methods.Yes mailService is a Seam Statless EJB component and it is called from another component.
Maybe it doesn't work because I need to catch Exception (if mail server is not located) and present error message to the user.
This I think doesn't happen if I use raiseAsynch event. Or maybe I need to use the AsynchronousExceptionHandler.How do you solve exceptions?
-
5. Re: Conversation-scoped component's method annotated both @Destroy and @Asynchronous
kapitanpetko Aug 20, 2010 9:22 AM (in response to derekmd)Should work. Can you show some code? I handle exceptions in the async job (just dump to log), so no messages to user.
-
6. Re: Conversation-scoped component's method annotated both @Destroy and @Asynchronous
cash1981 Aug 20, 2010 9:27 AM (in response to derekmd)EmailService
/** * This service is responsible for sending emails asynchronously * @author Shervin Asgari * */ @Stateless @Local(MailService.class) @Name("mailService") @AutoCreate public class MailServiceImpl implements MailService { @In(create = true) private Renderer renderer; @Observer("sendOneTimepassword") @Asynchronous public void sendOneTimepassword(ProcessUser emailUser, String oneTimePassword) { Contexts.getEventContext().set(OnetimePasswordAction.EMAILUSER, emailUser); Contexts.getEventContext().set(OnetimePasswordAction.ONTIME_PW, oneTimePassword); renderer.render("/generic/email-template/onetimepassword-email-template.xhtml"); } }
Some other component:
I am not sure if the exception is catched here if I am raising asynchronous eventtry { mailService.sendOneTimepassword(user, theOnetimepass); //This is synchronous for some reason Events.instance().raiseAsynchronousEvent("sendOneTimepassword", user, theOnetimepass); //This is asynchronous } catch(Exception ejbEx) { ejbEx.printStackTrace(); statusMessages.add(ejbEx.getCause().getMessage()); StringWriter sw = new StringWriter(); PrintWriter pw = new PrintWriter(sw); ejbEx.printStackTrace(pw); //Put the stracktrace in StringWriter Events.instance().raiseAsynchronousEvent(SystemlogListener.EVENT_ADD_DETAILED_SYSTEMLOG, sw.toString()); Events.instance().raiseEvent("LoginSupport.sendingOneTimePassFailed"); return ProcessHandler.OUTCOME_FAILURE; }
-
7. Re: Conversation-scoped component's method annotated both @Destroy and @Asynchronous
cash1981 Aug 20, 2010 9:38 AM (in response to derekmd)I can confirm that the mailService.sendOneTimepassword(user, theOnetimepass); is handled synchronously and the other asyncrhonously.
Why, I have no idea... -
8. Re: Conversation-scoped component's method annotated both @Destroy and @Asynchronous
kapitanpetko Aug 20, 2010 10:12 AM (in response to derekmd)
Shervin Asgari wrote on Aug 20, 2010 09:38:
I can confirm that the mailService.sendOneTimepassword(user, theOnetimepass); is handled synchronously and the other asyncrhonously.
Why, I have no idea...Are you actually calling both? If you raise an async event, there will be no exception, as sendOneTimepassword() will be called on another thread. Still don't see why it doesn't work... Who/what is triggering the 'other component'?
-
9. Re: Conversation-scoped component's method annotated both @Destroy and @Asynchronous
cash1981 Aug 20, 2010 10:19 AM (in response to derekmd)No of course I am not calling them both :-)
I just wrote them there for your convenience.Actually there will be exception. Haven't you seen the AsyncrhonousExceptionHandler in seam?
All you need to do is:@Scope(ScopeType.STATELESS) @Name("org.jboss.seam.async.asynchronousExceptionHandler") public class MyAsynchronousExceptionHandler extends AsynchronousExceptionHandler { @Logger private Log log; @In private QuartzTriggerHandle timer; @Override public void handleException(Exception ex) { StringWriter sw = new StringWriter(); PrintWriter pw = new PrintWriter(sw); ex.printStackTrace(pw); //Put the stracktrace in StringWriter try { log.warn("Cancelling timer job with name #0", timer.getTrigger().getFullName()); timer.cancel(); } catch (SchedulerException e1) { log.error("Could not cancel asynchronous job"); e1.printStackTrace(); sw.append("Could not cancel asyncrhonous job " + e1.getMessage()); } //Here you can log the exception if you want }
-
10. Re: Conversation-scoped component's method annotated both @Destroy and @Asynchronous
kapitanpetko Aug 20, 2010 10:56 AM (in response to derekmd)
Shervin Asgari wrote on Aug 20, 2010 10:19:
Actually there will be exception. Haven't you seen the AsyncrhonousExceptionHandler in seam?I meant, you can't catch it with the code you posted.