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

jakarta.faces.view.ViewDeclarationLanguage Maven / Gradle / Ivy

/*
 * 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.view;

import static jakarta.faces.application.ResourceVisitOption.TOP_LEVEL_VIEWS_ONLY;

import java.beans.BeanInfo;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.stream.Stream;

import jakarta.faces.application.Resource;
import jakarta.faces.application.ViewVisitOption;
import jakarta.faces.component.UIComponent;
import jakarta.faces.component.UIViewRoot;
import jakarta.faces.context.FacesContext;

/**
 * 

* The contract that a view * declaration language must implement to interact with the Jakarta Faces runtime. An implementation of this * class must be thread-safe. *

* *
* *

* Instances of this class are application scoped and must be obtained from the {@link ViewDeclarationLanguageFactory}. *

* *
* * @since 2.0 */ public abstract class ViewDeclarationLanguage { /** *

* Identifier for the Facelets view declaration language. *

* * @since 2.1 */ public final static String FACELETS_VIEW_DECLARATION_LANGUAGE_ID = "java.faces.Facelets"; /** *

* Restore a UIViewRoot from a previously created view. * See section 7.7.2 "Default ViewDeclarationLanguage Implementation" of the Jakarta Faces Specification Document * for the specification of the default implementation. *

* * @param context the FacesContext for this request. * @param viewId the identifier for a previously rendered view. * * @throws NullPointerException if any of the arguments are null * * @return the restored view */ public abstract UIViewRoot restoreView(FacesContext context, String viewId); /** *

* Return a reference to the view metadata for the view represented by the argument viewId, or * null if the metadata cannot be found. * See section 7.7.2 "Default ViewDeclarationLanguage Implementation" of the Jakarta Faces Specification Document * for the specification of the default * implementation. Facelets implementation must return non-null. *

* * @param context The FacesContext for this request. * @param viewId the view id from which to extract the metadata * @since 2.0 * * @throws NullPointerException if any of the arguments are null. * * @throws jakarta.faces.FacesException if there is an error in obtaining the metadata * * @return the view metadata */ public abstract ViewMetadata getViewMetadata(FacesContext context, String viewId); /** *

* Create a UIViewRoot from the VDL contained in the artifact * referenced by the argument viewId. * See section 7.7.2"Default ViewDeclarationLanguage Implementation" of the Jakarta Faces Specification Document * for the specification of the default implementation. *

* * @param context the FacesContext for this request. * @param viewId the identifier of an artifact that contains the VDL syntax that describes this view. * * @throws NullPointerException if any of the arguments are null * * @since 2.0 * * @return the newly created view root */ public abstract UIViewRoot createView(FacesContext context, String viewId); /** *

* Take any actions specific to this VDL implementation to cause the argument * UIViewRoot which must have been created via a call to {@link #createView}, to be populated with * children. *

* *
* *

* The Facelets implementation must insure that markup comprising the view must be executed, with the * {@link jakarta.faces.component.UIComponent} instances in the view being encountered in the same depth-first order as * in other lifecycle methods defined on UIComponent, and added to the view (but not rendered) during the * traversal. The runtime must guarantee that the view must be fully populated before any of the following happen. *

*
    * *
  • *

    * The {@link jakarta.faces.event.PhaseListener#afterPhase} method of any PhaseListeners attached to the * application is called *

    *
  • *
  • *

    * The {@link jakarta.faces.component.UIViewRoot} phase listener installed via * {@link jakarta.faces.component.UIViewRoot#setAfterPhaseListener} or * {@link jakarta.faces.component.UIViewRoot#addPhaseListener} are called. *

    *
  • * *
*

* If the root is already populated with children, the view must still be re-built, but care must be taken * to ensure that the existing components are correctly paired up with their VDL counterparts in the VDL page. Also, any * system events that would normally be generated during the adding or removing of components from the view must be * temporarily disabled during the creation of the view and then re-enabled when the view has been built. *

*
* * @param context the FacesContext for this request * @param root the UIViewRoot to populate with children using techniques specific to this VDL * implementation. * * @throws IOException if view cannot be built for any reason */ public abstract void buildView(FacesContext context, UIViewRoot root) throws IOException; /** *

* Render a view rooted at argumentview. * See section 7.7.2 "Default ViewDeclarationLanguage Implementation" of the Jakarta Faces Specification Document * for the specification of the default implementation. *

* * @param context the FacesContext for this request. * @param view the UIViewRoot from an early call to {@link #createView} or {@link #restoreView}. * * @throws NullPointerException if any of the arguments are null * * @throws IOException if the view cannot be rendered for any reason */ public abstract void renderView(FacesContext context, UIViewRoot view) throws IOException; /** *

* Return a reference to the component metadata for the composite component represented by the argument * componentResource, or null if the metadata cannot be found. * See section 7.7.2 "Default ViewDeclarationLanguage Implementation" of the Jakarta Faces Specification Document * for the specification of the default implementation. Jakarta Server Pages implementations must throw * UnsupportedOperationException. *

* * @param context The FacesContext for this request. * @param componentResource The Resource that represents the component. * @since 2.0 * * @throws NullPointerException if any of the arguments are null. * * @throws jakarta.faces.FacesException if there is an error in obtaining the metadata * * @throws UnsupportedOperationException if this is a Jakarta Server Pages VDL implementation. * * @return the component metadata */ public abstract BeanInfo getComponentMetadata(FacesContext context, Resource componentResource); /** *

* Take implementation specific action to discover a Resource given the argument * componentResource. * See section 7.7.2 "Default ViewDeclarationLanguage Implementation" of the Jakarta Faces Specification Document * for the specification of the default implementation. Jakarta * Server Pages implementations must throw UnsupportedOperationException. *

* * @param context The FacesContext for this request. * @param componentResource The Resource that represents the component. * @since 2.0 * * @throws NullPointerException if any of the arguments are null. * * @throws jakarta.faces.FacesException if there is an error in obtaining the script component resource * @throws UnsupportedOperationException if this is a Jakarta Server Pages VDL implementation. * * @return the {@link Resource} corresponding to the argument {@code * componentResource} */ public abstract Resource getScriptComponentResource(FacesContext context, Resource componentResource); /** *

* Create a component given a {@link ViewDeclarationLanguage} specific tag library URI and tag name. The runtime must * support this method operating for the Facelets VDL. Other kinds of {@code ViewDeclarationLanguage} may be supported * but are not required to be supported. For backward compatibility with decorated {@code ViewDeclrationLanguage} * implementations that do not override this method, a default implementation is provided that returns {@code null}. * However, any implementation that is compliant with the version of the specification in which this method was * introduced must implement this method. *

* * @param context the {@link FacesContext} for this request * @param taglibURI the fully qualified tag library URI that contains the component * @param tagName the name of the tag within that library that exposes the component * @param attributes any name=value pairs that would otherwise have been given on the markup that would cause the * creation of this component or {@code null} if no attributes need be given. * * @throws NullPointerException if {@code context}, {@code taglibURI}, or {@code tagName} are {@code null} * * @since 2.2 * * @return the newly created component */ public UIComponent createComponent(FacesContext context, String taglibURI, String tagName, Map attributes) { return null; } /** *

* Assuming the component metadata for argument * topLevelComponent has been made available by an earlier call to * {@link ViewDeclarationLanguage#getComponentMetadata}, leverage the component metadata for the purpose of re-targeting * attached objects from the top level composite component to the individual {@link AttachedObjectTarget} instances * inside the composite component. This method must be called by the {@link ViewDeclarationLanguage} implementation when * creating the UIComponent tree when a composite component usage is encountered. *

* *
* *

* An algorithm semantically equivalent to the following must be implemented. *

* *
    * *
  • *

    * Obtain the metadata for the composite component. Currently this entails getting the value of the * {@link UIComponent#BEANINFO_KEY} component attribute, which will be an instance of BeanInfo. If the * metadata cannot be found, log an error message and return. *

    *
  • * *
  • *

    * Get the BeanDescriptor from the BeanInfo. *

    *
  • * *
  • *

    * Get the value of the {@link AttachedObjectTarget#ATTACHED_OBJECT_TARGETS_KEY} from the BeanDescriptor's * getValue() method. This will be a List<{@link *AttachedObjectTarget}>. Let this be targetList. *

    *
  • * *
  • *

    * For each curHandler entry in the argument handlers *

    * *
      * *
    • *

      * Let forAttributeValue be the return from {@link AttachedObjectHandler#getFor}. *

      *
    • * *
    • *

      * For each curTarget entry in targetList, the first of the following items that causes a match will * take this action: *

      * *

      * For each UIComponent in the list returned from curTarget.getTargets(), call * curHandler.applyAttachedObject(), passing the * FacesContext and the UIComponent. *

      * *

      * and cause this inner loop to terminate. *

      * *
        * *
      • *

        * If curHandler is an instance of {@link ActionSource2AttachedObjectHandler} and curTarget is an * instance of {@link ActionSource2AttachedObjectTarget}, and curTarget.getName() is equal to * curTargetName, consider it a match. *

        *
      • * *
      • *

        * If curHandler is an instance of {@link EditableValueHolderAttachedObjectHandler} and curTarget is * an instance of {@link EditableValueHolderAttachedObjectTarget}, and * curTarget.getName() is equal to curTargetName, consider it a match. *

        *
      • * *
      • *

        * If curHandler is an instance of {@link ValueHolderAttachedObjectHandler} and curTarget is an * instance of {@link ValueHolderAttachedObjectTarget}, and curTarget.getName() is equal to * curTargetName, consider it a match. *

        *
      • * *
      • *

        * If curHandler is an instance of {@link BehaviorHolderAttachedObjectHandler} and curTarget is an * instance of {@link BehaviorHolderAttachedObjectTarget}, and either of the following conditions are true, *

        * *
          * *
        • curHandler.getEventName() is not null and is equal to curTargetName.
        • * *
        • curHandler.getEventName() is null and curTarget.isDefaultEvent() is * true.
        • * *
        * *

        * consider it a match. *

        *
      • * *
      *
    • *
    *
  • *
* *

* The implementation must support retargeting attached objects from the top level compsite component to targets that * are composite and non-composite components. *

* *

* An implementation is provided that will throw UnsupportedOperationException. A Faces implementation * compliant with version 2.0 and beyond of the specification must override this method. *

* *
* * @param context the FacesContext for this request. * * @param topLevelComponent The UIComponent in the view to which the attached objects must be attached. This UIComponent * must have its component metadata already associated and available from via the JavaBeans API. * * @param handlers the tag handlers for the attached objects * * @throws NullPointerException if any of the arguments are null. * * @since 2.0 */ public void retargetAttachedObjects(FacesContext context, UIComponent topLevelComponent, List handlers) { // no-op } /** *

* Assuming the component metadata for argument topLevelComponent has been made available by an earlier * call to {@link ViewDeclarationLanguage#getComponentMetadata}, leverage the component metadata for the purpose of * re-targeting any method expressions from the top level component to the appropriate inner component. For each * attribute that is a MethodExpression (as indicated by the presence of a "method-signature" * attribute and the absence of a "type" attribute), the following action must be taken: *

* *
* *
    * *
  • *

    * Get the value of the targets attribute. If the value is a ValueExpression evaluate it. If there * is no targets attribute, let the name of the metadata element be the evaluated value of the targets * attribute. *

    *
  • * *
  • *

    * Interpret targets as a space (not tab) separated list of ids. For each entry in the list: *

    * *
      * *
    • *

      * Find the inner component of the topLevelComponent with the id equal to the current list entry. For * discussion, this component is called target. If not found, log and error and continue to the next attribute. *

      *
    • * *
    • *

      * For discussion the declared name of the attribute is called name. *

      *
    • * *
    • *

      * In the attributes map of the topLevelComponent, look up the entry under the key name. Assume the * result is a ValueExpression. For discussion, this is attributeValueExpression. If not found, * log an error and continue to the next attribute. *

      *
    • * *
    • *

      * If name is equal to the string "action", or "actionListener" without the quotes, assume target is * an {@link jakarta.faces.component.ActionSource2}. *

      *
    • * *
    • *

      * If name is equal to the string "validator", or "valueChangeListener" without the quotes, assume * target is an {@link jakarta.faces.component.EditableValueHolder}. *

      *
    • * *
    • *

      * Call getExpressionString() on the attributeValueExpression and use that string to create a * MethodExpression of the appropriate signature for name. *

      *
    • * *
    • *

      * If name is not equal to any of the previously listed strings, call getExpressionString() on the * attributeValueExpression and use that string to create a MethodExpression where the signature * is created based on the value of the "method-signature" attribute of the * <composite:attribute /> tag. *

      *
    • * *
    • *

      * Let the resultant MethodExpression be called attributeMethodExpression for discussion. *

      *
    • * *
    • *

      * If name is equal to the string "action" without the quotes, call * {@link jakarta.faces.component.ActionSource2#setActionExpression} on target, passing * attributeMethodExpression. *

      *
    • * *
    • *

      * If name is equal to the string "actionListener" without the quotes, call * {@link jakarta.faces.component.ActionSource#addActionListener} on target, passing * attributeMethodExpression wrapped in a {@link jakarta.faces.event.MethodExpressionActionListener}. *

      *
    • * *
    • *

      * If name is equal to the string "validator" without the quotes, call * {@link jakarta.faces.component.EditableValueHolder#addValidator} on target, passing * attributeMethodExpression wrapped in a {@link jakarta.faces.validator.MethodExpressionValidator}. *

      *
    • * *
    • *

      * If name is equal to the string "valueChangeListener" without the quotes, call * {@link jakarta.faces.component.EditableValueHolder#addValueChangeListener} on target, passing * attributeMethodExpression wrapped in a {@link jakarta.faces.event.MethodExpressionValueChangeListener}. *

      *
    • * *
    • *

      * Otherwise, assume that the MethodExpression should be placed in the components attribute set. The runtme * must create the MethodExpression instance based on the value of the "method-signature" * attribute. *

      *
    • *
    * *
  • * *
* *

* An implementation is provided that will throw UnsupportedOperationException. A Faces implementation * compliant with version 2.0 and beyond of the specification must override this method. *

* *
* * @param context the FacesContext for this request. * * @param topLevelComponent The UIComponent in the view to which the attached objects must be attached. This UIComponent * must have its component metadata already associated and available from via the JavaBeans API. * * @throws NullPointerException if context or topLevelComponent is null. * * @since 2.0 */ public void retargetMethodExpressions(FacesContext context, UIComponent topLevelComponent) { // no-op } /** *

* Return the list of resource library contracts that will be made available for use in the view specified by the * argument {@code viewId}. If no match is found, return an empty list. * See section 7.7.2 "Default ViewDeclarationLanguage Implementation" of the Jakarta Faces Specification Document for the specification of * the default implementation. For backward compatibility with prior implementations, an implementation is provided that * returns {@code null}, but any implementation compliant with the version of the specification in which this method was * introduced must implement it as specified in * section 7.7.2 "Default ViewDeclarationLanguage Implementation" of the Jakarta Faces Specification Document. *

* * @param context the {@code FacesContext} for this request * @param viewId the view id for which the applicable resource library contracts should be calculated. * * @since 2.2 * * @return the calculated list of resource library contract names */ public List calculateResourceLibraryContracts(FacesContext context, String viewId) { return null; } /** *

* For implementations that want to control the implementation of state saving and restoring, the * {@link StateManagementStrategy} allows them to do so. Returning null indicates that the implementation * wishes the runtime to handle the state saving and restoring. Implementations that provide the VDL for Facelets for * Jakarta Faces 2.0 and later must return non-null from this method. *

* * @param context the {@code FacesContext} for the current request. * * @param viewId the view id. * * @return the strategy as specified above * * @since 2.0 */ public abstract StateManagementStrategy getStateManagementStrategy(FacesContext context, String viewId); /** *

* Tests whether a physical resource corresponding to the specified viewId * exists. *

* *

* The default implementation uses {@link jakarta.faces.application.ResourceHandler#createViewResource} to locate the * physical resource. *

* * @param context The FacesContext for this request. * @param viewId the view id to test * * @return the result as specified above * * @since 2.1 */ public boolean viewExists(FacesContext context, String viewId) { return context.getApplication().getResourceHandler().createViewResource(context, viewId) != null; } /** *

* Return a {@code Stream} possibly lazily populated by walking the view tree rooted at a given initial path. The view * tree is traversed breadth-first, the elements in the stream are logical view ids. *

* *

* This method works as if invoking it were equivalent to evaluating the expression:

* *
     * getViewResources(facesContext, start, Integer.MAX_VALUE, options)
     * 
* *
Put differently, it visits all levels of the resource tree. * * @param facesContext The {@link FacesContext} for this request. * @param path The initial path from which to start looking for views * @param options The options to influence the traversal. See {@link ViewVisitOption} for details on those. * * @return the {@link Stream} of view ids * * @since 2.3 */ public Stream getViews(FacesContext facesContext, String path, ViewVisitOption... options) { return facesContext.getApplication().getResourceHandler().getViewResources(facesContext, path, TOP_LEVEL_VIEWS_ONLY); } /** *

* Return a {@code Stream} possibly lazily populated by walking the view tree rooted at a given initial path. The view * tree is traversed breadth-first, the elements in the stream are logical view ids. *

* *

* The {@code maxDepth} parameter is the maximum depth of directory levels to visit beyond the initial path, * which is always visited. The value is relative to the root ({@code /}), not to the given initial path. E.g. given * {@code maxDepth} = {@code 3} and initial path {@code /foo/}, visiting will proceed up to {@code /foo/bar/}, where * {@code /} counts as depth {@code 1}, {@code /foo/} as depth {@code 2} and {@code /foo/bar/} as depth {@code 3}. A * value lower or equal to the depth of the initial path means that only the initial path is visited. A value of * {@link Integer#MAX_VALUE MAX_VALUE} may be used to indicate that all levels should be visited. * * @param facesContext The {@link FacesContext} for this request. * @param path The initial path from which to start looking for views * @param maxDepth The absolute maximum depth of nested directories to visit counted from the root ({@code /}). * @param options The options to influence the traversal. See {@link ViewVisitOption} for details on those. * * @return the {@link Stream} of view ids * * @since 2.3 */ public Stream getViews(FacesContext facesContext, String path, int maxDepth, ViewVisitOption... options) { return facesContext.getApplication().getResourceHandler().getViewResources(facesContext, path, maxDepth, TOP_LEVEL_VIEWS_ONLY); } /** *

* Returns a non-null String that can be used to identify this view declaration language. *

* *

* The default implementation returns the fully qualified class name of the view declaration language implementation. * Subclasses may override to provide a more meaningful id. *

* * @return the id of this view declaration language * * @since 2.1 */ public String getId() { return getClass().getName(); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy