javax.faces.view.ViewDeclarationLanguage Maven / Gradle / Ivy
Show all versions of jboss-javaee-all-8.0
/*
* Copyright (c) 1997, 2018 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 javax.faces.view;
import static javax.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 javax.faces.application.Resource;
import javax.faces.application.ViewVisitOption;
import javax.faces.component.UIComponent;
import javax.faces.component.UIViewRoot;
import javax.faces.context.FacesContext;
/**
* The contract that a view declaration
* language must implement to interact with the JSF 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 JSP view declaration
* language.
*
* @since 2.1
*/
public final static String JSP_VIEW_DECLARATION_LANGUAGE_ID =
"java.faces.JSP";
/**
* 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 JSF.7.7.2 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 JSF.7.7.2 for the specification of the
* default implementation. Facelets for JSF 2 implementation must
* return non-null
. JSP implementations must return
* null
.
*
* @param context The FacesContext
for this request.
* @param viewId the view id from whith to extract the metadata
* @since 2.0
*
* @throws NullPointerException if any of the arguments are
* null
.
*
* @throws javax.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 JSF.7.7.2 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
* javax.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 javax.faces.event.PhaseListener#afterPhase}
* method of any PhaseListener
s attached to the
* application is called
* The {@link javax.faces.component.UIViewRoot} phase
* listener installed via {@link
* javax.faces.component.UIViewRoot#setAfterPhaseListener} or {@link
* javax.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 JSF.7.7.2 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 JSF.7.7.2 for the
* specification of the default implementation. JSP 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 javax.faces.FacesException if there is an error in
* obtaining the metadata
*
* @throws UnsupportedOperationException if this is a JSP 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 JSF.7.7.2 for the
* specification of the default implementation. JSP 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 javax.faces.FacesException if there is an error in
* obtaining the script component resource
* @throws UnsupportedOperationException if this is a JSP 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 javax.faces.component.ActionSource2}.
*
* If name is equal to the string "validator", or
* "valueChangeListener" without the quotes, assume
* target is an {@link
* javax.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
* javax.faces.component.ActionSource2#setActionExpression} on
* target, passing attributeMethodExpression.
*
* If name is equal to the string
* "actionListener" without the quotes, call {@link
* javax.faces.component.ActionSource#addActionListener} on
* target, passing attributeMethodExpression
* wrapped in a {@link javax.faces.event.MethodExpressionActionListener}.
*
* If name is equal to the string
* "validator" without the quotes, call {@link
* javax.faces.component.EditableValueHolder#addValidator} on target,
* passing attributeMethodExpression wrapped in a {@link
* javax.faces.validator.MethodExpressionValidator}.
*
* If name is equal to the string
* "valueChangeListener" without the quotes, call {@link
* javax.faces.component.EditableValueHolder#addValueChangeListener} on
* target, passing attributeMethodExpression wrapped in a
* {@link javax.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 JSF.7.7.2 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
* JSF.7.7.2.
*
* @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 JSF 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 javax.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();
}
}