package org.jboss.seam.servlet; import java.io.IOException; import java.util.concurrent.atomic.AtomicInteger; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import org.jboss.seam.contexts.Lifecycle; import org.jboss.seam.contexts.ServletLifecycle; import org.jboss.seam.core.ConversationPropagation; import org.jboss.seam.core.Manager; import org.jboss.seam.log.LogProvider; import org.jboss.seam.log.Logging; import org.jboss.seam.web.ServletContexts; /** * Perform work in a full set of Seam contexts * * @author Gavin King * @author Marek Novotny * */ public abstract class ContextualHttpServletRequest { private static final LogProvider log = Logging.getLogProvider(ContextualHttpServletRequest.class); private final HttpServletRequest request; private static ThreadLocal<AtomicInteger> count = new ThreadLocal<AtomicInteger>(); public ContextualHttpServletRequest(HttpServletRequest request) { this.request = request; } public abstract void process() throws Exception; public void run() throws ServletException, IOException { log.debug("beginning request"); // Force creation of the session if (request.getSession(false) == null) { request.getSession(true); } // Begin request and Seam life cycle only if it is not nested // ContextualHttpServletRequest if (getCounterValue() == 0) { ServletLifecycle.beginRequest(request); ServletContexts.instance().setRequest(request); restoreConversationId(); Manager.instance().restoreConversation(); ServletLifecycle.resumeConversation(request); handleConversationPropagation(); } try { incrementCounterValue(); process(); decrementCounterValue(); // End request only if it is not nested ContextualHttpServletRequest if (getCounterValue() == 0) { //TODO: conversation timeout Manager.instance().endRequest( new ServletRequestSessionMap(request) ); ServletLifecycle.endRequest(request); removeCounter(); } } catch (IOException ioe) { removeCounter(); Lifecycle.endRequest(); log.debug("ended request due to exception"); throw ioe; } catch (ServletException se) { removeCounter(); Lifecycle.endRequest(); log.debug("ended request due to exception"); throw se; } catch (Exception e) { removeCounter(); Lifecycle.endRequest(); log.debug("ended request due to exception"); throw new ServletException(e); } finally { log.debug("ended request"); } } protected void handleConversationPropagation() { Manager.instance().handleConversationPropagation( request.getParameterMap() ); } protected void restoreConversationId() { ConversationPropagation.instance().restoreConversationId( request.getParameterMap() ); } /* * Getter for ThreadLocal counter value */ private int getCounterValue() { AtomicInteger i = count.get(); if (i == null || i.intValue() < 0) { log.trace("Getting 0" ); return 0; } else { log.trace("Getting " + i.intValue()); return i.intValue(); } } /* * Increments ThreadLocal counter value */ private void incrementCounterValue() { AtomicInteger i = count.get(); if (i == null || i.intValue() < 0) { i = new AtomicInteger(0); count.set(i); } i.incrementAndGet(); log.trace("Incrementing to " + count.get()); } /* * Decrements ThreadLocal counter value */ private void decrementCounterValue() { AtomicInteger i = count.get(); if (i == null) { log.trace("OOps, something removed counter befor end of request!"); // we should never get here... throw new IllegalStateException("Counter for nested ContextualHttpServletRequest was removed before it should be!"); } if (i.intValue() > 0) { i.decrementAndGet(); log.trace("Decrementing to " + count.get()); } } /* * Removes ThreadLocal counter */ private void removeCounter() { log.trace("Removing ThreadLocal counter"); count.remove(); } }