Package org.jboss.portletbridge.seam

Source Code of org.jboss.portletbridge.seam.SeamPhaseListenerWrapper

/******************************************************************************
* JBoss, a division of Red Hat                                               *
* Copyright 2006, Red Hat Middleware, LLC, and individual                    *
* contributors as indicated by the @authors tag. See the                     *
* copyright.txt in the distribution for a full listing of                    *
* individual contributors.                                                   *
*                                                                            *
* This is free software; you can redistribute it and/or modify it            *
* under the terms of the GNU Lesser General Public License as                *
* published by the Free Software Foundation; either version 2.1 of           *
* the License, or (at your option) any later version.                        *
*                                                                            *
* This software is distributed in the hope that it will be useful,           *
* but WITHOUT ANY WARRANTY; without even the implied warranty of             *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU           *
* Lesser General Public License for more details.                            *
*                                                                            *
* You should have received a copy of the GNU Lesser General Public           *
* License along with this software; if not, write to the Free                *
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA         *
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.                   *
******************************************************************************/
package org.jboss.portletbridge.seam;

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 static org.jboss.seam.transaction.Transaction.TRANSACTION_FAILED;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
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 javax.portlet.faces.Bridge;
import javax.portlet.faces.Bridge.PortletPhase;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jboss.portletbridge.BridgeRequestScope;
import org.jboss.portletbridge.context.PortletBridgeContext;
import org.jboss.portletbridge.richfaces.RichFacesStrategy;
import org.jboss.seam.Seam;
import org.jboss.seam.contexts.Context;
import org.jboss.seam.contexts.Contexts;
import org.jboss.seam.contexts.FacesLifecycle;
import org.jboss.seam.core.ConversationPropagation;
import org.jboss.seam.core.Events;
import org.jboss.seam.core.Init;
import org.jboss.seam.core.Manager;
import org.jboss.seam.exception.Exceptions;
import org.jboss.seam.faces.FacesManager;
import org.jboss.seam.faces.FacesMessages;
import org.jboss.seam.faces.FacesPage;
import org.jboss.seam.faces.Switcher;
import org.jboss.seam.faces.Validation;
import org.jboss.seam.jsf.SeamPhaseListener;
import org.jboss.seam.navigation.Pages;
import org.jboss.seam.pageflow.Pageflow;
import org.jboss.seam.persistence.PersistenceContexts;
import org.jboss.seam.transaction.Transaction;
import org.jboss.seam.transaction.UserTransaction;

/**
* @author asmirnov
*
*/
public class SeamPhaseListenerWrapper implements PhaseListener {

  private final SeamPhaseListener _defaultListener;

  private static final Log log = LogFactory
          .getLog(SeamPhaseListenerWrapper.class);

  /**
   * @param defaultListener
   */
  public SeamPhaseListenerWrapper(PhaseListener defaultListener) {
    _defaultListener = (SeamPhaseListener) defaultListener;
  }

  /**
    *
    */
  private static final long serialVersionUID = -8465467659533393697L;

  /*
   * (non-Javadoc)
   *
   * @see
   * javax.faces.event.PhaseListener#afterPhase(javax.faces.event.PhaseEvent)
   */
  public void afterPhase(PhaseEvent event) {
    FacesContext facesContext = event.getFacesContext();
    ExternalContext externalContext = facesContext.getExternalContext();
    Bridge.PortletPhase portletPhase = (PortletPhase) externalContext
            .getRequestMap().get(Bridge.PORTLET_LIFECYCLE_PHASE);
    if (null != portletPhase) {
      try {
        raiseEventsAfterPhase(event);
        afterPortletPhase(event, facesContext, portletPhase);
      } finally {
        FacesLifecycle.clearPhaseId();
      }

    } else {
      _defaultListener.afterPhase(event);
    }
  }

  protected void afterPortletPhase(PhaseEvent event,
          FacesContext facesContext, PortletPhase portletPhase) {

    PhaseId phaseId = event.getPhaseId();
    if (phaseId == RESTORE_VIEW) {
      afterRestoreView(facesContext);
    } else if (phaseId == INVOKE_APPLICATION) {
      afterInvokeApplication();
    } else if (phaseId == PROCESS_VALIDATIONS) {
      afterProcessValidations(facesContext);
    }

    FacesMessages.afterPhase();

    // delegate to subclass:
    handleTransactionsAfterPhase(event);

    if (phaseId == RENDER_RESPONSE) {
      // writeConversationIdToResponse(
      // facesContext.getExternalContext().getResponse() );
      if(isRichFacesResourceRequest(facesContext)){
        finishRequest(facesContext);
      } else {
        afterRenderResponse(facesContext);
      }
    }

  }

  protected void finishRequest(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
    PortletBridgeContext bridgeContext = PortletBridgeContext
            .getCurrentInstance(facesContext);
    if (null != bridgeContext) {
      BridgeRequestScope windowState = bridgeContext.getRequestScope();
      if (Contexts.isEventContextActive()) {
        Manager manager = Manager.instance();
        if (manager.isLongRunningConversation()) {
          windowState.setConversationIdParameter(manager
                  .getConversationIdParameter());
          windowState.setConversationId(manager
                  .getCurrentConversationId());
        } else {
          windowState.setConversationIdParameter(null);
          windowState.setConversationId(null);
        }
      }
    }
    ExternalContext externalContext = facesContext.getExternalContext();
    if (Contexts.isEventContextActive()) {
      Manager.instance().endRequest(externalContext.getSessionMap());
    }
    FacesLifecycle.endRequest(facesContext.getExternalContext());
  }

  protected void saveFacesMessages(FacesContext facesContext) {
    if (Contexts.isConversationContextActive()) {
      PortletBridgeContext bridgeContext = PortletBridgeContext
              .getCurrentInstance(facesContext);
      if (null != bridgeContext) {
        BridgeRequestScope windowState = bridgeContext
                .getRequestScope();
        // Exceptions.instance().handle(e);
        org.jboss.portletbridge.seam.FacesMessages.afterPhase();
        org.jboss.portletbridge.seam.FacesMessages messages = org.jboss.portletbridge.seam.FacesMessages
                .instance();
        List<FacesMessage> messageList = new ArrayList<FacesMessage>(messages.getStatusMessages());
        Map<String, List<FacesMessage>> messagesMap = windowState.getMessages();
        messagesMap.put("", messageList);
      }
    }
  }

  protected void afterRenderResponse(FacesContext facesContext) {
    // do this both before and after render, since conversations
    // and pageflows can begin during render
    FacesManager.instance().prepareBackswitch(facesContext);

    PersistenceContexts persistenceContexts = PersistenceContexts
            .instance();
    if (persistenceContexts != null) {
      persistenceContexts.afterRender();
    }

  }

  /**
   * Restore the page and conversation contexts during a JSF request
   */
  protected void afterRestoreView(FacesContext facesContext) {
    FacesLifecycle.resumePage();
    Map<String, String> parameters = facesContext.getExternalContext()
            .getRequestParameterMap();
    ConversationPropagation.instance().restoreConversationId(parameters);
    boolean conversationFound = Manager.instance().restoreConversation();
    FacesLifecycle.resumeConversation(facesContext.getExternalContext());
    if(!isRichFacesResourceRequest(facesContext)){
      afterRestorePage(facesContext, parameters, conversationFound);
    }
  }

  protected boolean isRichFacesResourceRequest(FacesContext facesContext) {
      return null != facesContext.getExternalContext().getRequestMap().get(RichFacesStrategy.RICHFACES_RESOURCE);
    }

  protected void afterRestorePage(FacesContext facesContext,
          Map<String, String> parameters, boolean conversationFound) {
    if (!Pages.isDebugPage()) {
      // Only redirect to no-conversation-view if a login redirect isn't
      // required
      if (!conversationFound
              && !Pages.instance().isLoginRedirectRequired(facesContext)) {
        Pages.instance().redirectToNoConversationView();
      }

      Manager.instance().handleConversationPropagation(parameters);

      if (Init.instance().isJbpmInstalled()
              && !isExceptionHandlerRedirect()) {
        Pageflow.instance().validatePageflow(facesContext);
      }

      Pages.instance().postRestore(facesContext);
    }
  }

  protected boolean isExceptionHandlerRedirect() {
    return Contexts.getConversationContext().isSet(
            "org.jboss.seam.handledException");
  }

  protected void afterInvokeApplication() {
    if (Init.instance().isTransactionManagementEnabled()) {
      raiseTransactionFailedEvent();
    }
  }

  protected void afterProcessValidations(FacesContext facesContext) {
    Validation.instance().afterProcessValidations(facesContext);
  }

  protected void raiseEventsAfterPhase(PhaseEvent event) {
    if (Contexts.isApplicationContextActive()) {
      Events.instance().raiseEvent("org.jboss.seam.afterPhase", event);
    }
  }

  /*
   * (non-Javadoc)
   *
   * @see
   * javax.faces.event.PhaseListener#beforePhase(javax.faces.event.PhaseEvent)
   */
  public void beforePhase(PhaseEvent event) {
    FacesContext facesContext = event.getFacesContext();
    ExternalContext externalContext = facesContext.getExternalContext();
    Bridge.PortletPhase portletPhase = (PortletPhase) externalContext
            .getRequestMap().get(Bridge.PORTLET_LIFECYCLE_PHASE);
    if (null != portletPhase) {
      log.trace("before phase: " + event.getPhaseId());

      FacesLifecycle.setPhaseId(event.getPhaseId());

      try {
        beforePortletPhase(event, facesContext, portletPhase);
        raiseEventsBeforePhase(event);
      } catch (Exception e) {
        log.debug("uncaught exception, try to recovery", e);
        try {
          Exceptions.instance().handle(e);
        } catch (Exception ehe) {
          log.error("swallowing exception", e);
        }
      }
    } else {
      _defaultListener.beforePhase(event);
    }
  }

  protected void beforePortletPhase(PhaseEvent event,
          FacesContext facesContext, PortletPhase portletPhase) {
    if(event.getPhaseId()== RESTORE_VIEW && isRichFacesResourceRequest(facesContext)){
      beginRequest(facesContext);
    }
    // delegate to subclass:
    handleTransactionsBeforePhase(event);

    if (event.getPhaseId() == RENDER_RESPONSE) {
      beforeRenderResponse(facesContext);
    }
  }

  /**
   * Set up the Seam contexts, except for the conversation context
   */
  protected void beginRequest(FacesContext facesContext) {
    FacesLifecycle.beginRequest(facesContext.getExternalContext());
  }

  protected void beforeRenderResponse(FacesContext facesContext) {

    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(Switcher.class));
      pageContext.remove("org.jboss.seam.core.conversationList");
      pageContext.remove("org.jboss.seam.core.conversationStack");
    }

    performPageActions(facesContext);

    if (facesContext.getResponseComplete()) {
      // workaround for a bug in MyFaces prior to 1.1.3
      if (Init.instance().isMyFacesLifecycleBug()) {
        FacesLifecycle.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
      FacesManager.instance().prepareBackswitch(facesContext);
    }

    FacesPage.instance().storeConversation();
    FacesPage.instance().storePageflow();

    PersistenceContexts persistenceContexts = PersistenceContexts
            .instance();
    if (persistenceContexts != null) {
      persistenceContexts.beforeRender();
    }
  }

  protected boolean performPageActions(FacesContext facesContext) {
    if (Pages.isDebugPage()) {
      return false;
    } else {
      FacesLifecycle.setPhaseId(PhaseId.INVOKE_APPLICATION);
      boolean actionsWereCalled = false;
      try {
        actionsWereCalled = Pages.instance().preRender(facesContext);
        return actionsWereCalled;
      } finally {
        FacesLifecycle.setPhaseId(PhaseId.RENDER_RESPONSE);
        if (actionsWereCalled) {
          FacesMessages.afterPhase();
          handleTransactionsAfterPageActions(facesContext); // TODO:
                                                            // does it
                                                            // really
                                                            // belong
                                                            // in the
                                                            // finally?
        }
      }
    }
  }

  protected void raiseEventsBeforePhase(PhaseEvent event) {
    if (Contexts.isApplicationContextActive()) {
      Events.instance().raiseEvent("org.jboss.seam.beforePhase", event);
    }

  }

  /**
   * Raise an event so that an observer may add a faces message when
   * Seam-managed transactions fail.
   */
  protected void raiseTransactionFailedEvent() {
    try {
      UserTransaction tx = Transaction.instance();
      if (tx.isRolledBackOrMarkedRollback()) {
        if (Events.exists())
            Events.instance().raiseEvent(TRANSACTION_FAILED,
                    tx.getStatus());
      }
    } catch (Exception e) {
    } // swallow silently, not important
  }

  protected 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;
      // ( 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(FacesContext facesContext) {
    if (Init.instance().isTransactionManagementEnabled()) {
      commitOrRollback("after invoking page actions");
      if (!facesContext.getResponseComplete()) {
        begin("before continuing render");
      }
    }
  }

  protected void handleTransactionsBeforePhase(PhaseEvent event) {
    if (Init.instance().isTransactionManagementEnabled()) {
      PhaseId phaseId = event.getPhaseId();
      boolean beginTran = phaseId == PhaseId.RENDER_RESPONSE
              || phaseId == (Transaction.instance()
                      .isConversationContextRequired() ? PhaseId.APPLY_REQUEST_VALUES
                      : PhaseId.RESTORE_VIEW);
      // ( phaseId == PhaseId.RENDER_RESPONSE &&
      // !Init.instance().isClientSideConversations() );

      if (beginTran) {
        begin(phaseId);
      }
    }
  }

  protected void begin(PhaseId phaseId) {
    begin("prior to phase: " + phaseId);
  }

  protected void begin(String phaseString) {
    try {
      if (!Transaction.instance().isActiveOrMarkedRollback()) {
        log.debug("beginning transaction " + phaseString);
        Transaction.instance().begin();
      }
    } catch (Exception e) {
      throw new IllegalStateException("Could not start transaction", e);
    }
  }

  protected void commitOrRollback(PhaseId phaseId) {
    commitOrRollback("after phase: " + phaseId);
  }

  protected void commitOrRollback(String phaseString) {
    try {
      if (Transaction.instance().isActive()) {
        try {
          log.debug("committing transaction " + phaseString);
          Transaction.instance().commit();

        } catch (IllegalStateException e) {
          log.warn(
                  "TX commit failed with illegal state exception. This may be "
                          + "because the tx timed out and was rolled back in the background.",
                  e);
        }
      } else if (Transaction.instance().isRolledBackOrMarkedRollback()) {
        log.debug("rolling back transaction " + phaseString);
        Transaction.instance().rollback();
      }

    } catch (Exception e) {
      throw new IllegalStateException("Could not commit transaction", e);
    }
  }

  /*
   * (non-Javadoc)
   *
   * @see javax.faces.event.PhaseListener#getPhaseId()
   */
  public PhaseId getPhaseId() {
    return _defaultListener.getPhaseId();
  }

}
TOP

Related Classes of org.jboss.portletbridge.seam.SeamPhaseListenerWrapper

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.