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
/** * 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; } } }
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; } } }