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;
}
}