Do not start long-running conversations in direct calls to EJBs on async call
egoosen May 2, 2009 11:32 AMI'm getting the above exception after a long running process completes on a Conversation scoped POJO.
The process gets kicked off from a JSF page. I made it asynchronous because I'm using the a4j:progressBar, which polls this bean.
- Please advise me on when/how to start the conversation.
- How to handle exceptions thrown from an asynchronous call, currently no error appears to the user. (Added the try/catch now...so will test and see if it displays the error)
- I've packaged my application as an EAR running on JBoss-4.2.3GA, do I need to add the @Transcational annotation to the index() method?
Here's the code
@Name("indexer") @Scope(ScopeType.CONVERSATION) public class IndexerBean { @Logger private Log log; static final int BATCH_SIZE = 1000; private boolean enabled = false; private boolean buttonRendered = true; private float index; private long total; private long percentage = -1; @In EntityManager entityManager; @In FacesMessages facesMessages; private Stopwatch stopwatch = new Stopwatch(); @Asynchronous public String startProcess(IndexerBean indexerBean){ indexerBean.setEnabled(true); indexerBean.setButtonRendered(false); indexerBean.index(); return null; } @Begin(join=true) public void index() { stopwatch.start(); Session session = (Session)entityManager.getDelegate(); session.setFlushMode(FlushMode.MANUAL); //Disable flush operations session.setCacheMode(CacheMode.IGNORE); //Disable 2nd-level cache operations final FullTextSession ftSession = org.hibernate.search.Search.createFullTextSession( session ); indexAllClasses(ftSession, ProductInfo.class); stopwatch.stop(); setButtonRendered(true); } @SuppressWarnings("unchecked") @End private void indexAllClasses(FullTextSession fullTextSession, Class... entityTypes){ try { //First calculate the total records to index for (Class entityType : entityTypes){ Query query = entityManager.createQuery("select COUNT(e) from "+entityType.getName()+" e"); total += (Long)query.getSingleResult(); } //Perform indexing for (Class entityType : entityTypes){ //read the data from the database //Scrollable results will avoid loading too many objects in memory ScrollableResults results = fullTextSession.createCriteria( entityType ) .scroll( ScrollMode.FORWARD_ONLY ); while( results.next() ) { index++; percentage = (long)((index / total) * 100); fullTextSession.index( results.get(0) ); if (index % BATCH_SIZE == 0) { fullTextSession.clear(); } } } } catch (Throwable t) { log.error("Exception during indexing operation.", t); facesMessages.add(Severity.ERROR, "Exception during indexing operation. See log for details."); } } public long getPercentage() { return percentage; } public long getRunningTime(){ return stopwatch.getRunningTime(); } public boolean isEnabled() { return enabled; } public void setEnabled(boolean enabled) { this.enabled = enabled; } public boolean isButtonRendered() { return buttonRendered; } public void setButtonRendered(boolean buttonRendered) { this.buttonRendered = buttonRendered; } }