[jboss-cvs] jboss-seam/src/main/org/jboss/seam/jsf ...

Gavin King gavin.king at jboss.com
Fri Jun 15 03:24:56 EDT 2007


  User: gavin   
  Date: 07/06/15 03:24:56

  Modified:    src/main/org/jboss/seam/jsf     SeamPhaseListener.java
  Removed:     src/main/org/jboss/seam/jsf    
                        SeamPortletPhaseListener.java
                        TransactionalSeamPhaseListener.java
                        TransactionalSeamPortletPhaseListener.java
  Log:
  auto-install phaselistener
  
  Revision  Changes    Path
  1.101     +501 -48   jboss-seam/src/main/org/jboss/seam/jsf/SeamPhaseListener.java
  
  (In the diff below, changes in quantity of whitespace are not shown.)
  
  Index: SeamPhaseListener.java
  ===================================================================
  RCS file: /cvsroot/jboss/jboss-seam/src/main/org/jboss/seam/jsf/SeamPhaseListener.java,v
  retrieving revision 1.100
  retrieving revision 1.101
  diff -u -b -r1.100 -r1.101
  --- SeamPhaseListener.java	30 May 2007 18:53:46 -0000	1.100
  +++ SeamPhaseListener.java	15 Jun 2007 07:24:56 -0000	1.101
  @@ -1,24 +1,49 @@
   /*
  - * JBoss, Home of Professional Open Source
  - *
  - * Distributable under LGPL license.
  - * See terms of license at gnu.org.
  - */
  + * JBoss, Home of Professional Open Source
  + *
  + * Distributable under LGPL license.
  + * See terms of license at gnu.org.
  + */
   package org.jboss.seam.jsf;
   
  +import static javax.faces.event.PhaseId.ANY_PHASE;
   import static javax.faces.event.PhaseId.INVOKE_APPLICATION;
   import static javax.faces.event.PhaseId.PROCESS_VALIDATIONS;
   import static javax.faces.event.PhaseId.RENDER_RESPONSE;
   import static javax.faces.event.PhaseId.RESTORE_VIEW;
   
  +import java.lang.reflect.Method;
  +import java.util.Map;
  +
  +import javax.faces.application.FacesMessage;
  +import javax.faces.context.ExternalContext;
   import javax.faces.context.FacesContext;
   import javax.faces.event.PhaseEvent;
  +import javax.faces.event.PhaseId;
  +import javax.faces.event.PhaseListener;
   
  +import org.jboss.seam.Seam;
  +import org.jboss.seam.contexts.Context;
  +import org.jboss.seam.contexts.Contexts;
   import org.jboss.seam.contexts.Lifecycle;
  +import org.jboss.seam.core.ConversationList;
  +import org.jboss.seam.core.ConversationPropagation;
  +import org.jboss.seam.core.ConversationStack;
  +import org.jboss.seam.core.Events;
   import org.jboss.seam.core.Exceptions;
   import org.jboss.seam.core.FacesMessages;
  +import org.jboss.seam.core.FacesPage;
  +import org.jboss.seam.core.Init;
  +import org.jboss.seam.core.Manager;
  +import org.jboss.seam.core.Pageflow;
  +import org.jboss.seam.core.Pages;
  +import org.jboss.seam.core.PersistenceContexts;
  +import org.jboss.seam.core.Switcher;
  +import org.jboss.seam.core.Validation;
   import org.jboss.seam.log.LogProvider;
   import org.jboss.seam.log.Logging;
  +import org.jboss.seam.transaction.Transaction;
  +import org.jboss.seam.util.Reflections;
   
   /**
    * Manages the Seam contexts associated with a JSF request.
  @@ -28,12 +53,50 @@
    *
    * @author Gavin King
    */
  -public class SeamPhaseListener extends AbstractSeamPhaseListener
  +public class SeamPhaseListener implements PhaseListener
   {
      private static final long serialVersionUID = -9127555729455066493L;
      
      private static final LogProvider log = Logging.getLogProvider(SeamPhaseListener.class);
      
  +   private static boolean exists = false;
  +   
  +   private static final Method SET_RENDER_PARAMETER;
  +   private static final Class ACTION_RESPONSE;
  +   private static final Class PORTLET_REQUEST;
  +   
  +   static
  +   {
  +      Method method = null;
  +      Class actionResponseClass = null;
  +      Class portletRequestClass = null;
  +      try
  +      {
  +         Class[] parameterTypes = { String.class, String.class };
  +         actionResponseClass = Class.forName("javax.portlet.ActionResponse");
  +         portletRequestClass = Class.forName("javax.portlet.PortletRequest");
  +         method = actionResponseClass.getMethod("setRenderParameter", parameterTypes);
  +      }
  +      catch (Exception e) {}
  +      SET_RENDER_PARAMETER = method;
  +      ACTION_RESPONSE = actionResponseClass;
  +      PORTLET_REQUEST = portletRequestClass;
  +   }
  +
  +   public SeamPhaseListener()
  +   {
  +      if (exists) 
  +      {
  +         log.warn("There should only be one Seam phase listener per application");
  +      }
  +      exists=true;
  +   }
  +   
  +   public PhaseId getPhaseId()
  +   {
  +      return ANY_PHASE;
  +   }
  +   
      public void beforePhase(PhaseEvent event)
      {
         log.trace( "before phase: " + event.getPhaseId() );
  @@ -42,7 +105,33 @@
   
         try
         {
  +         if ( isPortletRequest(event) )
  +         {
  +            beforePortletPhase(event);
  +         }
  +         else
  +         {
  +            beforeServletPhase(event);
  +         }
  +         raiseEventsBeforePhase(event);
  +      }
  +      catch (Exception e)
  +      {
  +         log.error("uncaught exception", e);
  +         try
  +         {
  +            Exceptions.instance().handle(e);
  +         }
  +         catch (Exception ehe) 
  +         {
  +            log.error("swallowing exception", e);
  +         }
  +      }
            
  +   }
  +
  +   private void beforeServletPhase(PhaseEvent event)
  +   {
            if ( event.getPhaseId() == RESTORE_VIEW )
            {
               beforeRestoreView( event.getFacesContext() );
  @@ -56,8 +145,43 @@
               beforeRender(event);
            }
            
  -         raiseEventsBeforePhase(event);
  +   }
  +   
  +   private void beforePortletPhase(PhaseEvent event)
  +   {
  +
  +      FacesContext facesContext = event.getFacesContext();
  +      
  +      if ( event.getPhaseId() == RESTORE_VIEW || event.getPhaseId() == RENDER_RESPONSE )
  +      {
  +         beforeRestoreView(facesContext);
  +      }
            
  +      //delegate to subclass:
  +      handleTransactionsBeforePhase(event);
  +      
  +      if ( event.getPhaseId() == RENDER_RESPONSE )
  +      {
  +         afterRestoreView(facesContext);         
  +         beforeRender(event);
  +      }
  +   }
  +
  +   public void afterPhase(PhaseEvent event)
  +   {
  +      log.trace( "after phase: " + event.getPhaseId() );
  +      
  +      try
  +      {
  +         raiseEventsAfterPhase(event);
  +         if ( isPortletRequest(event) )
  +         {
  +            afterPortletPhase(event);
  +         }
  +         else
  +         {
  +            afterServletPhase(event);
  +         }
         }
         catch (Exception e)
         {
  @@ -72,17 +196,13 @@
            }
         }
   
  -   }
  +      Lifecycle.setPhaseId(null);
   
  -   public void afterPhase(PhaseEvent event)
  -   {
  -      log.trace( "after phase: " + event.getPhaseId() );
  +   }
         
  -      try
  +   private void afterServletPhase(PhaseEvent event)
         {
            
  -         raiseEventsAfterPhase(event);
  -   
            FacesContext facesContext = event.getFacesContext();
            
            if ( event.getPhaseId() == RESTORE_VIEW )
  @@ -113,26 +233,359 @@
            {
               afterResponseComplete(facesContext);
            }
  +   }
  +   
  +   private void afterPortletPhase(PhaseEvent event)
  +   {
  +      FacesContext facesContext = event.getFacesContext();
         
  +      if ( event.getPhaseId() == RESTORE_VIEW )
  +      {
  +         afterRestoreView(facesContext);
         }
  -      catch (Exception e)
  +      else if ( event.getPhaseId() == INVOKE_APPLICATION )
  +      {
  +         afterInvokeApplication();
  +      }
  +      else if ( event.getPhaseId() == PROCESS_VALIDATIONS )
  +      {
  +         afterProcessValidations( event.getFacesContext() );
  +      }
  +      
  +      FacesMessages.afterPhase();
  +      
  +      //delegate to subclass:
  +      handleTransactionsAfterPhase(event);
  +            
  +      if ( event.getPhaseId() == RENDER_RESPONSE )
  +      {
  +         //writeConversationIdToResponse( facesContext.getExternalContext().getResponse() );
  +         afterRender(facesContext);
  +      }
  +      else if ( event.getPhaseId() == INVOKE_APPLICATION || facesContext.getRenderResponse() || facesContext.getResponseComplete() )
  +      {
  +         Manager manager = Manager.instance();
  +         manager.beforeRedirect();
  +         if ( manager.isLongRunningConversation() )
  +         {
  +            setPortletRenderParameter(
  +                  facesContext.getExternalContext().getResponse(), 
  +                  manager.getConversationIdParameter(), 
  +                  manager.getCurrentConversationId()
  +               );
  +         }
  +         afterResponseComplete(facesContext);
  +      }
  +      
  +   }
  +   
  +   private static void setPortletRenderParameter(Object response, String conversationIdParameter, String conversationId)
  +   {
  +      if ( ACTION_RESPONSE.isInstance(response) )
  +      {
  +         Reflections.invokeAndWrap(SET_RENDER_PARAMETER, response, conversationIdParameter, conversationId);
  +      }
  +   }
  +   
  +   private static boolean isPortletRequest(PhaseEvent event)
  +   {
  +      return PORTLET_REQUEST!=null && 
  +            PORTLET_REQUEST.isInstance( event.getFacesContext().getExternalContext().getRequest() );
  +   }
  +   
  +   public void handleTransactionsBeforePhase(PhaseEvent event)
  +   {
  +      if ( Init.instance().isTransactionManagementEnabled() ) 
  +      {
  +         PhaseId phaseId = event.getPhaseId();
  +         boolean beginTran = phaseId==PhaseId.RESTORE_VIEW || 
  +               ( phaseId==PhaseId.RENDER_RESPONSE && !Init.instance().isClientSideConversations() );
  +         
  +         if (beginTran) 
  +         {
  +            begin(phaseId);
  +         }
  +      }
  +   }
  +   
  +   public void handleTransactionsAfterPhase(PhaseEvent event)
  +   {
  +      if ( Init.instance().isTransactionManagementEnabled() ) 
  +      {
  +         PhaseId phaseId = event.getPhaseId();
  +         boolean commitTran = phaseId==PhaseId.INVOKE_APPLICATION || 
  +               event.getFacesContext().getRenderResponse() || //TODO: no need to commit the tx if we failed to restore the view
  +               event.getFacesContext().getResponseComplete() ||
  +               ( phaseId==PhaseId.RENDER_RESPONSE && !Init.instance().isClientSideConversations() );
  +         
  +         if (commitTran)
  +         { 
  +            commitOrRollback(phaseId); //we commit before destroying contexts, cos the contexts have the PC in them
  +         }
  +      }
  +   }
  +   
  +   protected void handleTransactionsAfterPageActions(PhaseEvent event)
  +   {
  +      if ( Init.instance().isTransactionManagementEnabled() ) 
  +      {
  +         commitOrRollback(PhaseId.INVOKE_APPLICATION);
  +         if ( !event.getFacesContext().getResponseComplete() )
  +         {
  +            begin(PhaseId.INVOKE_APPLICATION);
  +         }
  +      }
  +   }
  +   
  +   protected void afterInvokeApplication() 
  +   {
  +      if ( Init.instance().isTransactionManagementEnabled() ) 
  +      {
  +         addTransactionFailedMessage();
  +      }
  +   }
  +
  +   protected void afterProcessValidations(FacesContext facesContext)
  +   {
  +      Validation.instance().afterProcessValidations(facesContext);
  +   }
  +   
  +   /**
  +    * Set up the Seam contexts, except for the conversation
  +    * context
  +    */
  +   protected void beforeRestoreView(FacesContext facesContext)
  +   {
  +      Lifecycle.beginRequest( facesContext.getExternalContext() );
  +   }
  +   
  +   /**
  +    * Restore the page and conversation contexts during a JSF request
  +    */
  +   protected void afterRestoreView(FacesContext facesContext)
  +   {
  +      Lifecycle.resumePage();
  +      Map parameters = facesContext.getExternalContext().getRequestParameterMap();
  +      ConversationPropagation.instance().restoreConversationId(parameters);
  +      boolean conversationFound = Manager.instance().restoreConversation();
  +      Lifecycle.resumeConversation( facesContext.getExternalContext() );
  +      if (!conversationFound)
  +      {
  +         Pages.instance().redirectToNoConversationView();
  +      }
  +      if ( Init.instance().isJbpmInstalled() )
  +      {
  +         Pageflow.instance().validatePageflow();
  +      }
  +      Manager.instance().handleConversationPropagation(parameters);
  +      
  +      if ( log.isDebugEnabled() )
  +      {
  +         log.debug( "After restoring conversation context: " + Contexts.getConversationContext() );
  +      }
  +      
  +      Pages.instance().postRestore(facesContext);
  +            
  +   }
  +  
  +   public void raiseEventsBeforePhase(PhaseEvent event)
  +   {
  +      if ( Contexts.isApplicationContextActive() )
  +      {
  +         Events.instance().raiseEvent("org.jboss.seam.beforePhase", event);
  +      }
  +      
  +      if ( Contexts.isConversationContextActive() && Init.instance().isJbpmInstalled() && Pageflow.instance().isInProcess() )
  +      {
  +         String name;
  +         PhaseId phaseId = event.getPhaseId();
  +         if ( phaseId == PhaseId.PROCESS_VALIDATIONS )
  +         {
  +            name = "process-validations";
  +         }
  +         else if ( phaseId == PhaseId.UPDATE_MODEL_VALUES )
  +         {
  +            name = "update-model-values";
  +         }
  +         else if ( phaseId == PhaseId.INVOKE_APPLICATION )
  +         {
  +            name = "invoke-application";
  +         }
  +         else if ( phaseId == PhaseId.RENDER_RESPONSE )
  +         {
  +            name = "render-response";
  +         }
  +         else
  +         {
  +            return;
  +         }
  +         Pageflow.instance().processEvents(name);
  +      }
  +   }
  +   
  +   public void raiseEventsAfterPhase(PhaseEvent event)
  +   {
  +      if ( Contexts.isApplicationContextActive() )
  +      {
  +         Events.instance().raiseEvent("org.jboss.seam.afterPhase", event);
  +      }
  +   }
  +   
  +   /**
  +    * Add a faces message when Seam-managed transactions fail.
  +    */
  +   protected void addTransactionFailedMessage()
         {
  -         log.error("uncaught exception", e);
            try
            {
  -            Exceptions.instance().handle(e);
  +         if ( Transaction.instance().isRolledBackOrMarkedRollback() )
  +         {
  +            FacesMessages.instance().addFromResourceBundleOrDefault(
  +                     FacesMessage.SEVERITY_WARN, 
  +                     "org.jboss.seam.TransactionFailed", 
  +                     "Transaction failed"
  +                  );
            }
  -         catch (Exception ehe) 
  +      }
  +      catch (Exception e) {} //swallow silently, not important
  +   }
  +   
  +   protected void beforeRender(PhaseEvent event)
            {
  -            log.error("swallowing exception", e);
  +      
  +      FacesContext facesContext = event.getFacesContext();
  +      
  +      if ( Contexts.isPageContextActive() )
  +      {
  +         Context pageContext = Contexts.getPageContext();
  +         //after every time that the view may have changed,
  +         //we need to flush the page context, since the 
  +         //attribute map is being discarder
  +         pageContext.flush();
  +         //force refresh of the conversation lists (they are kept in PAGE context)
  +         pageContext.remove( Seam.getComponentName(ConversationList.class) );
  +         pageContext.remove( Seam.getComponentName(Switcher.class) );
  +         pageContext.remove( Seam.getComponentName(ConversationStack.class) );
            }
  +      
  +      preRenderPage(event);
  +      
  +      if ( facesContext.getResponseComplete() )
  +      {
  +         //workaround for a bug in MyFaces prior to 1.1.3
  +         if ( Init.instance().isMyFacesLifecycleBug() ) 
  +         {
  +            Lifecycle.endRequest( facesContext.getExternalContext() );
  +         }
  +      }
  +      else //if the page actions did not call responseComplete()
  +      {
  +         FacesMessages.instance().beforeRenderResponse();
  +         //do this both before and after render, since conversations 
  +         //and pageflows can begin during render
  +         Manager.instance().prepareBackswitch(facesContext); 
         }
   
  -      Lifecycle.setPhaseId(null);
  +      FacesPage.instance().storeConversation();
  +      FacesPage.instance().storePageflow();
         
  +      PersistenceContexts persistenceContexts = PersistenceContexts.instance();
  +      if (persistenceContexts != null) 
  +      {
  +          persistenceContexts.beforeRender();
  +      }
      }
   
  -   protected void handleTransactionsAfterPhase(PhaseEvent event) {}
  -   protected void handleTransactionsBeforePhase(PhaseEvent event) {}
  +   protected void afterRender(FacesContext facesContext)
  +   {
  +      //do this both before and after render, since conversations 
  +      //and pageflows can begin during render
  +      Manager.instance().prepareBackswitch(facesContext);
  +      
  +      PersistenceContexts persistenceContexts = PersistenceContexts.instance();
  +      if (persistenceContexts != null) 
  +      {
  +          persistenceContexts.afterRender();
  +      }
  +      
  +      ExternalContext externalContext = facesContext.getExternalContext();
  +      Manager.instance().endRequest( externalContext.getSessionMap() );
  +      Lifecycle.endRequest(externalContext);
  +   }
  +   
  +   protected void afterResponseComplete(FacesContext facesContext)
  +   {
  +      //responseComplete() was called by one of the other phases, 
  +      //so we will never get to the RENDER_RESPONSE phase
  +      //Note: we can't call Manager.instance().beforeRedirect() here, 
  +      //since a redirect is not the only reason for a responseComplete
  +      ExternalContext externalContext = facesContext.getExternalContext();
  +      Manager.instance().endRequest( externalContext.getSessionMap() );
  +      Lifecycle.endRequest( facesContext.getExternalContext() );
  +   }
  +   
  +   private boolean preRenderPage(PhaseEvent event)
  +   {
  +      if ( Pages.isDebugPage() )
  +      {
  +         return false;
  +      }
  +      else
  +      {
  +         Lifecycle.setPhaseId(PhaseId.INVOKE_APPLICATION);
  +         boolean actionsWereCalled = false;
  +         try
  +         {
  +            actionsWereCalled = Pages.instance().preRender( event.getFacesContext() );
  +            return actionsWereCalled;
  +         }
  +         finally
  +         {
  +            Lifecycle.setPhaseId( PhaseId.RENDER_RESPONSE );
  +            if (actionsWereCalled) 
  +            {
  +               FacesMessages.afterPhase();
  +               handleTransactionsAfterPageActions(event); //TODO: does it really belong in the finally?
  +            }
  +         }
  +      }
  +   }
  +      
  +   void begin(PhaseId phaseId) 
  +   {
  +      try 
  +      {
  +         if ( !Transaction.instance().isActiveOrMarkedRollback() )
  +         {
  +            log.debug("beginning transaction prior to phase: " + phaseId);
  +            Transaction.instance().begin();
  +         }
  +      }
  +      catch (Exception e)
  +      {
  +         throw new IllegalStateException("Could not start transaction", e);
  +      }
  +   }
  +   
  +   void commitOrRollback(PhaseId phaseId) 
  +   {
  +      try 
  +      {
  +         if ( Transaction.instance().isActive() )
  +         {
  +            log.debug("committing transaction after phase: " + phaseId);
  +            Transaction.instance().commit();
  +         }
  +         else if ( Transaction.instance().isRolledBackOrMarkedRollback() )
  +         {
  +            log.debug("rolling back transaction after phase: " + phaseId);
  +            Transaction.instance().rollback();
  +         }
  +      }
  +      catch (Exception e)
  +      {
  +         throw new IllegalStateException("Could not commit transaction", e);
  +      }
  +   }
   
   }
  
  
  



More information about the jboss-cvs-commits mailing list