[jboss-user] [JBoss Seam] - Getting objects from conversation in a custom PhaseListener

JakeC do-not-reply at jboss.com
Thu Jul 5 19:24:14 EDT 2007

I need to make a URL that can download a binary file based on information stored in a long running conversation. I can get it to work fine once from a page, but the second time, it fails with:
ERROR [PhaseListenerManager] Exception in PhaseListener RESTORE_VIEW(1) afterPhase
  | java.lang.IllegalStateException: No active event context
  |         at org.jboss.seam.core.Manager.instance(Manager.java:267)

I'm pretty sure something I'm doing is ending the long running conversation, because if I just download a document once, then try to continue with my workflow by going to the next page, or even just refresh the current page, I get a similar error:
org.jboss.seam.NoConversationException: no long-running conversation for @Conversational bean

I'm pretty new at Seam, so if I'm making a colossal blunder, please be kind... :-) I've searched all over trying to figure out what is going on, but I just can't seem to find anything relevant.

Here is my PhaseListener:
package com.myco.myproj;
  | import java.util.Set;
  | import javax.faces.context.FacesContext;
  | import javax.faces.el.ValueBinding;
  | import javax.faces.event.PhaseEvent;
  | import javax.faces.event.PhaseId;
  | import javax.servlet.http.HttpServletResponse;
  | import org.jboss.seam.annotations.Name;
  | import org.jboss.seam.annotations.security.Restrict;
  | import org.jboss.seam.contexts.EntityBean;
  | import org.jboss.seam.core.Manager;
  | import org.jboss.seam.jsf.TransactionalSeamPhaseListener;
  | import org.jboss.seam.log.Log;
  | @Name("docPhaseListener")
  | @Restrict("#{identity.loggedIn}")
  | @SuppressWarnings("serial")
  | public class DocPhaseListener extends TransactionalSeamPhaseListener {
  | 	public final static int BUF_SIZE = 16384;
  | 	public final static String DOC_VIEW_ID = "/document/";
  | 	private static Log log = (Log) org.jboss.seam.log.Logging.getLog(DocPhaseListener.class);
  | 	private MyObject getMyObject(FacesContext context) {
  | 		MyObject myObject = null;
  | 		log.info("Manager.instance().getCurrentConversationId()="+Manager.instance().getCurrentConversationId());
  | 		ValueBinding vb = context.getApplication().createValueBinding("#{myObject}");
  | 		if(vb == null) {
  | 			log.info("vb is null!");
  | 		} else {
  | 			Object o = null;
  | 			log.info("vb type="+vb.getType(context)+", vb value="+(o=vb.getValue(context)));
  | 			if(o instanceof MyObject)
  | 				myObject = (MyObject) o;
  | 			else
  | 				log.info("Not MyObject!");
  | 		}
  | 		return myObject;
  | 	}
  | 	public void afterPhase(PhaseEvent event) {
  | 		super.afterPhase(event);
  | 		FacesContext context = event.getFacesContext();
  |         String viewId = context.getViewRoot().getViewId();
  |         int index = viewId.indexOf(DOC_VIEW_ID);
  |         if (PhaseId.RESTORE_VIEW.equals(event.getPhaseId()) && index != -1 && viewId.endsWith(".xhtml")) {
  |     		MyObject myObject = getMyObject(context);
  |     		if(myObject != null)
  |     			Util.handleDocumentRequest(context, myObject);
  |     		else {
  |     			// TODO: Handle bad requests better
  |     			((HttpServletResponse)context.getExternalContext().getResponse()).setContentType("application/octet-stream");
  |     			context.responseComplete();
  |     		}
  |         }
  | 	}
  | }

Since I'm extending TransactionalSeamPhaseListener (it seems necessary to get into the conversation the first time), and you can't have more than one SeamPhaseListener, I had to replace the existing one with mine, so my faces-config.xml looks like this:

  |       <!--phase-listener>org.jboss.seam.jsf.TransactionalSeamPhaseListener</phase-listener-->
  |       <phase-listener>com.medorder.mazama.DocumentPhaseListener</phase-listener>
  |    </lifecycle>

My UI is part of a rich:dataTable, and the column looks like this:

  |             <f:facet name="header">Download</f:facet>
  |             <h:outputLink value="document/download.seam?cid=#{conversation.id}&clr=true">
  | 	            <f:verbatim>Download</f:verbatim>
  |             </h:outputLink>
  |           </h:column>

Eventually, this URL will be called from an embedded Flash object, so I really need to use a PhaseListener. Can anyone tell me what I'm doing wrong to end the conversation?

I have also tried just implementing PhaseListener, and pulling the object from the SessionMap directly using the key "org.jboss.seam.CONVERSATION#xx$myObject", but I get the same kind of problem. The second time I access the EntityBean that is returned, the instance it points to is null.

Also, can someone confirm my suspicion that @Name and @Restrict are pointless to use on a PhaseListener? I don't think any injection has worked on it, and I'm pretty sure that it is not possible to use those on something that pretty much by definition lives outside the life-cycle.

View the original post : http://www.jboss.com/index.html?module=bb&op=viewtopic&p=4061067#4061067

Reply to the post : http://www.jboss.com/index.html?module=bb&op=posting&mode=reply&p=4061067

More information about the jboss-user mailing list