Esempio n. 1
0
public class FacesContextImpl extends FacesContext {

  private static final String POST_BACK_MARKER = FacesContextImpl.class.getName() + "_POST_BACK";

  // Queried by InjectionFacesContextFactory
  private static final ThreadLocal<FacesContext> DEFAULT_FACES_CONTEXT =
      new ThreadLocal<FacesContext>();

  // Log instance for this class
  private static Logger LOGGER = FacesLogger.CONTEXT.getLogger();

  private boolean released;

  // BE SURE TO ADD NEW IVARS TO THE RELEASE METHOD
  private ResponseStream responseStream = null;
  private ResponseWriter responseWriter = null;
  private ExternalContext externalContext = null;
  private Application application = null;
  private UIViewRoot viewRoot = null;
  private ELContext elContext = null;
  private RenderKitFactory rkFactory;
  private RenderKit lastRk;
  private String lastRkId;
  private Severity maxSeverity;
  private boolean renderResponse = false;
  private boolean responseComplete = false;
  private boolean validationFailed = false;
  private Map<Object, Object> attributes;
  private PhaseId currentPhaseId;
  private PartialViewContext partialViewContext = null;
  private ExceptionHandler exceptionHandler = null;

  /**
   * Store mapping of clientId to ArrayList of FacesMessage instances. The null key is used to
   * represent FacesMessage instances that are not associated with a clientId instance.
   */
  private Map<String, List<FacesMessage>> componentMessageLists;

  private ComponentModificationManager componentModificationManager;

  // ----------------------------------------------------------- Constructors

  public FacesContextImpl(ExternalContext ec, Lifecycle lifecycle) {
    Util.notNull("ec", ec);
    Util.notNull("lifecycle", lifecycle);
    this.externalContext = ec;
    setCurrentInstance(this);
    DEFAULT_FACES_CONTEXT.set(this);
    rkFactory = (RenderKitFactory) FactoryFinder.getFactory(FactoryFinder.RENDER_KIT_FACTORY);
  }

  // ---------------------------------------------- Methods from FacesContext

  /** @see javax.faces.context.FacesContext#getExternalContext() */
  public ExternalContext getExternalContext() {
    assertNotReleased();
    return externalContext;
  }

  /** @see javax.faces.context.FacesContext#getApplication() */
  public Application getApplication() {
    assertNotReleased();
    if (null != application) {
      return application;
    }
    ApplicationFactory aFactory =
        (ApplicationFactory) FactoryFinder.getFactory(FactoryFinder.APPLICATION_FACTORY);
    application = aFactory.getApplication();
    assert (null != application);
    return application;
  }

  /** @see javax.faces.context.FacesContext#getExceptionHandler() */
  @Override
  public ExceptionHandler getExceptionHandler() {
    return exceptionHandler;
  }

  /**
   * @see javax.faces.context.FacesContext#setExceptionHandler(javax.faces.context.ExceptionHandler)
   */
  @Override
  public void setExceptionHandler(ExceptionHandler exceptionHandler) {
    this.exceptionHandler = exceptionHandler;
  }

  /** @see javax.faces.context.FacesContext#getPartialViewContext() */
  public PartialViewContext getPartialViewContext() {

    assertNotReleased();
    if (partialViewContext == null) {
      PartialViewContextFactory f =
          (PartialViewContextFactory)
              FactoryFinder.getFactory(FactoryFinder.PARTIAL_VIEW_CONTEXT_FACTORY);
      partialViewContext = f.getPartialViewContext(this);
    }
    return partialViewContext;
  }

  /** @see javax.faces.context.FacesContext#isPostback() */
  @Override
  public boolean isPostback() {

    assertNotReleased();
    Boolean postback = (Boolean) this.getAttributes().get(POST_BACK_MARKER);
    if (postback == null) {
      RenderKit rk = this.getRenderKit();
      if (rk != null) {
        postback = rk.getResponseStateManager().isPostback(this);
      } else {
        // ViewRoot hasn't been set yet, so calculate the RK
        ViewHandler vh = this.getApplication().getViewHandler();
        String rkId = vh.calculateRenderKitId(this);
        postback = RenderKitUtils.getResponseStateManager(this, rkId).isPostback(this);
      }
      this.getAttributes().put(POST_BACK_MARKER, postback);
    }

    return postback;
  }

  /** @see javax.faces.context.FacesContext#isReleased() */
  @Override
  public boolean isReleased() {
    return released;
  }

  /** @see javax.faces.context.FacesContext#getAttributes() */
  @Override
  public Map<Object, Object> getAttributes() {

    assertNotReleased();
    if (attributes == null) {
      attributes = new HashMap<Object, Object>();
    }
    return attributes;
  }

  /** @see javax.faces.context.FacesContext#getELContext() */
  @Override
  public ELContext getELContext() {
    assertNotReleased();
    if (elContext == null) {
      Application app = getApplication();
      elContext = new ELContextImpl(app.getELResolver());
      elContext.putContext(FacesContext.class, this);
      UIViewRoot root = this.getViewRoot();
      if (null != root) {
        elContext.setLocale(root.getLocale());
      }
      ELContextListener[] listeners = app.getELContextListeners();
      if (listeners.length > 0) {
        ELContextEvent event = new ELContextEvent(elContext);
        for (ELContextListener listener : listeners) {
          listener.contextCreated(event);
        }
      }
    }
    return elContext;
  }

  /** @see javax.faces.context.FacesContext#getClientIdsWithMessages() */
  public Iterator<String> getClientIdsWithMessages() {
    assertNotReleased();
    return ((componentMessageLists == null)
        ? Collections.<String>emptyList().iterator()
        : componentMessageLists.keySet().iterator());
  }

  /** @see javax.faces.context.FacesContext#getMaximumSeverity() */
  public Severity getMaximumSeverity() {
    assertNotReleased();
    Severity result = null;
    if (componentMessageLists != null && !(componentMessageLists.isEmpty())) {
      for (Iterator<FacesMessage> i = new ComponentMessagesIterator(componentMessageLists);
          i.hasNext(); ) {
        Severity severity = i.next().getSeverity();
        if (result == null || severity.compareTo(result) > 0) {
          result = severity;
        }
        if (result == FacesMessage.SEVERITY_FATAL) {
          break;
        }
      }
    }
    return result;
  }

  /** @see javax.faces.context.FacesContext#getMessageList() */
  @Override
  public List<FacesMessage> getMessageList() {

    assertNotReleased();

    if (null == componentMessageLists) {
      return Collections.unmodifiableList(Collections.<FacesMessage>emptyList());
    } else {
      List<FacesMessage> messages = new ArrayList<FacesMessage>();
      for (List<FacesMessage> list : componentMessageLists.values()) {
        messages.addAll(list);
      }
      return Collections.unmodifiableList(messages);
    }
  }

  /** @see javax.faces.context.FacesContext#getMessageList(String) */
  @Override
  public List<FacesMessage> getMessageList(String clientId) {

    assertNotReleased();

    if (null == componentMessageLists) {
      return Collections.unmodifiableList(Collections.<FacesMessage>emptyList());
    } else {
      List<FacesMessage> list = componentMessageLists.get(clientId);
      return Collections.unmodifiableList(
          (list != null) ? list : Collections.<FacesMessage>emptyList());
    }
  }

  /** @see javax.faces.context.FacesContext#getMessages() */
  public Iterator<FacesMessage> getMessages() {
    assertNotReleased();
    if (null == componentMessageLists) {
      List<FacesMessage> emptyList = Collections.emptyList();
      return (emptyList.iterator());
    }

    if (componentMessageLists.size() > 0) {
      return new ComponentMessagesIterator(componentMessageLists);
    } else {
      List<FacesMessage> emptyList = Collections.emptyList();
      return (emptyList.iterator());
    }
  }

  /** @see FacesContext#getMessages(String) */
  public Iterator<FacesMessage> getMessages(String clientId) {
    assertNotReleased();

    // If no messages have been enqueued at all,
    // return an empty List Iterator
    if (null == componentMessageLists) {
      List<FacesMessage> emptyList = Collections.emptyList();
      return (emptyList.iterator());
    }

    List<FacesMessage> list = componentMessageLists.get(clientId);
    if (list == null) {
      List<FacesMessage> emptyList = Collections.emptyList();
      return (emptyList.iterator());
    }
    return (list.iterator());
  }

  /** @see javax.faces.context.FacesContext#getRenderKit() */
  public RenderKit getRenderKit() {
    assertNotReleased();
    UIViewRoot vr = getViewRoot();
    if (vr == null) {
      return (null);
    }
    String renderKitId = vr.getRenderKitId();

    if (renderKitId == null) {
      return null;
    }

    if (renderKitId.equals(lastRkId)) {
      return lastRk;
    } else {
      lastRk = rkFactory.getRenderKit(this, renderKitId);
      if (lastRk == null) {
        if (LOGGER.isLoggable(Level.SEVERE)) {
          LOGGER.log(
              Level.SEVERE,
              "Unable to locate renderkit " + "instance for render-kit-id {0}.  Using {1} instead.",
              new String[] {renderKitId, RenderKitFactory.HTML_BASIC_RENDER_KIT});
        }
      }
      lastRkId = renderKitId;
      return lastRk;
    }
  }

  /** @see javax.faces.context.FacesContext#getResponseStream() */
  public ResponseStream getResponseStream() {
    assertNotReleased();
    return responseStream;
  }

  /** @see FacesContext#setResponseStream(javax.faces.context.ResponseStream) */
  public void setResponseStream(ResponseStream responseStream) {
    assertNotReleased();
    Util.notNull("responseStrean", responseStream);
    this.responseStream = responseStream;
  }

  /** @see javax.faces.context.FacesContext#getViewRoot() */
  public UIViewRoot getViewRoot() {
    assertNotReleased();
    return viewRoot;
  }

  /** @see FacesContext#setViewRoot(javax.faces.component.UIViewRoot) */
  public void setViewRoot(UIViewRoot root) {
    assertNotReleased();
    Util.notNull("root", root);

    if (viewRoot != null && !viewRoot.equals(root)) {
      Map<String, Object> viewMap = viewRoot.getViewMap(false);
      if (viewMap != null) {
        viewRoot.getViewMap().clear();
      }
    }

    viewRoot = root;
  }

  /** @see javax.faces.context.FacesContext#getResponseWriter() */
  public ResponseWriter getResponseWriter() {
    assertNotReleased();
    return responseWriter;
  }

  /** @see FacesContext#setResponseWriter(javax.faces.context.ResponseWriter) */
  public void setResponseWriter(ResponseWriter responseWriter) {
    assertNotReleased();
    Util.notNull("responseWriter", responseWriter);
    this.responseWriter = responseWriter;
  }

  /** @see FacesContext#addMessage(String, javax.faces.application.FacesMessage) */
  public void addMessage(String clientId, FacesMessage message) {
    assertNotReleased();
    // Validate our preconditions
    Util.notNull("message", message);

    if (maxSeverity == null) {
      maxSeverity = message.getSeverity();
    } else {
      Severity sev = message.getSeverity();
      if (sev.getOrdinal() > maxSeverity.getOrdinal()) {
        maxSeverity = sev;
      }
    }

    if (componentMessageLists == null) {
      componentMessageLists = new LinkedHashMap<String, List<FacesMessage>>();
    }

    // Add this message to our internal queue
    List<FacesMessage> list = componentMessageLists.get(clientId);
    if (list == null) {
      list = new ArrayList<FacesMessage>();
      componentMessageLists.put(clientId, list);
    }
    list.add(message);
    if (LOGGER.isLoggable(Level.FINE)) {
      LOGGER.fine(
          "Adding Message[sourceId="
              + (clientId != null ? clientId : "<<NONE>>")
              + ",summary="
              + message.getSummary()
              + ")");
    }
  }

  /** @see javax.faces.context.FacesContext#getCurrentPhaseId() */
  @Override
  public PhaseId getCurrentPhaseId() {

    assertNotReleased();
    return currentPhaseId;
  }

  @Override
  public ComponentModificationManager getComponentModificationManager() {
    assertNotReleased();
    if (componentModificationManager == null) {
      componentModificationManager = new ComponentModificationManagerImpl();
    }
    return componentModificationManager;
  }

  /** @see javax.faces.context.FacesContext#setCurrentPhaseId(javax.faces.event.PhaseId) */
  @Override
  public void setCurrentPhaseId(PhaseId currentPhaseId) {

    assertNotReleased();
    this.currentPhaseId = currentPhaseId;
  }

  /** @see javax.faces.context.FacesContext#release() */
  public void release() {

    released = true;
    externalContext = null;
    responseStream = null;
    responseWriter = null;
    componentMessageLists = null;
    renderResponse = false;
    responseComplete = false;
    validationFailed = false;
    viewRoot = null;
    maxSeverity = null;
    application = null;
    currentPhaseId = null;
    if (attributes != null) {
      attributes.clear();
      attributes = null;
    }
    partialViewContext = null;
    exceptionHandler = null;
    elContext = null;
    rkFactory = null;
    lastRk = null;
    lastRkId = null;

    // PENDING(edburns): write testcase that verifies that release
    // actually works.  This will be important to keep working as
    // ivars are added and removed on this class over time.

    // Make sure to clear our ThreadLocal instance.
    setCurrentInstance(null);

    // remove our private ThreadLocal instance.
    DEFAULT_FACES_CONTEXT.remove();
  }

  /** @see javax.faces.context.FacesContext#renderResponse() */
  public void renderResponse() {
    assertNotReleased();
    renderResponse = true;
  }

  /** @see javax.faces.context.FacesContext#responseComplete() */
  public void responseComplete() {
    assertNotReleased();
    responseComplete = true;
  }

  /** @see javax.faces.context.FacesContext#validationFailed() */
  public void validationFailed() {
    assertNotReleased();
    validationFailed = true;
  }

  /** @see javax.faces.context.FacesContext#getRenderResponse() */
  public boolean getRenderResponse() {
    assertNotReleased();
    return renderResponse;
  }

  /** @see javax.faces.context.FacesContext#getResponseComplete() */
  public boolean getResponseComplete() {
    assertNotReleased();
    return responseComplete;
  }

  /** @see javax.faces.context.FacesContext#isValidationFailed() */
  public boolean isValidationFailed() {
    assertNotReleased();
    return validationFailed;
  }

  // --------------------------------------------------------- Public Methods

  public static FacesContext getDefaultFacesContext() {

    return DEFAULT_FACES_CONTEXT.get();
  }

  // -------------------------------------------------------- Private Methods

  @SuppressWarnings({"FinalPrivateMethod"})
  private final void assertNotReleased() {
    if (released) {
      throw new IllegalStateException();
    }
  }

  // ---------------------------------------------------------- Inner Classes

  private static final class ComponentMessagesIterator implements Iterator<FacesMessage> {

    private Map<String, List<FacesMessage>> messages;
    private int outerIndex = -1;
    private int messagesSize;
    private Iterator<FacesMessage> inner;
    private Iterator<String> keys;

    // ------------------------------------------------------- Constructors

    ComponentMessagesIterator(Map<String, List<FacesMessage>> messages) {

      this.messages = messages;
      messagesSize = messages.size();
      keys = messages.keySet().iterator();
    }

    // ---------------------------------------------- Methods from Iterator

    public boolean hasNext() {

      if (outerIndex == -1) {
        // pop our first List, if any;
        outerIndex++;
        inner = messages.get(keys.next()).iterator();
      }
      while (!inner.hasNext()) {
        outerIndex++;
        if ((outerIndex) < messagesSize) {
          inner = messages.get(keys.next()).iterator();
        } else {
          return false;
        }
      }
      return inner.hasNext();
    }

    public FacesMessage next() {

      if (outerIndex >= messagesSize) {
        throw new NoSuchElementException();
      }
      if (inner != null && inner.hasNext()) {
        return inner.next();
      } else {
        // call this.hasNext() to properly initialize/position 'inner'
        if (!this.hasNext()) {
          throw new NoSuchElementException();
        } else {
          return inner.next();
        }
      }
    }

    public void remove() {

      if (outerIndex == -1) {
        throw new IllegalStateException();
      }
      inner.remove();
    }
  } // END ComponentMessagesIterator

  // The testcase for this class is TestFacesContextImpl.java
  // The testcase for this class is TestFacesContextImpl_Model.java

} // end of class FacesContextImpl
Esempio n. 2
0
/**
 * The default implementation of {@link ExceptionHandler} for JSF 2.0.
 *
 * <p>As an implementation note, if changes going forward are required here, review the <code>
 * ExceptionHandler</code> implementation within <code>
 * javax.faces.webapp.PreJsf2ExceptionHandlerFactory</code>. The code is, in most cases, quite
 * similar.
 */
public class ExceptionHandlerImpl extends ExceptionHandler {

  private static final Logger LOGGER = FacesLogger.CONTEXT.getLogger();
  private static final String LOG_BEFORE_KEY = "jsf.context.exception.handler.log_before";
  private static final String LOG_AFTER_KEY = "jsf.context.exception.handler.log_after";
  private static final String LOG_KEY = "jsf.context.exception.handler.log";

  private LinkedList<ExceptionQueuedEvent> unhandledExceptions;
  private LinkedList<ExceptionQueuedEvent> handledExceptions;
  private ExceptionQueuedEvent handled;
  private boolean errorPagePresent;

  // ------------------------------------------------------------ Constructors

  public ExceptionHandlerImpl() {

    this.errorPagePresent = true;
  }

  public ExceptionHandlerImpl(boolean errorPagePresent) {

    this.errorPagePresent = errorPagePresent;
  }

  // ------------------------------------------- Methods from ExceptionHandler

  /** @see ExceptionHandler@getHandledExceptionQueuedEvent() */
  public ExceptionQueuedEvent getHandledExceptionQueuedEvent() {

    return handled;
  }

  /** @see javax.faces.context.ExceptionHandler#handle() */
  @SuppressWarnings({"ThrowableInstanceNeverThrown"})
  public void handle() throws FacesException {

    for (Iterator<ExceptionQueuedEvent> i = getUnhandledExceptionQueuedEvents().iterator();
        i.hasNext(); ) {
      ExceptionQueuedEvent event = i.next();
      ExceptionQueuedEventContext context = (ExceptionQueuedEventContext) event.getSource();
      try {
        Throwable t = context.getException();
        if (isRethrown(t)) {
          handled = event;
          Throwable unwrapped = getRootCause(t);
          if (unwrapped != null) {
            throwIt(context.getContext(), new FacesException(unwrapped.getMessage(), unwrapped));
          } else {
            if (t instanceof FacesException) {
              throwIt(context.getContext(), (FacesException) t);
            } else {
              throwIt(context.getContext(), new FacesException(t.getMessage(), t));
            }
          }
        } else {
          log(context);
        }

      } finally {
        if (handledExceptions == null) {
          handledExceptions = new LinkedList<ExceptionQueuedEvent>();
        }
        handledExceptions.add(event);
        i.remove();
      }
    }
  }

  /** @see javax.faces.context.ExceptionHandler#isListenerForSource(Object) */
  public boolean isListenerForSource(Object source) {

    return (source instanceof ExceptionQueuedEventContext);
  }

  /** @see javax.faces.context.ExceptionHandler#processEvent(javax.faces.event.SystemEvent) */
  public void processEvent(SystemEvent event) throws AbortProcessingException {

    if (event != null) {
      if (unhandledExceptions == null) {
        unhandledExceptions = new LinkedList<ExceptionQueuedEvent>();
      }
      unhandledExceptions.add((ExceptionQueuedEvent) event);
    }
  }

  /** @see ExceptionHandler#getRootCause(Throwable) */
  public Throwable getRootCause(Throwable t) {

    if (t == null) {
      return null;
    }
    if (shouldUnwrap(t.getClass())) {
      Throwable root = t.getCause();
      if (root != null) {
        Throwable tmp = getRootCause(root);
        if (tmp == null) {
          return root;
        } else {
          return tmp;
        }
      } else {
        return t;
      }
    }
    return t;
  }

  /** @see javax.faces.context.ExceptionHandler#getUnhandledExceptionQueuedEvents() */
  public Iterable<ExceptionQueuedEvent> getUnhandledExceptionQueuedEvents() {

    return ((unhandledExceptions != null)
        ? unhandledExceptions
        : Collections.<ExceptionQueuedEvent>emptyList());
  }

  /**
   * @see javax.faces.context.ExceptionHandler#getHandledExceptionQueuedEvents()
   * @return
   */
  public Iterable<ExceptionQueuedEvent> getHandledExceptionQueuedEvents() {

    return ((handledExceptions != null)
        ? handledExceptions
        : Collections.<ExceptionQueuedEvent>emptyList());
  }

  // --------------------------------------------------------- Private Methods

  private void throwIt(FacesContext ctx, FacesException fe) {

    boolean isDevelopment = ctx.isProjectStage(ProjectStage.Development);
    if (isDevelopment && !errorPagePresent) {
      // RELEASE_PENDING_2_1
      // thThe error page here will be text/html which means not all device
      // types are going to render this properly.  This should be addressed
      // in 2.1
      RenderKitUtils.renderHtmlErrorPage(ctx, fe);
    } else {
      if (isDevelopment) {
        // store the view root where the exception occurred into the
        // request scope so that the error page can display that component
        // tree and not the one rendering the errorpage
        ctx.getExternalContext().getRequestMap().put("com.sun.faces.error.view", ctx.getViewRoot());
      }
      throw fe;
    }
  }

  /**
   * @param c <code>Throwable</code> implementation class
   * @return <code>true</code> if <code>c</code> is FacesException.class or ELException.class
   */
  private boolean shouldUnwrap(Class<? extends Throwable> c) {

    return (FacesException.class.equals(c) || ELException.class.equals(c));
  }

  private boolean isRethrown(Throwable t) {

    return (!(t instanceof AbortProcessingException));
  }

  private void log(ExceptionQueuedEventContext exceptionContext) {

    UIComponent c = exceptionContext.getComponent();
    boolean beforePhase = exceptionContext.inBeforePhase();
    boolean afterPhase = exceptionContext.inAfterPhase();
    PhaseId phaseId = exceptionContext.getPhaseId();
    Throwable t = exceptionContext.getException();
    String key = getLoggingKey(beforePhase, afterPhase);
    if (LOGGER.isLoggable(Level.SEVERE)) {
      LOGGER.log(
          Level.SEVERE,
          key,
          new Object[] {
            t.getClass().getName(),
            phaseId.toString(),
            ((c != null) ? c.getClientId(exceptionContext.getContext()) : ""),
            t.getMessage()
          });
      LOGGER.log(Level.SEVERE, t.getMessage(), t);
    }
  }

  private String getLoggingKey(boolean beforePhase, boolean afterPhase) {
    if (beforePhase) {
      return LOG_BEFORE_KEY;
    } else if (afterPhase) {
      return LOG_AFTER_KEY;
    } else {
      return LOG_KEY;
    }
  }
}
Esempio n. 3
0
public class PartialViewContextImpl extends PartialViewContext {

  // Log instance for this class
  private static Logger LOGGER = FacesLogger.CONTEXT.getLogger();

  private boolean released;

  // BE SURE TO ADD NEW IVARS TO THE RELEASE METHOD
  private PartialResponseWriter partialResponseWriter;
  private List<String> executeIds;
  private Collection<String> renderIds;
  private Boolean ajaxRequest;
  private Boolean partialRequest;
  private Boolean renderAll;
  private FacesContext ctx;

  private static final String ORIGINAL_WRITER = "com.sun.faces.ORIGINAL_WRITER";

  // ----------------------------------------------------------- Constructors

  public PartialViewContextImpl(FacesContext ctx) {
    this.ctx = ctx;
  }

  // ---------------------------------------------- Methods from PartialViewContext

  /** @see javax.faces.context.PartialViewContext#isAjaxRequest() */
  @Override
  public boolean isAjaxRequest() {

    assertNotReleased();
    if (ajaxRequest == null) {
      ajaxRequest =
          "partial/ajax"
              .equals(ctx.getExternalContext().getRequestHeaderMap().get("Faces-Request"));
    }
    return ajaxRequest;
  }

  /** @see javax.faces.context.PartialViewContext#isPartialRequest() */
  @Override
  public boolean isPartialRequest() {

    assertNotReleased();
    if (partialRequest == null) {
      partialRequest =
          isAjaxRequest()
              || "partial/process"
                  .equals(ctx.getExternalContext().getRequestHeaderMap().get("Faces-Request"));
    }
    return partialRequest;
  }

  /** @see javax.faces.context.PartialViewContext#isExecuteAll() */
  @Override
  public boolean isExecuteAll() {

    assertNotReleased();
    String execute =
        ctx.getExternalContext().getRequestParameterMap().get(PARTIAL_EXECUTE_PARAM_NAME);
    return (ALL_PARTIAL_PHASE_CLIENT_IDS.equals(execute));
  }

  /** @see javax.faces.context.PartialViewContext#isRenderAll() */
  @Override
  public boolean isRenderAll() {

    assertNotReleased();
    if (renderAll == null) {
      String render =
          ctx.getExternalContext().getRequestParameterMap().get(PARTIAL_RENDER_PARAM_NAME);
      renderAll = (ALL_PARTIAL_PHASE_CLIENT_IDS.equals(render));
    }

    return renderAll;
  }

  /** @see javax.faces.context.PartialViewContext#setRenderAll(boolean) */
  @Override
  public void setRenderAll(boolean renderAll) {

    this.renderAll = renderAll;
  }

  @Override
  public void setPartialRequest(boolean isPartialRequest) {
    this.partialRequest = isPartialRequest;
  }

  /** @see javax.faces.context.PartialViewContext#getExecuteIds() */
  @Override
  public Collection<String> getExecuteIds() {

    assertNotReleased();
    if (executeIds != null) {
      return executeIds;
    }
    executeIds = populatePhaseClientIds(PARTIAL_EXECUTE_PARAM_NAME);

    // include the view parameter facet ID if there are other execute IDs
    // to process
    if (!executeIds.isEmpty()) {
      UIViewRoot root = ctx.getViewRoot();
      if (root.getFacetCount() > 0) {
        if (root.getFacet(UIViewRoot.METADATA_FACET_NAME) != null) {
          executeIds.add(0, UIViewRoot.METADATA_FACET_NAME);
        }
      }
    }
    return executeIds;
  }

  /** @see javax.faces.context.PartialViewContext#getRenderIds() */
  @Override
  public Collection<String> getRenderIds() {

    assertNotReleased();
    if (renderIds != null) {
      return renderIds;
    }
    renderIds = populatePhaseClientIds(PARTIAL_RENDER_PARAM_NAME);
    return renderIds;
  }

  /** @see javax.faces.context.PartialViewContext#processPartial(javax.faces.event.PhaseId)) */
  @Override
  public void processPartial(PhaseId phaseId) {
    Collection<String> executeIds = getExecuteIds();
    Collection<String> renderIds = getRenderIds();
    UIViewRoot viewRoot = ctx.getViewRoot();

    if (phaseId == PhaseId.APPLY_REQUEST_VALUES
        || phaseId == PhaseId.PROCESS_VALIDATIONS
        || phaseId == PhaseId.UPDATE_MODEL_VALUES) {

      // Skip this processing if "none" is specified in the render list,
      // or there were no execute phase client ids.

      if (executeIds == null || executeIds.isEmpty()) {
        // RELEASE_PENDING LOG ERROR OR WARNING
        return;
      }

      try {
        processComponents(viewRoot, phaseId, executeIds, ctx);
      } catch (Exception e) {
        // RELEASE_PENDING LOG EXCEPTION
      }

      // If we have just finished APPLY_REQUEST_VALUES phase, install the
      // partial response writer.  We want to make sure that any content
      // or errors generated in the other phases are written using the
      // partial response writer.
      //
      if (phaseId == PhaseId.APPLY_REQUEST_VALUES) {
        PartialResponseWriter writer = getPartialResponseWriter();
        ctx.setResponseWriter(writer);
      }

    } else if (phaseId == PhaseId.RENDER_RESPONSE) {

      try {
        //
        // We re-enable response writing.
        //
        OnOffResponseWrapper onOffResponse = new OnOffResponseWrapper(ctx);
        onOffResponse.setEnabled(true);
        PartialResponseWriter writer = getPartialResponseWriter();
        ResponseWriter orig = ctx.getResponseWriter();
        ctx.getAttributes().put(ORIGINAL_WRITER, orig);
        ctx.setResponseWriter(writer);

        ExternalContext exContext = ctx.getExternalContext();
        exContext.setResponseContentType("text/xml");
        exContext.addResponseHeader("Cache-Control", "no-cache");
        writer.startDocument();
        if (isRenderAll()) {
          renderAll(ctx, viewRoot);
          renderState(ctx);
          writer.endDocument();
          return;
        }

        // Skip this processing if "none" is specified in the render list,
        // or there were no render phase client ids.
        if (renderIds == null || renderIds.isEmpty()) {
        } else {
          processComponents(viewRoot, phaseId, renderIds, ctx);
        }

        renderState(ctx);

        writer.endDocument();
      } catch (IOException ex) {
        this.cleanupAfterView();
      } catch (RuntimeException ex) {
        this.cleanupAfterView();
        // Throw the exception
        throw ex;
      }
    }
  }

  /** @see javax.faces.context.PartialViewContext#getPartialResponseWriter() */
  @Override
  public PartialResponseWriter getPartialResponseWriter() {
    assertNotReleased();
    if (partialResponseWriter == null) {
      partialResponseWriter = new DelayedInitPartialResponseWriter(this);
    }
    return partialResponseWriter;
  }

  /** @see javax.faces.context.PartialViewContext#release() */
  public void release() {

    released = true;
    ajaxRequest = null;
    renderAll = null;
    partialResponseWriter = null;
    executeIds = null;
    renderIds = null;
    ctx = null;
    partialRequest = null;
  }

  // -------------------------------------------------------- Private Methods

  private List<String> populatePhaseClientIds(String parameterName) {

    Map<String, String> requestParamMap = ctx.getExternalContext().getRequestParameterMap();

    String param = requestParamMap.get(parameterName);
    if (param == null) {
      return new ArrayList<String>();
    } else {
      String[] pcs = Util.split(param, "[ \t]+");
      return ((pcs != null && pcs.length != 0)
          ? new ArrayList<String>(Arrays.asList(pcs))
          : new ArrayList<String>());
    }
  }

  // Process the components specified in the phaseClientIds list
  private void processComponents(
      UIComponent component,
      PhaseId phaseId,
      Collection<String> phaseClientIds,
      FacesContext context)
      throws IOException {

    // We use the tree visitor mechanism to locate the components to
    // process.  Create our (partial) VisitContext and the
    // VisitCallback that will be invoked for each component that
    // is visited.  Note that we use the SKIP_UNRENDERED hint as we
    // only want to visit the rendered subtree.
    EnumSet<VisitHint> hints = EnumSet.of(VisitHint.SKIP_UNRENDERED);
    PartialVisitContext visitContext = new PartialVisitContext(context, phaseClientIds, hints);
    PhaseAwareVisitCallback visitCallback = new PhaseAwareVisitCallback(ctx, phaseId);
    component.visitTree(visitContext, visitCallback);
  }

  private void renderAll(FacesContext context, UIViewRoot viewRoot) throws IOException {
    // If this is a "render all via ajax" request,
    // make sure to wrap the entire page in a <render> elemnt
    // with the special id of VIEW_ROOT_ID.  This is how the client
    // JavaScript knows how to replace the entire document with
    // this response.
    PartialResponseWriter writer = getPartialResponseWriter();
    writer.startUpdate(PartialResponseWriter.RENDER_ALL_MARKER);

    Iterator<UIComponent> itr = viewRoot.getFacetsAndChildren();
    while (itr.hasNext()) {
      UIComponent kid = itr.next();
      kid.encodeAll(context);
    }

    writer.endUpdate();
  }

  private void renderState(FacesContext context) throws IOException {

    // Get the view state and write it to the response..
    PartialResponseWriter writer = getPartialResponseWriter();
    writer.startUpdate(PartialResponseWriter.VIEW_STATE_MARKER);
    String state = context.getApplication().getStateManager().getViewState(context);
    writer.write(state);
    writer.endUpdate();
  }

  private PartialResponseWriter createPartialResponseWriter() {

    ExternalContext extContext = ctx.getExternalContext();
    String encoding = extContext.getRequestCharacterEncoding();
    extContext.setResponseCharacterEncoding(encoding);
    ResponseWriter responseWriter = null;
    Writer out = null;
    try {
      out = extContext.getResponseOutputWriter();
    } catch (IOException ioe) {
      if (LOGGER.isLoggable(Level.SEVERE)) {
        LOGGER.log(Level.SEVERE, ioe.toString(), ioe);
      }
    }

    if (out != null) {
      responseWriter = ctx.getRenderKit().createResponseWriter(out, "text/xml", encoding);
    }
    if (responseWriter instanceof PartialResponseWriter) {
      return (PartialResponseWriter) responseWriter;
    } else {
      return new PartialResponseWriter(responseWriter);
    }
  }

  private void cleanupAfterView() {
    ResponseWriter orig = (ResponseWriter) ctx.getAttributes().get(ORIGINAL_WRITER);
    assert (null != orig);
    // move aside the PartialResponseWriter
    ctx.setResponseWriter(orig);
  }

  @SuppressWarnings({"FinalPrivateMethod"})
  private final void assertNotReleased() {
    if (released) {
      throw new IllegalStateException();
    }
  }

  // ----------------------------------------------------------- Inner Classes

  private static class PhaseAwareVisitCallback implements VisitCallback {

    private PhaseId curPhase;
    private FacesContext ctx;

    private PhaseAwareVisitCallback(FacesContext ctx, PhaseId curPhase) {
      this.ctx = ctx;
      this.curPhase = curPhase;
    }

    public VisitResult visit(VisitContext context, UIComponent comp) {
      try {

        if (curPhase == PhaseId.APPLY_REQUEST_VALUES) {

          // RELEASE_PENDING handle immediate request(s)
          // If the user requested an immediate request
          // Make sure to set the immediate flag here.

          comp.processDecodes(ctx);
        } else if (curPhase == PhaseId.PROCESS_VALIDATIONS) {
          comp.processValidators(ctx);
        } else if (curPhase == PhaseId.UPDATE_MODEL_VALUES) {
          comp.processUpdates(ctx);
        } else if (curPhase == PhaseId.RENDER_RESPONSE) {

          PartialResponseWriter writer = ctx.getPartialViewContext().getPartialResponseWriter();

          writer.startUpdate(comp.getClientId(ctx));
          try {
            // do the default behavior...
            comp.encodeAll(ctx);
          } catch (Exception ce) {
            if (LOGGER.isLoggable(Level.SEVERE)) {
              LOGGER.severe(ce.toString());
            }
            if (LOGGER.isLoggable(Level.FINE)) {
              LOGGER.log(Level.FINE, ce.toString(), ce);
            }
          }
          writer.endUpdate();
        } else {
          throw new IllegalStateException(
              "I18N: Unexpected "
                  + "PhaseId passed to "
                  + " PhaseAwareContextCallback: "
                  + curPhase.toString());
        }
      } catch (IOException ex) {
        ex.printStackTrace();
      }

      // Once we visit a component, there is no need to visit
      // its children, since processDecodes/Validators/Updates and
      // encodeAll() already traverse the subtree.  We return
      // VisitResult.REJECT to supress the subtree visit.
      return VisitResult.REJECT;
    }
  }

  /**
   * Delays the actual construction of the PartialResponseWriter <em>until</em> content is going to
   * actually be written.
   */
  private static final class DelayedInitPartialResponseWriter extends PartialResponseWriter {

    private ResponseWriter writer;
    private PartialViewContextImpl ctx;

    // -------------------------------------------------------- Constructors

    public DelayedInitPartialResponseWriter(PartialViewContextImpl ctx) {

      super(null);
      this.ctx = ctx;
    }

    // ---------------------------------- Methods from PartialResponseWriter

    @Override
    public ResponseWriter getWrapped() {

      if (writer == null) {
        writer = ctx.createPartialResponseWriter();
      }
      return writer;
    }
  } // END DelayedInitPartialResponseWriter
}
/**
 * A specialized implementation of {@link ExceptionHandler} for JSF 2.0 that handles exceptions by
 * writing error information to the partial response.
 */
public class AjaxExceptionHandlerImpl extends ExceptionHandlerWrapper {

  private static final Logger LOGGER = FacesLogger.CONTEXT.getLogger();
  private static final String LOG_BEFORE_KEY = "jsf.context.exception.handler.log_before";
  private static final String LOG_AFTER_KEY = "jsf.context.exception.handler.log_after";
  private static final String LOG_KEY = "jsf.context.exception.handler.log";

  private LinkedList<ExceptionQueuedEvent> unhandledExceptions;
  private LinkedList<ExceptionQueuedEvent> handledExceptions;
  private ExceptionQueuedEvent handled;

  public AjaxExceptionHandlerImpl(ExceptionHandler handler) {
    super(handler);
  }

  /**
   * @return
   * @see ExceptionHandler#getHandledExceptionQueuedEvent()
   */
  @Override
  public ExceptionQueuedEvent getHandledExceptionQueuedEvent() {

    return handled;
  }

  /** @see javax.faces.context.ExceptionHandlerWrapper#handle() */
  @Override
  public void handle() throws FacesException {

    for (Iterator<ExceptionQueuedEvent> i = getUnhandledExceptionQueuedEvents().iterator();
        i.hasNext(); ) {
      ExceptionQueuedEvent event = i.next();
      ExceptionQueuedEventContext context = (ExceptionQueuedEventContext) event.getSource();
      try {
        Throwable t = context.getException();
        if (isRethrown(t)) {
          handled = event;
          Throwable unwrapped = getRootCause(t);

          if (unwrapped != null) {
            handlePartialResponseError(context.getContext(), unwrapped);
          } else {
            if (t instanceof FacesException) {
              handlePartialResponseError(context.getContext(), t);
            } else {
              handlePartialResponseError(
                  context.getContext(), new FacesException(t.getMessage(), t));
            }
          }
        } else {
          log(context);
        }

      } finally {
        if (handledExceptions == null) {
          handledExceptions = new LinkedList<>();
        }
        handledExceptions.add(event);
        i.remove();
      }
    }
  }

  /**
   * @see javax.faces.context.ExceptionHandlerWrapper#processEvent(javax.faces.event.SystemEvent)
   */
  @Override
  public void processEvent(SystemEvent event) throws AbortProcessingException {

    if (event != null) {
      if (unhandledExceptions == null) {
        unhandledExceptions = new LinkedList<>();
      }
      unhandledExceptions.add((ExceptionQueuedEvent) event);
    }
  }

  /** @see javax.faces.context.ExceptionHandlerWrapper#getUnhandledExceptionQueuedEvents() */
  @Override
  public Iterable<ExceptionQueuedEvent> getUnhandledExceptionQueuedEvents() {

    return ((unhandledExceptions != null)
        ? unhandledExceptions
        : Collections.<ExceptionQueuedEvent>emptyList());
  }

  /** @see javax.faces.context.ExceptionHandlerWrapper#getHandledExceptionQueuedEvents() */
  @Override
  public Iterable<ExceptionQueuedEvent> getHandledExceptionQueuedEvents() {

    return ((handledExceptions != null)
        ? handledExceptions
        : Collections.<ExceptionQueuedEvent>emptyList());
  }

  // --------------------------------------------------------- Private Methods

  private void handlePartialResponseError(FacesContext context, Throwable t) {
    if (context.getResponseComplete()) {
      return; // don't write anything if the response is complete
    }
    try {

      ExternalContext extContext = context.getExternalContext();
      extContext.setResponseContentType("text/xml");
      extContext.addResponseHeader("Cache-Control", "no-cache");
      PartialResponseWriter writer = context.getPartialViewContext().getPartialResponseWriter();

      writer.startDocument();
      writer.startError(t.getClass().toString());
      String msg;
      if (context.isProjectStage(ProjectStage.Production)) {
        msg = "See your server log for more information";
      } else {
        if (t.getCause() != null) {
          msg = t.getCause().getMessage();
        } else {
          msg = t.getMessage();
        }
      }
      writer.write(((msg != null) ? msg : ""));
      writer.endError();
      writer.endDocument();

      if (LOGGER.isLoggable(Level.SEVERE)) {
        StringWriter sw = new StringWriter();
        PrintWriter pw = new PrintWriter(sw);
        t.printStackTrace(pw);
        LOGGER.log(Level.SEVERE, sw.toString());
      }

      context.responseComplete();
    } catch (IOException ioe) {
      if (LOGGER.isLoggable(Level.SEVERE)) {
        LOGGER.log(Level.SEVERE, ioe.toString(), ioe);
      }
    }
  }

  private boolean isRethrown(Throwable t) {

    return (!(t instanceof AbortProcessingException));
  }

  private void log(ExceptionQueuedEventContext exceptionContext) {

    UIComponent c = exceptionContext.getComponent();
    boolean beforePhase = exceptionContext.inBeforePhase();
    boolean afterPhase = exceptionContext.inAfterPhase();
    PhaseId phaseId = exceptionContext.getPhaseId();
    Throwable t = exceptionContext.getException();
    String key = getLoggingKey(beforePhase, afterPhase);
    if (LOGGER.isLoggable(Level.SEVERE)) {
      LOGGER.log(
          Level.SEVERE,
          key,
          new Object[] {
            t.getClass().getName(),
            phaseId.toString(),
            ((c != null) ? c.getClientId(exceptionContext.getContext()) : ""),
            t.getMessage()
          });
      LOGGER.log(Level.SEVERE, t.getMessage(), t);
    }
  }

  private String getLoggingKey(boolean beforePhase, boolean afterPhase) {
    if (beforePhase) {
      return LOG_BEFORE_KEY;
    } else if (afterPhase) {
      return LOG_AFTER_KEY;
    } else {
      return LOG_KEY;
    }
  }
}