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

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

The 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 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 - 2024 Weber Informatics LLC | Privacy Policy