All Downloads are FREE. Search and download functionalities are using the official Maven repository.

jakarta.faces.context.FacesContext Maven / Gradle / Ivy

Go to download

Jakarta Faces defines an MVC framework for building user interfaces for web applications, including UI components, state management, event handing, input validation, page navigation, and support for internationalization and accessibility.

There is a newer version: 4.1.2
Show newest version
/*
 * Copyright (c) 1997, 2020 Oracle and/or its affiliates. All rights reserved.
 *
 * This program and the accompanying materials are made available under the
 * terms of the Eclipse Public License v. 2.0, which is available at
 * http://www.eclipse.org/legal/epl-2.0.
 *
 * This Source Code may also be made available under the following Secondary
 * Licenses when the conditions for such availability set forth in the
 * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
 * version 2 with the GNU Classpath Exception, which is available at
 * https://www.gnu.org/software/classpath/license.html.
 *
 * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
 */

package jakarta.faces.context;

import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import com.sun.faces.config.InitFacesContext;
import jakarta.el.ELContext;
import jakarta.faces.FactoryFinder;
import jakarta.faces.application.Application;
import jakarta.faces.application.FacesMessage;
import jakarta.faces.application.FacesMessage.Severity;
import jakarta.faces.application.ProjectStage;
import jakarta.faces.component.UINamingContainer;
import jakarta.faces.component.UIViewRoot;
import jakarta.faces.event.PhaseId;
import jakarta.faces.lifecycle.Lifecycle;
import jakarta.faces.render.RenderKit;

/**
 * 

* FacesContext contains all of * the per-request state information related to the processing of a single Jakarta Faces request, and the * rendering of the corresponding response. It is passed to, and potentially modified by, each phase of the request * processing lifecycle. *

* *

* A {@link FacesContext} instance is associated with a particular request at the beginning of request processing, by a * call to the getFacesContext() method of the {@link FacesContextFactory} instance associated with the * current web application. The instance remains active until its release() method is called, after which * no further references to this instance are allowed. While a {@link FacesContext} instance is active, it must not be * referenced from any thread other than the one upon which the Jakarta Servlet container executing this web application * utilizes for the processing of this request. *

* *

* A FacesContext can be injected into a request scoped bean using @Inject FacesContext facesContext; *

*/ public abstract class FacesContext { private FacesContext defaultFacesContext; private boolean processingEvents = true; private boolean isCreatedFromValidFactory = true; private static final ConcurrentHashMap threadInitContext = new ConcurrentHashMap<>(2); private static final ConcurrentHashMap initContextServletContext = new ConcurrentHashMap<>(2); /** * Default constructor. *

* This looks at the callstack to see if we're created from a factory. *

*/ public FacesContext() { Thread curThread = Thread.currentThread(); StackTraceElement[] callstack = curThread.getStackTrace(); String declaringClassName = callstack[3].getClassName(); try { ClassLoader curLoader = curThread.getContextClassLoader(); Class declaringClass = curLoader.loadClass(declaringClassName); if (!FacesContextFactory.class.isAssignableFrom(declaringClass)) { isCreatedFromValidFactory = false; } } catch (ClassNotFoundException ignored) { } } // -------------------------------------------------------------- Properties /** *

* Return the {@link Application} instance associated with this web * application. *

* *

* It is valid to call this method during application startup or shutdown. If called during application startup or * shutdown, returns the correct current {@link jakarta.faces.application.Application} instance. *

* * @return the Application instance associated with this web application. * * @throws IllegalStateException if this method is called after this instance has been released */ public abstract Application getApplication(); /** *

* Return a mutable Map representing the attributes associated wth this FacesContext instance. * This Map is useful to store attributes that you want to go out of scope when the Faces lifecycle for the * current request ends, which is not always the same as the request ending, especially in the case of Jakarta Servlet * filters that are invoked after the Faces lifecycle for this request completes. Accessing this * Map does not cause any events to fire, as is the case with the other maps: for request, session, and * application scope. When {@link #release()} is invoked, the attributes must be cleared. *

* *
* *

* The Map returned by this method is not associated with the request. If you would like to get or set * request attributes, see {@link ExternalContext#getRequestMap}. * *

* The default implementation throws UnsupportedOperationException and is provided for the sole purpose of * not breaking existing applications that extend this class. *

* *
* * @return mutable Map representing the attributes associated wth this FacesContext instance. * * @throws IllegalStateException if this method is called after this instance has been released * * @since 2.0 */ public Map getAttributes() { if (defaultFacesContext != null) { return defaultFacesContext.getAttributes(); } if (!isCreatedFromValidFactory) { if (attributesForInvalidFactoryConstruction == null) { attributesForInvalidFactoryConstruction = new HashMap<>(); } return attributesForInvalidFactoryConstruction; } throw new UnsupportedOperationException(); } private Map attributesForInvalidFactoryConstruction; /** *

* Return the {@link PartialViewContext} for this request. The {@link PartialViewContext} is used to control the * processing of specified components during the execute portion of the request processing lifecycle (known as partial * processing) and the rendering of specified components (known as partial rendering). This method must return a new * {@link PartialViewContext} if one does not already exist. *

* * @return the instance of PartialViewContext for this request. * * @throws IllegalStateException if this method is called after this instance has been released * * @since 2.0 */ public PartialViewContext getPartialViewContext() { if (defaultFacesContext != null) { return defaultFacesContext.getPartialViewContext(); } if (!isCreatedFromValidFactory) { if (partialViewContextForInvalidFactoryConstruction == null) { PartialViewContextFactory f = (PartialViewContextFactory) FactoryFinder.getFactory(FactoryFinder.PARTIAL_VIEW_CONTEXT_FACTORY); partialViewContextForInvalidFactoryConstruction = f.getPartialViewContext(FacesContext.getCurrentInstance()); } return partialViewContextForInvalidFactoryConstruction; } throw new UnsupportedOperationException(); } private PartialViewContext partialViewContextForInvalidFactoryConstruction; /** *

* Return an Iterator over the client identifiers for which at least one * {@link jakarta.faces.application.FacesMessage} has been queued. If there are no such client identifiers, an empty * Iterator is returned. If any messages have been queued that were not associated with any specific client * identifier, a null value will be included in the iterated values. The elements in the * Iterator must be returned in the order in which they were added with {@link #addMessage}. *

* * @return the Iterator over the client identifiers for which at least one * {@link jakarta.faces.application.FacesMessage} has been queued. * * @throws IllegalStateException if this method is called after this instance has been released */ public abstract Iterator getClientIdsWithMessages(); /** *

* Return the ELContext instance for this FacesContext instance. This ELContext * instance has the same lifetime and scope as the FacesContext instance with which it is associated, and * may be created lazily the first time this method is called for a given FacesContext instance. Upon * creation of the ELContext instance, the implementation must take the following action: *

* *
    * *
  • *

    * Call the {@link ELContext#putContext} method on the instance, passing in FacesContext.class and the * this reference for the FacesContext instance itself. *

    *
  • * *
  • *

    * If the Collection returned by {@link jakarta.faces.application.Application#getELContextListeners} is * non-empty, create an instance of {@link jakarta.el.ELContextEvent} and pass it to each * {@link jakarta.el.ELContextListener} instance in the Collection by calling the * {@link jakarta.el.ELContextListener#contextCreated} method. *

    *
  • * *
* * @return instance of ELContext. * * @throws IllegalStateException if this method is called after this instance has been released * * @since 1.2 */ public ELContext getELContext() { if (defaultFacesContext != null) { return defaultFacesContext.getELContext(); } throw new UnsupportedOperationException(); } /** *

* Return the {@link ExceptionHandler} for this request. *

* * @return instance of ExceptionHandler. */ public ExceptionHandler getExceptionHandler() { if (defaultFacesContext != null) { return defaultFacesContext.getExceptionHandler(); } throw new UnsupportedOperationException(); } /** *

* Set the {@link ExceptionHandler} for this request. *

* * @param exceptionHandler the ExceptionHandler for this request. */ public void setExceptionHandler(ExceptionHandler exceptionHandler) { if (defaultFacesContext != null) { defaultFacesContext.setExceptionHandler(exceptionHandler); } else { throw new UnsupportedOperationException(); } } /** *

* Return the {@link Lifecycle} instance for this * FacesContext instance. *

* * @return instance of Lifecycle * * @throws IllegalStateException if this method is called after this instance has been released * * @since 4.0 */ public abstract Lifecycle getLifecycle(); /** *

* Return the {@link ExternalContext} instance for this * FacesContext instance. *

* *

* It is valid to call this method during application startup or shutdown. If called during application startup or * shutdown, this method returns an {@link ExternalContext} instance with the special behaviors indicated in the javadoc * for that class. Methods document as being valid to call during application startup or shutdown must be supported. *

* * @return instance of ExternalContext * * @throws IllegalStateException if this method is called after this instance has been released */ public abstract ExternalContext getExternalContext(); /** *

* Return the maximum severity level recorded on any {@link jakarta.faces.application.FacesMessage}s that has been * queued, whether or not they are associated with any specific {@link jakarta.faces.component.UIComponent}. If no such * messages have been queued, return null. *

* * @return the maximum severity level. * * @throws IllegalStateException if this method is called after this instance has been released */ public abstract Severity getMaximumSeverity(); /** *

* Return an Iterator over the {@link jakarta.faces.application.FacesMessage}s that have been queued, * whether or not they are associated with any specific client identifier. If no such messages have been queued, return * an empty Iterator. The elements of the Iterator must be returned in the order in which they * were added with calls to {@link #addMessage}. *

* * @return Iterator over the FacesMessages that have been queued. * * @throws IllegalStateException if this method is called after this instance has been released */ public abstract Iterator getMessages(); /** *

* Like {@link #getMessages}, but returns a List<FacesMessage>, enabling use from Jakarta Expression * Language expressions. *

* *

* The default implementation throws UnsupportedOperationException and is provided for the sole purpose of * not breaking existing applications that extend this class. *

* * @return an immutable List which is effectively a snapshot of the messages present at the time of * invocation. * * @throws IllegalStateException if this method is called after this instance has been released * * @since 2.0 */ public List getMessageList() { if (defaultFacesContext != null) { return defaultFacesContext.getMessageList(); } throw new UnsupportedOperationException(); } /** *

* Like {@link #getMessages(java.lang.String)}, but returns a List<FacesMessage> of messages for the * component with client id matching argument clientId. *

* *

* The default implementation throws UnsupportedOperationException and is provided for the sole purpose of * not breaking existing applications that extend this class. *

* * @param clientId the client id of a component. * * @return an immutable List which is effectively a snapshot of the messages present at the time of * invocation. * * @throws IllegalStateException if this method is called after this instance has been released * * @since 2.0 */ public List getMessageList(String clientId) { if (defaultFacesContext != null) { return defaultFacesContext.getMessageList(clientId); } throw new UnsupportedOperationException(); } /** *

* Return an Iterator over the {@link jakarta.faces.application.FacesMessage}s that have been queued that * are associated with the specified client identifier (if clientId is not null), or over the * {@link jakarta.faces.application.FacesMessage}s that have been queued that are not associated with any specific * client identifier (if clientId is null). If no such messages have been queued, return an * empty Iterator. The elements of the Iterator must be returned in the order in which they * were added with calls to {@link #addMessage}. *

* * @param clientId The client identifier for which messages are requested, or null for messages not * associated with any client identifier * * @return Iterator over the FacesMessages. * * @throws IllegalStateException if this method is called after this instance has been released */ public abstract Iterator getMessages(String clientId); /** *

* Return the result of calling {@link UINamingContainer#getSeparatorChar}, passing this as the argument. * Note that this enables accessing the value of this property from the Jakarta Expression Language expression * #{facesContext.namingContainerSeparatorChar}. *

* * @return the separator char. * */ public char getNamingContainerSeparatorChar() { return UINamingContainer.getSeparatorChar(this); } /** *

* Return the {@link RenderKit} instance for the render kit identifier specified on our {@link UIViewRoot}, if there is * one. If there is no current {@link UIViewRoot}, if the {@link UIViewRoot} does not have a specified * renderKitId, or if there is no {@link RenderKit} for the specified identifier, return null * instead. *

* * @return instance of RenderKit associated with the UIViewRoot. * * @throws IllegalStateException if this method is called after this instance has been released */ public abstract RenderKit getRenderKit(); /** *

* Return true if the renderResponse() method has been called for the current request. *

* * @return flag indicating whether the renderResponse() has been called. * * @throws IllegalStateException if this method is called after this instance has been released */ public abstract boolean getRenderResponse(); /** *

* Return true if the responseComplete() method has been called for the current request. *

* * @return the boolean indicating whether responseComplete() method has been called. * * @throws IllegalStateException if this method is called after this instance has been released */ public abstract boolean getResponseComplete(); /** *

* Return the list of resource library contracts that have been calculated to be appropriate for use with this view, or * an empty list if there are no such resource library contracts. The list returned by this method must be immutable. * For backward compatibility with implementations of the specification prior to when this method was introduced, an * implementation is provided that returns an empty list. Implementations compliant with the version in which this * method was introduced must implement this method as specified. *

* * @return the list of resource library contracts. * * @throws IllegalStateException if this method is called after this instance has been released * * @since 2.2 */ public List getResourceLibraryContracts() { return Collections.emptyList(); } /** *

* Set the resource library contracts calculated as valid to use with this view. The implementation must copy the * contents of the incoming {@code List} into an immutable {@code List} for return from * {@link #getResourceLibraryContracts}. If the argument is {@code null} or empty, the action taken is the same as if * the argument is {@code null}: a subsequent call to {@code getResourceLibraryContracts} returns {@code null}. This * method may only be called during the processing of {@link jakarta.faces.view.ViewDeclarationLanguage#createView} and * during the VDL tag handler for the tag corresponding to an instance of {@code UIViewRoot}. For backward compatibility * with implementations of the specification prior to when this method was introduced, an implementation is provided * that takes no action. Implementations compliant with the version in which this method was introduced must implement * this method as specified. * *

* * @param contracts The new contracts to be returned, as an immutable {@code List}. from a subsequent call to * {@link #getResourceLibraryContracts}. * * @throws IllegalStateException if this method is called after this instance has been released * * @since 2.2 * */ public void setResourceLibraryContracts(List contracts) { } /** *

* Return true if the validationFailed() method has been called for the current request. *

* * @return boolean indicating if the validationFailed() method has been called for the current request * * @throws IllegalStateException if this method is called after this instance has been released */ public boolean isValidationFailed() { if (defaultFacesContext != null) { return defaultFacesContext.isValidationFailed(); } throw new UnsupportedOperationException(); } /** *

* Return the {@link ResponseStream} to which components should direct their binary output. Within a given response, * components can use either the ResponseStream or the ResponseWriter, but not both. * * @return ResponseStream instance. * * @throws IllegalStateException if this method is called after this instance has been released */ public abstract ResponseStream getResponseStream(); /** *

* Set the {@link ResponseStream} to which components should direct their binary output. * * @param responseStream The new ResponseStream for this response * * @throws NullPointerException if responseStream is null * * @throws IllegalStateException if this method is called after this instance has been released */ public abstract void setResponseStream(ResponseStream responseStream); /** *

* Return the {@link ResponseWriter} to which components should direct their character-based output. Within a given * response, components can use either the ResponseStream or the ResponseWriter, but not both. *

* * @return ResponseWriter instance. * * @throws IllegalStateException if this method is called after this instance has been released */ public abstract ResponseWriter getResponseWriter(); /** *

* Set the {@link ResponseWriter} to which components should direct their character-based output. * * @param responseWriter The new ResponseWriter for this response * * @throws IllegalStateException if this method is called after this instance has been released * @throws NullPointerException if responseWriter is null */ public abstract void setResponseWriter(ResponseWriter responseWriter); /** *

* Return the root component that is associated with the this request. *

* *

* It is valid to call this method during application startup or shutdown. If called during application startup or * shutdown, this method returns a new UIViewRoot with its locale set to Locale.getDefault(). *

* * @return UIViewRoot instance. * * @throws IllegalStateException if this method is called after this instance has been released */ public abstract UIViewRoot getViewRoot(); /** *

* Set the root component that is associated with this * request. * *

* This method can be called by the application handler (or a class that the handler calls), during the Invoke * Application phase of the request processing lifecycle and during the Restore View phase of the request * processing lifecycle (especially when a new root component is created). In the present version of the specification, * implementations are not required to enforce this restriction, though a future version of the specification may * require enforcement. *

* *

* If the current UIViewRoot is non-null, and calling equals() on the argument * root, passing the current UIViewRoot returns false, the clear * method must be called on the Map returned from {@link UIViewRoot#getViewMap}. *

* * @param root The new component {@link UIViewRoot} component * * @throws IllegalStateException if this method is called after this instance has been released * @throws NullPointerException if root is null */ public abstract void setViewRoot(UIViewRoot root); // ---------------------------------------------------------- Public Methods /** *

* Append a {@link jakarta.faces.application.FacesMessage} to the set of messages associated with the specified client * identifier, if clientId is not null. If clientId is null, this * {@link jakarta.faces.application.FacesMessage} is assumed to not be associated with any specific component instance. *

* * @param clientId The client identifier with which this message is associated (if any) * @param message The message to be appended * * @throws IllegalStateException if this method is called after this instance has been released * @throws NullPointerException if message is null */ public abstract void addMessage(String clientId, FacesMessage message); /** *

* Return a flag indicating if the resources associated with this FacesContext instance have been released. *

* * @return true if the resources have been released. * * @since 2.1 */ public boolean isReleased() { if (defaultFacesContext != null) { return defaultFacesContext.isReleased(); } throw new UnsupportedOperationException(); } /** *

* Release any resources associated with this FacesContext * instance. Faces implementations may choose to pool instances in the associated {@link FacesContextFactory} to avoid * repeated object creation and garbage collection. After release() is called on a * FacesContext instance (until the FacesContext instance has been recycled by the * implementation for re-use), calling any other methods will cause an IllegalStateException to be thrown. *

* *

* If a call was made to {@link #getAttributes} during the processing for this request, the implementation must call * clear() on the Map returned from getAttributes(), and then de-allocate the * data-structure behind that Map. *

* *

* The implementation must call {@link #setCurrentInstance} passing null to remove the association between * this thread and this dead FacesContext instance. *

* * @throws IllegalStateException if this method is called after this instance has been released */ public abstract void release(); /** *

* Signal the Jakarta Faces implementation that, as soon as the current phase of the request processing lifecycle * has been completed, control should be passed to the Render Response phase, bypassing any phases that have * not been executed yet. *

* * @throws IllegalStateException if this method is called after this instance has been released */ public abstract void renderResponse(); /** *

* This utility method simply returns the result of * {@link jakarta.faces.render.ResponseStateManager#isPostback(FacesContext)}. *

* *

* The default implementation throws UnsupportedOperationException and is provided for the sole purpose of * not breaking existing applications that extend this class. *

* * @return the boolean indicating whether this request is a post one. * * @throws IllegalStateException if this method is called after this instance has been released * * @since 2.0 */ public boolean isPostback() { if (defaultFacesContext != null) { return defaultFacesContext.isPostback(); } throw new UnsupportedOperationException(); } /** *

* Signal the Jakarta Faces implementation that the HTTP response for this request has already been generated * (such as an HTTP redirect), and that the request processing lifecycle should be terminated as soon as the current * phase is completed. *

* * @throws IllegalStateException if this method is called after this instance has been released */ public abstract void responseComplete(); /** *

* Sets a flag which indicates that a conversion or validation error occurred while processing the inputs. Inputs * consist of either page parameters or form bindings. This flag can be read using {@link #isValidationFailed}. *

* * @throws IllegalStateException if this method is called after this instance has been released */ public void validationFailed() { if (defaultFacesContext != null) { defaultFacesContext.validationFailed(); } else { throw new UnsupportedOperationException(); } } /** *

* Return the value last set on this FacesContext instance when {@link #setCurrentPhaseId} was called. *

* * @return the current phase id. * * @throws IllegalStateException if this method is called after this instance has been released * * @since 2.0 */ public PhaseId getCurrentPhaseId() { if (defaultFacesContext != null) { return defaultFacesContext.getCurrentPhaseId(); } if (!isCreatedFromValidFactory) { return currentPhaseIdForInvalidFactoryConstruction; } throw new UnsupportedOperationException(); } /** *

* The implementation must call this method at the earliest possble point in time after entering into a new phase in the * request processing lifecycle. *

* * @param currentPhaseId The {@link jakarta.faces.event.PhaseId} for the current phase. * * @throws IllegalStateException if this method is called after this instance has been released * * @since 2.0 */ public void setCurrentPhaseId(PhaseId currentPhaseId) { if (defaultFacesContext != null) { defaultFacesContext.setCurrentPhaseId(currentPhaseId); } else if (!isCreatedFromValidFactory) { currentPhaseIdForInvalidFactoryConstruction = currentPhaseId; } else { throw new UnsupportedOperationException(); } } private PhaseId currentPhaseIdForInvalidFactoryConstruction; /** *

* Allows control of wheter or not the runtime will publish events when * {@link Application#publishEvent(FacesContext, Class, Object)} or * {@link Application#publishEvent(FacesContext, Class, Class, Object)} is called. *

* * @param processingEvents flag indicating events should be processed or not */ public void setProcessingEvents(boolean processingEvents) { this.processingEvents = processingEvents; } /** *

* Returns a flag indicating whether or not the runtime should publish events when asked to do so. *

* * @return true if events should be published, otherwise false */ public boolean isProcessingEvents() { return processingEvents; } /** *

* Return true if the current {@link ProjectStage} as returned by the {@link Application} instance is equal * to stage, otherwise return false *

* * @param stage the {@link ProjectStage} to check * * @return boolean indicating whether the application has the same stage. * * @throws IllegalStateException if this method is called after this instance has been released * @throws NullPointerException if stage is null */ public boolean isProjectStage(ProjectStage stage) { if (stage == null) { throw new NullPointerException(); } return stage.equals(getApplication().getProjectStage()); } // ---------------------------------------------------------- Static Methods /** *

* The ThreadLocal variable used to record the {@link FacesContext} instance for each processing thread. *

*/ private static final ThreadLocal instance = ThreadLocal.withInitial(() -> null); /** *

* Return the {@link FacesContext} instance for the request that is being processed by the current thread. If called * during application initialization or shutdown, any method documented as "valid to call this method during application * startup or shutdown" must be supported during application startup or shutdown time. The result of calling a method * during application startup or shutdown time that does not have this designation is undefined. *

* * @return the instance of FacesContext. */ public static FacesContext getCurrentInstance() { FacesContext facesContext = instance.get(); if (null == facesContext) { facesContext = threadInitContext.get(Thread.currentThread()); } // Bug 20458755: If not found in the threadInitContext, use // a special FacesContextFactory implementation that knows how to // use the initContextServletContext map to obtain current ServletContext // out of thin air (actually, using the current ClassLoader), and use it // to obtain the init FacesContext corresponding to that ServletContext. if (null == facesContext) { // In the non-init case, this will immediately return null. // In the init case, this will return null if Jakarta Faces hasn't been // initialized in the ServletContext corresponding to this // Thread's context ClassLoader. ClassLoader cl = Thread.currentThread().getContextClassLoader(); if (cl == null) { return null; } FacesContextFactory privateFacesContextFactory = (FacesContextFactory) FactoryFinder.getFactory("com.sun.faces.ServletContextFacesContextFactory"); if (null != privateFacesContextFactory) { facesContext = privateFacesContextFactory.getFacesContext(null, null, null, null); } } return facesContext; } /** *

* Set the {@link FacesContext} instance for the request that is being processed by the current thread. *

* * @param context The {@link FacesContext} instance for the current thread, or null if this thread no * longer has a FacesContext instance. * */ protected static void setCurrentInstance(FacesContext context) { if (context == null) { instance.remove(); } else { instance.set(context); } } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy