-
1. Re: Starting up Asynchronous Method at startup
pmuir Aug 20, 2007 11:45 AM (in response to damatrix)Which version of Seam?
-
2. Re: Starting up Asynchronous Method at startup
modoc Aug 20, 2007 12:14 PM (in response to damatrix)You can always use @Startup on the class and @Create on your method. I know this works.
Is there an advantage to using the postInitialize observer annotation instead? -
3. Re: Starting up Asynchronous Method at startup
damatrix Aug 21, 2007 4:35 AM (in response to damatrix)I'm using Seam 2.0.Beta and JBoss 4.2.1.GA.
I tried using @Startup and @Create but i realised that the contexts were not yet up and active at that stage of the application's startup. Putting my message in any context to be rendered by my email template throws an NPE at these stages. -
4. Re: Starting up Asynchronous Method at startup
gbc1 Aug 21, 2007 7:02 PM (in response to damatrix)Works like this:
In components.xml:<?xml version="1.0" encoding="UTF-8"?> <components xmlns="http://jboss.com/products/seam/components" ... xmlns:async="http://jboss.com/products/seam/async" ...> <async:quartz-dispatcher/> ...
Startup class:@Startup @Stateful @Scope(ScopeType.APPLICATION) @Name("startupManager") public class StartupManager implements StartupManagerLocal{ // create Interface @Logger private Log log; @In(create = true) private ProcessingActionLocal processingAction; private QuartzTriggerHandle handle = null; @Create public void create() { log.info("create(): called"); // init int delay = 20; // in seconds long interval = 1000 * delay; Calendar cal = Calendar.getInstance(); cal.setTime(new Date()); cal.add(Calendar.SECOND, delay); // create Processing long processingId = processingAction.createProcessing("serverJob"); // schedule job and save handler this.handle = processingAction.doServerJob(processingId, cal.getTime(), interval); log.info("create(): id: #0", processingId); } public QuartzTriggerHandle getHandle() { return this.handle ; } @Remove public void destroy() { } }
The ProcessingAction (The ProcessingBean is not shown here):@Stateful @Name("processingAction") public class ProcessingAction implements ProcessingActionLocal { // create Interface @Logger private Log log; @In private EntityManager entityManager; @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW) public long createProcessing(String string) { // create Processing ProcessingBean processing = new ProcessingBean(); // managed context entityManager.persist(processing); processing.setName("serverJob"); // return id return processing.getId(); } @Asynchronous @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW) public QuartzTriggerHandle doServerJob(long processingId, @Expiration Date date, @IntervalDuration Long interval) { log.info("doServerJob(): called"); // get bean ProcessingBean processing = entityManager.find(ProcessingBean.class, processingId); // if exists remove if (processing != null) { entityManager.remove(processing); log.info("doServerJob(): removed: id: #0", processingId); } else { // else stop server job try { startupManager.getHandle().cancel(); } catch (Exception e) { log.error("", e); } log.info("doServerJob(): stopped: id: #0", processingId); } // return new handle return new QuartzTriggerHandle("serverJob"); } @Remove public void destroy() { } }
Let me know if it worked out...
Greetz GHad -
5. Re: Starting up Asynchronous Method at startup
damatrix Aug 27, 2007 7:33 AM (in response to damatrix)Hi,
I tried your approach but had a problem which i expected will occur. Whiles seam is starting up, the contexts are not yet active. Since my email is made up of facelets templates, i could only send data to them when contexts are alive.
However i finally sorted it out.@Stateful @Scope(ScopeType.APPLICATION) @Name("startupManager") public class StartupManager implements StartupManagerLocal{ // create Interface @Create public void create() { TimerHandlerLocal timerHandler = (TimerHandlerLocal)Component.getInstance(TimerHandler.Class); timerHandler.sendNotifications; } @Remove public void destroy() { } }
The TimerHandler class:@Stateful @Name("timerhandler") public class TimerHandler implements TimerHandlerLocal { // create Interface @In private EntityManager entityManager; @In private MailRender mailRenderer; @Asynchronous @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW) public QuartzTriggerHandle createProcessing(String string) { List<Customer> customers = entityManager.createQuery("Select c from Customer where c.notification=true").getResultList(); Context.getSessionContext().set("customers",customers); mailRenderer.sendNotification(); Contexts.getSessionContxt().set("customers",null); return new QuartzTriggerHandle("notifications"); }
Lastly, find somewhere to inject the StartupMonitor so that it starts up on its own. I think your login/authentication class is the best place.@Scope(ScopeType.SESSION) @Name("authenticator") public class Authenticator implements java.io.Serializable { @In(create=true) StartupMonitor startupMonitor ... }
Since the StartupMonitor is APPLICATION scoped, it's @Create method will be called when the first person logs into the application and will run until applications is redeployed. -
6. Re: Starting up Asynchronous Method at startup
wiberto Sep 27, 2007 12:11 PM (in response to damatrix)I tried this approach and it works great. the only problem I'm seeing is that if I redeploy the EAR where the application is at after the AS is running I get a SAX error:
Caused by: org.jboss.xb.binding.JBossXBException: Failed to create a new SAX parser at org.jboss.xb.binding.parser.sax.SaxJBossXBParser.<init>(SaxJBossXBParser.java:96) at org.jboss.xb.binding.UnmarshallerImpl.<init>(UnmarshallerImpl.java:55) at org.jboss.xb.binding.UnmarshallerFactory$UnmarshallerFactoryImpl.newUnmarshaller(UnmarshallerFactory.java:96) ... 72 more Caused by: javax.xml.parsers.ParserConfigurationException: Feature 'http://apache.org/xml/features/xinclude' is not recognized. at org.apache.xerces.jaxp.SAXParserFactoryImpl.newSAXParser(Unknown Source) at org.jboss.xb.binding.parser.sax.SaxJBossXBParser.<init>(SaxJBossXBParser.java:92) ... 74 more
If I do a clean load of the application by starting the AS then it works fine.
Any idea why? Is it trying to use a different SAX parser after it has started?
Thanks,
Jose -
7. Re: Starting up Asynchronous Method at startup
damatrix Oct 1, 2007 6:28 AM (in response to damatrix)I'm no expert at this but i dont think that the problem is related to the startup of asynchronous methods.
SAX exception should be related to some xml file parsing exception, shouldn't it? -
8. Re: Starting up Asynchronous Method at startup
nickarls Oct 15, 2007 4:24 PM (in response to damatrix)I have a similar problem, I need a thread to run with a certain interval, regardless of if someone is logged in or not.
I can't get a reaction to postInitialize, @Startup works but when I try to reference the asynchronous bean I get a "Could not instantiate Seam component: org.jboss.seam.async.dispatcher" because "javax.naming.NameNotFoundException: X not bound" (X is the root of the ejb jndi-context?)
Tried various combinations of pojo and ejb for the asynchronous bean and I have <async:timer-service-dispatcher/> in my components.xml. Also tried various dependecies on the @Startup. Tried injecting the asynchronous bean, tried getting it from Components.
With and without chanting and waving a dead chicken across the keybord. -
9. Re: Starting up Asynchronous Method at startup
nickarls Oct 16, 2007 3:00 PM (in response to damatrix)Now accepting applicants for saving my day ;-)
Who can e.g paste in an example that starts up automagically and writes "ping" to System.out every second? -
10. Re: Starting up Asynchronous Method at startup
asavitsky Oct 16, 2007 4:33 PM (in response to damatrix)Here's what works for me (no EJB3 - plain POJO, Quartz and Tomcat, all deployed as WAR):
@Name ("scheduler") @Scope (ScopeType.APPLICATION) @Startup public class Scheduler { @In private IService service; @Logger private Log log; // set in seam.properties via scheduler.reminderCron private String reminderCron; public void setReminderCron(String reminderCron) { this.reminderCron = reminderCron; } @Create public void startJobs() { log.info("Reminder task started on #0, cron schedule is #1", new Date(), reminderCron); service.sendReminders(reminderCron); } }
public interface IService extends Serializable { void sendReminders(String cron); // other methods are omitted }
@Name ("service") @Scope (ScopeType.CONVERSATION) @AutoCreate @Transactional public class Service implements IService { @Asynchronous public void sendReminders(@IntervalCron String cron) { log.info("Reminder task activated on #0", new Date()); // plus whatever other functionality you need here... } }
The scheduler starts with the app, and runs every morning (as per cron expression, which you can change as needed) -
11. Re: Starting up Asynchronous Method at startup
nickarls Oct 17, 2007 2:00 AM (in response to damatrix)Thanks, I'll declare you the winner. Adding Quartz as a dependency isn't that bad considering it is working ootb...
-
12. Re: Starting up Asynchronous Method at startup
damatrix Oct 17, 2007 11:42 AM (in response to damatrix)I find your solution interesting.
However i need the contexts (mostly session and/or conversation) to be fully loaded so that i can pass data to them to be rendered by a facelet during email sending. Does your solution assume that the contexts will have been loaded by the time your method gets called? -
13. Re: Starting up Asynchronous Method at startup
hstang Oct 17, 2007 11:51 AM (in response to damatrix)What do you mean by "fully loaded"? Since the startup class in ASavitsky example is managed by Seam, I would assume that by the time execution begins all your contexts will be available to you.
-
14. Re: Starting up Asynchronous Method at startup
asavitsky Oct 17, 2007 11:53 AM (in response to damatrix)Application context would be initialized, but since this is an async invocation, there'd be no session or conversation context available (and, most likely, no HttpSession active, either), thus no Seam-email rendering. I believe there's a JIRA issue addressing just that (making FacesContext available for async calls) - until then, I switched temporarily to regular JavaMail