javax.faces.view.ViewDeclarationLanguage Maven / Gradle / Ivy
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright (c) 1997-2010 Oracle and/or its affiliates. All rights reserved.
*
* The contents of this file are subject to the terms of either the GNU
* General Public License Version 2 only ("GPL") or the Common Development
* and Distribution License("CDDL") (collectively, the "License"). You
* may not use this file except in compliance with the License. You can
* obtain a copy of the License at
* https://glassfish.dev.java.net/public/CDDL+GPL_1_1.html
* or packager/legal/LICENSE.txt. See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each
* file and include the License file at packager/legal/LICENSE.txt.
*
* GPL Classpath Exception:
* Oracle designates this particular file as subject to the "Classpath"
* exception as provided by Oracle in the GPL Version 2 section of the License
* file that accompanied this code.
*
* Modifications:
* If applicable, add the following below the License Header, with the fields
* enclosed by brackets [] replaced by your own identifying information:
* "Portions Copyright [year] [name of copyright owner]"
*
* Contributor(s):
* If you wish your version of this file to be governed by only the CDDL or
* only the GPL Version 2, indicate your decision by adding "[Contributor]
* elects to include this software in this distribution under the [CDDL or GPL
* Version 2] license." If you don't indicate a single choice of license, a
* recipient has the option to distribute your version of this file under
* either the CDDL, the GPL Version 2 or to extend the choice of license to
* its licensees as provided above. However, if you add GPL Version 2 code
* and therefore, elected the GPL Version 2 license, then the option applies
* only if the new code is made subject to such option by the copyright
* holder.
*/
package javax.faces.view;
import java.beans.BeanInfo;
import java.io.IOException;
import java.net.MalformedURLException;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.faces.application.Resource;
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";
/**
* 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.6.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.
*/
public abstract BeanInfo getComponentMetadata(FacesContext context, Resource componentResource);
/**
* 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.6.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
*/
public abstract ViewMetadata getViewMetadata(FacesContext context, String viewId);
/**
* Take implementation specific action
* to discover a Resource
given the argument
* componentResource
. See section JSF.7.6.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.
*/
public abstract Resource getScriptComponentResource(FacesContext context,
Resource componentResource);
/**
* Create a UIViewRoot
* from the VDL contained in the artifact referenced by the argument
* viewId
. See section JSF.7.6.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
*/
public abstract UIViewRoot createView(FacesContext context,
String viewId);
/**
* Restore a UIViewRoot
* from a previously created view. See section JSF.7.6.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
*/
public abstract UIViewRoot restoreView(FacesContext context, String viewId);
/**
* 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.
*
* @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
}
/**
* 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.
*/
public abstract void buildView(FacesContext context, UIViewRoot root)
throws IOException;
/**
* Render a view rooted at
* argumentview
. See section JSF.7.6.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
*/
public abstract void renderView(FacesContext context,
UIViewRoot view)
throws IOException;
/**
* 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.
*
*
* @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
* ExternalContext.getResource()
to locate the physical
* resource.
*
* @param context The FacesContext
for this request.
* @param viewId the view id to test
*
* @since 2.1
*/
public boolean viewExists(FacesContext context,
String viewId) {
try {
return context.getExternalContext().getResource(viewId) != null;
} catch (MalformedURLException e) {
if (LOGGER.isLoggable(Level.SEVERE)) {
LOGGER.log(Level.SEVERE,
e.toString(),
e);
}
}
return false;
}
/**
* 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.
*
* @since 2.1
*/
public String getId() {
return getClass().getName();
}
private static final Logger LOGGER =
Logger.getLogger("javax.faces.view", "javax.faces.LogStrings");
}