
com.sun.faces.application.view.FaceletViewHandlingStrategy Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of javax.faces Show documentation
Show all versions of javax.faces Show documentation
This is the master POM file for Oracle's Implementation of the JSF 2.1 Specification.
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright (c) 1997-2013 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.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 com.sun.faces.application.view;
import com.sun.faces.RIConstants;
import com.sun.faces.application.ApplicationAssociate;
import com.sun.faces.config.WebConfiguration;
import com.sun.faces.context.StateContext;
import javax.faces.view.facelets.Facelet;
import com.sun.faces.facelets.el.ContextualCompositeMethodExpression;
import com.sun.faces.facelets.el.VariableMapperWrapper;
import com.sun.faces.facelets.impl.DefaultFaceletFactory;
import com.sun.faces.facelets.tag.composite.CompositeComponentBeanInfo;
import com.sun.faces.facelets.tag.jsf.CompositeComponentTagHandler;
import com.sun.faces.facelets.tag.ui.UIDebug;
import com.sun.faces.scripting.groovy.GroovyHelper;
import com.sun.faces.util.Cache.Factory;
import com.sun.faces.util.Cache;
import com.sun.faces.util.FacesLogger;
import com.sun.faces.util.HtmlUtils;
import com.sun.faces.util.RequestStateManager;
import com.sun.faces.util.Util;
import java.beans.BeanDescriptor;
import java.beans.BeanInfo;
import java.beans.PropertyDescriptor;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.Writer;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.el.ExpressionFactory;
import javax.el.MethodExpression;
import javax.el.ValueExpression;
import javax.el.VariableMapper;
import javax.faces.FacesException;
import javax.faces.FactoryFinder;
import javax.faces.application.Resource;
import javax.faces.application.ResourceHandler;
import javax.faces.application.StateManager;
import javax.faces.application.ViewHandler;
import javax.faces.component.ActionSource2;
import javax.faces.component.EditableValueHolder;
import javax.faces.component.UIComponent;
import javax.faces.component.UIPanel;
import javax.faces.component.UIViewRoot;
import javax.faces.context.ExternalContext;
import javax.faces.context.FacesContext;
import javax.faces.context.ResponseWriter;
import javax.faces.event.ActionEvent;
import javax.faces.event.MethodExpressionActionListener;
import javax.faces.event.MethodExpressionValueChangeListener;
import javax.faces.event.PostAddToViewEvent;
import javax.faces.event.ValueChangeEvent;
import javax.faces.render.RenderKit;
import javax.faces.validator.MethodExpressionValidator;
import javax.faces.view.ActionSource2AttachedObjectHandler;
import javax.faces.view.ActionSource2AttachedObjectTarget;
import javax.faces.view.AttachedObjectHandler;
import javax.faces.view.AttachedObjectTarget;
import javax.faces.view.BehaviorHolderAttachedObjectHandler;
import javax.faces.view.BehaviorHolderAttachedObjectTarget;
import javax.faces.view.EditableValueHolderAttachedObjectHandler;
import javax.faces.view.EditableValueHolderAttachedObjectTarget;
import javax.faces.view.StateManagementStrategy;
import javax.faces.view.ValueHolderAttachedObjectHandler;
import javax.faces.view.ValueHolderAttachedObjectTarget;
import javax.faces.view.ViewDeclarationLanguage;
import javax.faces.view.ViewDeclarationLanguageFactory;
import javax.faces.view.ViewMetadata;
import javax.faces.view.facelets.FaceletContext;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import static com.sun.faces.config.WebConfiguration.WebContextInitParameter.FaceletsBufferSize;
import static com.sun.faces.config.WebConfiguration.WebContextInitParameter.FaceletsViewMappings;
import static com.sun.faces.config.WebConfiguration.WebContextInitParameter.StateSavingMethod;
import com.sun.faces.util.ComponentStruct;
import static javax.faces.application.StateManager.IS_BUILDING_INITIAL_STATE;
import javax.faces.component.ContextCallback;
import javax.faces.component.visit.VisitCallback;
import javax.faces.component.visit.VisitContext;
import javax.faces.component.visit.VisitResult;
import static com.sun.faces.RIConstants.DYNAMIC_COMPONENT;
import com.sun.faces.facelets.impl.XMLFrontMatterSaver;
import com.sun.faces.renderkit.RenderKitUtils;
import java.util.Collections;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
import javax.el.ELContext;
import javax.faces.application.ProjectStage;
import javax.faces.render.ResponseStateManager;
/**
* This {@link ViewHandlingStrategy} handles Facelets/PDL-based views.
*/
public class FaceletViewHandlingStrategy extends ViewHandlingStrategy {
private static final Logger LOGGER = FacesLogger.APPLICATION.getLogger();
private ViewDeclarationLanguageFactory vdlFactory;
private DefaultFaceletFactory faceletFactory;
// Array of viewId extensions that should be handled by Facelets
private String[] extensionsArray;
// Array of viewId prefixes that should be handled by Facelets
private String[] prefixesArray;
public static final String IS_BUILDING_METADATA =
FaceletViewHandlingStrategy.class.getName() + ".IS_BUILDING_METADATA";
public static final String RESOURCE_LIBRARY_CONTRACT_DATA_STRUCTURE_KEY =
FaceletViewHandlingStrategy.class.getName() + ".RESOURCE_LIBRARY_CONTRACT_DATA_STRUCTURE";
private MethodRetargetHandlerManager retargetHandlerManager =
new MethodRetargetHandlerManager();
private boolean groovyAvailable;
private int responseBufferSize;
private boolean responseBufferSizeSet;
private boolean isTrinidadStateManager;
private Cache metadataCache;
private Map> contractMappings;
/**
* Stores the skip hint.
*/
private static final String SKIP_ITERATION_HINT = "javax.faces.visit.SKIP_ITERATION";
// ------------------------------------------------------------ Constructors
public FaceletViewHandlingStrategy() {
initialize();
}
// ------------------------------------------------------------ Constructors
public static boolean isBuildingMetadata(FacesContext context) {
return context.getAttributes().containsKey(FaceletViewHandlingStrategy.IS_BUILDING_METADATA);
}
// ------------------------------------ Methods from ViewDeclarationLanguage
@Override
public StateManagementStrategy getStateManagementStrategy(FacesContext context, String viewId) {
StateManagementStrategy result;
StateContext stateCtx = StateContext.getStateContext(context);
if (stateCtx.isPartialStateSaving(context, viewId)) {
result = new FaceletPartialStateManagementStrategy(context);
} else {
// Spec for this method says:
// Implementations that provide the VDL for Facelets for JSF 2.0
// and later must return non-null from this method.
// Limit the specification violating change to the case where
// we are running in Trinidad.
//
result = isTrinidadStateManager ? null : new JspStateManagementStrategy(context);
}
return result;
}
/*
* Called by Application._createComponent(Resource).
*
* This method creates two temporary UIComponent instances to aid in
* the creation of the compcomp metadata. These instances no longer
* needed after the method returns and can be safely garbage
* collected.
*
* PENDING(): memory analysis should be done to verify there are no
* memory leaks as a result of this implementation.
* The instances are
* 1. tmp: a javax.faces.NamingContainer to serve as the temporary
* top level component
* 2. facetComponent: a javax.faces.Panel to serve as the parent
* UIComponent that is passed to Facelets so that the
* section can be parsed and understood.
* Per the compcomp spec, tmp has the compcomp Resource stored in
* its attr set under the key Resource.COMPONENT_RESOURCE_KEY. tmp
* has the facetComponent added as its
* UIComponent.COMPOSITE_FACET_NAME facet.
*/
@Override
public BeanInfo getComponentMetadata(FacesContext context,
Resource ccResource) {
DefaultFaceletFactory factory = (DefaultFaceletFactory)
RequestStateManager.get(context, RequestStateManager.FACELET_FACTORY);
DefaultFaceletFactory ourFactory = (DefaultFaceletFactory) factory;
if (ourFactory.needsToBeRefreshed(ccResource.getURL())) {
metadataCache.remove(ccResource);
}
return metadataCache.get(ccResource);
}
public BeanInfo createComponentMetadata(FacesContext context,
Resource ccResource) {
// PENDING this implementation is terribly wasteful.
// Must find a better way.
CompositeComponentBeanInfo result;
FaceletContext ctx = (FaceletContext)
context.getAttributes().get(FaceletContext.FACELET_CONTEXT_KEY);
DefaultFaceletFactory factory = (DefaultFaceletFactory)
RequestStateManager.get(context, RequestStateManager.FACELET_FACTORY);
VariableMapper orig = ctx.getVariableMapper();
// create tmp and facetComponent
UIComponent tmp = context.getApplication().createComponent("javax.faces.NamingContainer");
UIPanel facetComponent = (UIPanel)
context.getApplication().createComponent("javax.faces.Panel");
// PENDING I think this can be skipped because we don't render
// this component instance.
facetComponent.setRendererType("javax.faces.Group");
// PENDING This could possibly be skipped too. However, I think
// this is important because other tag handlers, within
// expect it will be there.
tmp.getFacets().put(UIComponent.COMPOSITE_FACET_NAME, facetComponent);
// We have to put the resource in here just so the classes that eventually
// get called by facelets have access to it.
tmp.getAttributes().put(Resource.COMPONENT_RESOURCE_KEY,
ccResource);
Facelet f;
try {
f = factory.getFacelet(context, ccResource.getURL());
VariableMapper wrapper = new VariableMapperWrapper(orig) {
@Override
public ValueExpression resolveVariable(String variable) {
return super.resolveVariable(variable);
}
};
ctx.setVariableMapper(wrapper);
context.getAttributes().put(IS_BUILDING_METADATA, Boolean.TRUE);
// Because mojarra currently requires a
// element within the compcomp markup, we can rely on the
// fact that its tag handler, InterfaceHandler.apply(), is
// called. In this method, we first imbue facetComponent
// with any config information present on the
// element.
// Then we do the normal facelet thing:
// this.nextHandler.apply(). This causes any child tag
// handlers of the to be called. The
// compcomp spec says each such tag handler is responsible
// for adding to the compcomp metadata, referenced from the
// facetComponent parent.
f.apply(context, facetComponent);
// When f.apply() returns (and therefore
// InterfaceHandler.apply() returns), the compcomp metadata
// pointed to by facetComponent is fully populated.
} catch (Exception e) {
if (e instanceof FacesException) {
throw (FacesException) e;
} else {
throw new FacesException(e);
}
}
finally {
context.getAttributes().remove(IS_BUILDING_METADATA);
ctx.setVariableMapper(orig);
}
// we extract the compcomp metadata and return it, making sure
// to discard tmp and facetComponent. The compcomp metadata
// should be cacheable and shareable across threads, but this is
// not yet implemented.
result = (CompositeComponentBeanInfo)
tmp.getAttributes().get(UIComponent.BEANINFO_KEY);
return result;
}
@Override
public ViewMetadata getViewMetadata(FacesContext context, String viewId) {
Util.notNull("context", context);
Util.notNull("viewId", viewId);
return new ViewMetadataImpl(viewId);
}
/**
* @see javax.faces.view.ViewDeclarationLanguage#getScriptComponentResource(javax.faces.context.FacesContext, javax.faces.application.Resource)
*/
@Override
public Resource getScriptComponentResource(FacesContext context,
Resource componentResource) {
Util.notNull("context", context);
Util.notNull("componentResource", componentResource);
if (!groovyAvailable) {
return null;
}
Resource result = null;
String resourceName = componentResource.getResourceName();
if (resourceName.endsWith(".xhtml")) {
resourceName = resourceName.substring(0,
resourceName.length() - 6) + ".groovy";
ResourceHandler resourceHandler = context.getApplication().getResourceHandler();
result = resourceHandler.createResource(resourceName,
componentResource.getLibraryName());
}
return result;
}
/**
* @see javax.faces.view.ViewDeclarationLanguage#renderView(javax.faces.context.FacesContext, javax.faces.component.UIViewRoot)
*/
@Override
public void renderView(FacesContext ctx,
UIViewRoot viewToRender)
throws IOException {
// suppress rendering if "rendered" property on the component is
// false
if (!viewToRender.isRendered()) {
return;
}
// log request
if (LOGGER.isLoggable(Level.FINE)) {
LOGGER.fine("Rendering View: " + viewToRender.getViewId());
}
WriteBehindStateWriter stateWriter = null;
try {
// Only build the view if this view has not yet been built.
if (!Util.isViewPopulated(ctx, viewToRender)) {
ViewDeclarationLanguage vdl = vdlFactory.getViewDeclarationLanguage(viewToRender.getViewId());
vdl.buildView(ctx, viewToRender);
}
// setup writer and assign it to the ctx
ResponseWriter origWriter = ctx.getResponseWriter();
if (origWriter == null) {
origWriter = createResponseWriter(ctx);
}
ExternalContext extContext = ctx.getExternalContext();
/*
* Make sure we have a session here if we are using server state
* saving. The WriteBehindStateWriter needs an active session when
* it writes out state to a server session.
*
* Note if you flag a view as transient then we won't acquire the
* session as you are stating it does not need one.
*/
if (isServerStateSaving() && !viewToRender.isTransient()) {
getSession(ctx);
}
Writer outputWriter = extContext.getResponseOutputWriter();
stateWriter = new WriteBehindStateWriter(outputWriter,
ctx,
responseBufferSize);
ResponseWriter writer = origWriter.cloneWithWriter(stateWriter);
ctx.setResponseWriter(writer);
// Don't call startDoc and endDoc on a partial response
if (ctx.getPartialViewContext().isPartialRequest()) {
viewToRender.encodeAll(ctx);
try {
ctx.getExternalContext().getFlash().doPostPhaseActions(ctx);
} catch (UnsupportedOperationException uoe) {
if (LOGGER.isLoggable(Level.FINE)) {
LOGGER.fine("ExternalContext.getFlash() throw UnsupportedOperationException -> Flash unavailable");
}
}
} else {
if (ctx.isProjectStage(ProjectStage.Development)) {
FormOmittedChecker.check(ctx);
}
// render the view to the response
String xmlDecl = Util.getXMLDECLFromFacesContextAttributes(ctx);
if (null != xmlDecl) {
// Do not escape.
writer.writePreamble(xmlDecl);
}
String docType = Util.getDOCTYPEFromFacesContextAttributes(ctx);
if (null != docType) {
// Do not escape.
writer.writeDoctype(docType);
}
writer.startDocument();
viewToRender.encodeAll(ctx);
try {
ctx.getExternalContext().getFlash().doPostPhaseActions(ctx);
} catch (UnsupportedOperationException uoe) {
if (LOGGER.isLoggable(Level.FINE)) {
LOGGER.fine("ExternalContext.getFlash() throw UnsupportedOperationException -> Flash unavailable");
}
}
writer.endDocument();
}
// finish writing
writer.close();
boolean writtenState = stateWriter.stateWritten();
// flush to origWriter
if (writtenState) {
stateWriter.flushToWriter();
}
} catch (FileNotFoundException fnfe) {
this.handleFaceletNotFound(ctx,
viewToRender.getViewId(),
fnfe.getMessage());
} catch (Exception e) {
this.handleRenderException(ctx, e);
} finally {
if (stateWriter != null)
stateWriter.release();
}
}
/**
* Are we saving state server side?
*
* @return true if we are, false otherwise.
*/
private boolean isServerStateSaving() {
boolean result = false;
String stateMode = webConfig.getOptionValue(StateSavingMethod);
if (StateManager.STATE_SAVING_METHOD_SERVER.equals(stateMode)) {
result = true;
}
return result;
}
/**
* Get a session (if we are using server state saving).
*
* @param context the Faces context.
* @return the session, or null if we are not using server state saving.
*/
private HttpSession getSession(FacesContext context) {
HttpSession result = null;
Object sessionObj = context.getExternalContext().getSession(true);
if (sessionObj instanceof HttpSession) {
result = (HttpSession) sessionObj;
}
return result;
}
/**
*
* If {@link UIDebug#debugRequest(javax.faces.context.FacesContext)}} is true
,
* simply return a new UIViewRoot(), otherwise, call the default logic.
*
* @see ViewDeclarationLanguage#restoreView(javax.faces.context.FacesContext, java.lang.String)
*/
@Override
public UIViewRoot restoreView(FacesContext context,
String viewId) {
Util.notNull("context", context);
Util.notNull("viewId", viewId);
if (UIDebug.debugRequest(context)) {
context.getApplication().createComponent(UIViewRoot.COMPONENT_TYPE);
}
UIViewRoot viewRoot;
/*
* Check if we are stateless.
*/
ViewHandler outerViewHandler = context.getApplication().getViewHandler();
String renderKitId = outerViewHandler.calculateRenderKitId(context);
ResponseStateManager rsm = RenderKitUtils.getResponseStateManager(context, renderKitId);
if (rsm.isStateless(context, viewId)) {
try {
context.setProcessingEvents(true);
ViewDeclarationLanguage vdl = vdlFactory.getViewDeclarationLanguage(viewId);
viewRoot = vdl.createView(context, viewId);
context.setViewRoot(viewRoot);
vdl.buildView(context, viewRoot);
if (!viewRoot.isTransient()) {
throw new FacesException("Unable to restore view " + viewId);
}
return viewRoot;
} catch (IOException ioe) {
throw new FacesException(ioe);
}
}
if (StateContext.getStateContext(context).isPartialStateSaving(context, viewId)) {
try {
context.setProcessingEvents(false);
ViewDeclarationLanguage vdl = vdlFactory.getViewDeclarationLanguage(viewId);
viewRoot = vdl.getViewMetadata(context, viewId).createMetadataView(context);
context.setViewRoot(viewRoot);
outerViewHandler = context.getApplication().getViewHandler();
renderKitId = outerViewHandler.calculateRenderKitId(context);
rsm = RenderKitUtils.getResponseStateManager(context, renderKitId);
Object[] rawState = (Object[]) rsm.getState(context, viewId);
if (rawState != null) {
Map state = (Map) rawState[1];
if (state != null) {
String cid = viewRoot.getClientId(context);
Object stateObj = state.get(cid);
if (stateObj != null) {
context.getAttributes().put("com.sun.faces.application.view.restoreViewScopeOnly", true);
viewRoot.restoreState(context, stateObj);
context.getAttributes().remove("com.sun.faces.application.view.restoreViewScopeOnly");
}
}
}
context.setProcessingEvents(true);
vdl.buildView(context, viewRoot);
} catch (IOException ioe) {
throw new FacesException(ioe);
}
}
UIViewRoot root = super.restoreView(context, viewId);
ViewHandler viewHandler = context.getApplication().getViewHandler();
ViewDeclarationLanguage vdl = viewHandler.getViewDeclarationLanguage(context, viewId);
context.setResourceLibraryContracts(vdl.calculateResourceLibraryContracts(context, viewId));
StateContext stateCtx = StateContext.getStateContext(context);
stateCtx.startTrackViewModifications(context, root);
return root;
}
/**
* @see ViewHandlingStrategy#retargetAttachedObjects(javax.faces.context.FacesContext, javax.faces.component.UIComponent, java.util.List)
*/
@SuppressWarnings({"unchecked"})
@Override
public void retargetAttachedObjects(FacesContext context,
UIComponent topLevelComponent,
List handlers) {
Util.notNull("context", context);
Util.notNull("topLevelComponent", topLevelComponent);
Util.notNull("handlers", handlers);
//List handlers =
// getAttachedObjectHandlers(topLevelComponent, false);
if (handlers == null || handlers.isEmpty()) {
return;
}
BeanInfo componentBeanInfo = (BeanInfo)
topLevelComponent.getAttributes().get(UIComponent.BEANINFO_KEY);
// PENDING(edburns): log error message if componentBeanInfo is null;
if (null == componentBeanInfo) {
return;
}
BeanDescriptor componentDescriptor = componentBeanInfo.getBeanDescriptor();
// There is an entry in targetList for each attached object in the
// section of the composite component.
List targetList = (List)
componentDescriptor.getValue(AttachedObjectTarget.ATTACHED_OBJECT_TARGETS_KEY);
// Each entry in targetList will vend one or more UIComponent instances
// that is to serve as the target of an attached object in the consuming
// page.
List targetComponents;
String forAttributeValue, curTargetName;
// For each of the attached object handlers...
for (AttachedObjectHandler curHandler : handlers) {
// Get the name given to this attached object by the page author
// in the consuming page.
forAttributeValue = curHandler.getFor();
// For each of the attached objects in the section
// of this composite component...
for (AttachedObjectTarget curTarget : targetList) {
// Get the name given to this attached object target by the
// composite component author
curTargetName = curTarget.getName();
targetComponents = curTarget.getTargets(topLevelComponent);
if (curHandler instanceof ActionSource2AttachedObjectHandler &&
curTarget instanceof ActionSource2AttachedObjectTarget) {
if (forAttributeValue.equals(curTargetName)) {
for (UIComponent curTargetComponent : targetComponents) {
retargetHandler(context, curHandler, curTargetComponent);
}
break;
}
}
else if (curHandler instanceof EditableValueHolderAttachedObjectHandler &&
curTarget instanceof EditableValueHolderAttachedObjectTarget) {
if (forAttributeValue.equals(curTargetName)) {
for (UIComponent curTargetComponent : targetComponents) {
retargetHandler(context, curHandler, curTargetComponent);
}
break;
}
}
else if (curHandler instanceof ValueHolderAttachedObjectHandler &&
curTarget instanceof ValueHolderAttachedObjectTarget) {
if (forAttributeValue.equals(curTargetName)) {
for (UIComponent curTargetComponent : targetComponents) {
retargetHandler(context, curHandler, curTargetComponent);
}
break;
}
} else if(curHandler instanceof BehaviorHolderAttachedObjectHandler &&
curTarget instanceof BehaviorHolderAttachedObjectTarget) {
BehaviorHolderAttachedObjectHandler behaviorHandler = (BehaviorHolderAttachedObjectHandler) curHandler;
BehaviorHolderAttachedObjectTarget behaviorTarget = (BehaviorHolderAttachedObjectTarget) curTarget;
String eventName = behaviorHandler.getEventName();
if((null !=eventName && eventName.equals(curTargetName))||(null ==eventName && behaviorTarget.isDefaultEvent())){
for (UIComponent curTargetComponent : targetComponents) {
retargetHandler(context, curHandler, curTargetComponent);
}
}
}
}
}
}
/**
* @see ViewHandlingStrategy#retargetMethodExpressions(javax.faces.context.FacesContext, javax.faces.component.UIComponent)
*/
@Override
public void retargetMethodExpressions(FacesContext context,
UIComponent topLevelComponent) {
Util.notNull("context", context);
Util.notNull("topLevelComponent", topLevelComponent);
BeanInfo componentBeanInfo = (BeanInfo)
topLevelComponent.getAttributes().get(UIComponent.BEANINFO_KEY);
// PENDING(edburns): log error message if componentBeanInfo is null;
if (null == componentBeanInfo) {
return;
}
PropertyDescriptor attributes[] = componentBeanInfo.getPropertyDescriptors();
MethodMetadataIterator allMetadata = new MethodMetadataIterator(context, attributes);
for (CompCompInterfaceMethodMetadata metadata : allMetadata) {
String attrName = metadata.getName();
String[] targets = metadata.getTargets(context);
Object attrValue = topLevelComponent.getValueExpression(attrName);
// In all cases but one, the attrValue will be a ValueExpression.
// The only case when it will not be a ValueExpression is
// the case when the attrName is an action, and even then, it'll be a
// ValueExpression in all cases except when it's a literal string.
if (null == attrValue) {
Map attrs = topLevelComponent.getAttributes();
attrValue = (attrs.containsKey(attrName)) ?
attrs.get(attrName) : metadata.getDefault();
if (attrValue == null) {
if (metadata.isRequired(context)) {
Object location = attrs.get(UIComponent.VIEW_LOCATION_KEY);
if (location == null) {
location = "";
}
throw new FacesException(
// RELEASE_PENDING need a better message
location.toString()
+ ": Unable to find attribute with name \""
+ attrName
+ "\" in top level component in consuming page, "
+ " or with default value in composite component. "
+ "Page author or composite component author error.");
} else {
continue;
}
}
}
String targetAttributeName = metadata.getTargetAttributeName(context);
UIComponent targetComp = null;
if (null != targetAttributeName) {
attrName = targetAttributeName;
}
if (targets != null) {
MethodRetargetHandler handler = retargetHandlerManager.getRetargetHandler(attrName);
if (handler != null) {
for (String curTarget : targets) {
targetComp = topLevelComponent.findComponent(curTarget);
if (null == targetComp) {
throw new FacesException(attrValue.toString()
+ " : Unable to re-target MethodExpression as inner component referenced by target id '"
+ curTarget
+ "' cannot be found.");
}
handler.retarget(context,
metadata,
attrValue,
targetComp);
}
} else {
// the developer has specified a target for a MethodExpression
// but the attribute name doesn't match one action, actionListener,
// validator, or valueChangeListener. We can ignore the
// target(s) in this case
if (LOGGER.isLoggable(Level.WARNING)) {
LOGGER.log(Level.WARNING,
"jsf.compcomp.unecessary.targets.attribute",
new Object[] { getCompositeComponentName(topLevelComponent),
attrName });
}
handler = retargetHandlerManager.getDefaultHandler();
handler.retarget(context, metadata, attrValue, topLevelComponent);
}
} else {
MethodRetargetHandler handler = null;
if (null != targetAttributeName) {
targetComp = topLevelComponent.findComponent(metadata.getName());
handler = retargetHandlerManager.getRetargetHandler(attrName);
}
if (null == handler) {
targetComp = topLevelComponent;
handler = retargetHandlerManager.getDefaultHandler();
}
handler.retarget(context, metadata, attrValue, targetComp);
}
// clear out the ValueExpression that we've retargeted as a
// MethodExpression
topLevelComponent.setValueExpression(attrName, null);
}
}
/**
* @see ViewDeclarationLanguage#createView(javax.faces.context.FacesContext, java.lang.String)
*/
@Override
public UIViewRoot createView(FacesContext ctx,
String viewId) {
Util.notNull("context", ctx);
Util.notNull("viewId", viewId);
if (UIDebug.debugRequest(ctx)) {
UIViewRoot root = (UIViewRoot)
ctx.getApplication().createComponent(UIViewRoot.COMPONENT_TYPE);
root.setViewId(viewId);
return root;
}
UIViewRoot result = super.createView(ctx, viewId);
ViewHandler viewHandler = ctx.getApplication().getViewHandler();
ViewDeclarationLanguage vdl = viewHandler.getViewDeclarationLanguage(ctx, viewId);
ctx.setResourceLibraryContracts(vdl.calculateResourceLibraryContracts(ctx, viewId));
return result;
}
@Override
public UIComponent createComponent(FacesContext context, String taglibURI, String tagName, Map attributes) {
Util.notNull("context", context);
Util.notNull("taglibURI", taglibURI);
Util.notNull("tagName", tagName);
UIComponent result = null;
DefaultFaceletFactory ff = associate.getFaceletFactory();
result = ff._createComponent(context, taglibURI, tagName, attributes);
return result;
}
@Override
public List calculateResourceLibraryContracts(FacesContext context, String viewId) {
List result = null;
String longestPattern = null;
if (null == contractMappings) {
return Collections.emptyList();
}
String longestMatch = null;
for (Map.Entry> mappings : contractMappings.entrySet()) {
String urlPattern = mappings.getKey();
if (urlPattern.endsWith("*")) {
String prefix = urlPattern.substring(0, urlPattern.length() - 1);
if (viewId.startsWith(prefix)) {
if (longestPattern == null) {
longestPattern = urlPattern;
longestMatch = prefix;
} else if (longestMatch.length() < prefix.length()) {
longestPattern = urlPattern;
longestMatch = prefix;
}
}
} else if (viewId.equals(urlPattern)) {
longestPattern = urlPattern;
break;
}
}
if (longestPattern != null) {
result = contractMappings.get(longestPattern);
}
if (result == null) {
result = contractMappings.get("*");
}
return result;
}
// --------------------------------------- Methods from ViewHandlingStrategy
/**
* @param viewId the view ID to check
* @return true
if assuming a default configuration and the
* view ID's extension is .xhtml
Otherwise try to match
* the view ID based on the configured extendsion and prefixes.
*
* @see com.sun.faces.config.WebConfiguration.WebContextInitParameter#FaceletsViewMappings
*/
@Override
public boolean handlesViewId(String viewId) {
if (viewId != null) {
if (viewId.endsWith(RIConstants.FLOW_DEFINITION_ID_SUFFIX)) {
return true;
}
// If there's no extensions array or prefixes array, then
// assume defaults. .xhtml extension is handled by
// the FaceletViewHandler and .jsp will be handled by
// the JSP view handler
if ((extensionsArray == null) && (prefixesArray == null)) {
boolean matched = isMatchedWithFaceletsSuffix(viewId)? true:(viewId.endsWith(ViewHandler.DEFAULT_FACELETS_SUFFIX));
return matched;
}
if (extensionsArray != null) {
for (String extension : extensionsArray) {
if (viewId.endsWith(extension)) {
return true;
}
}
}
if (prefixesArray != null) {
for (String prefix : prefixesArray) {
if (viewId.startsWith(prefix)) {
return true;
}
}
}
}
return false;
}
private boolean isMatchedWithFaceletsSuffix(String viewId) {
String[] defaultsuffixes = webConfig.getOptionValue(WebConfiguration.WebContextInitParameter.FaceletsSuffix, " ");
for ( String suffix :defaultsuffixes ) {
if (viewId.endsWith(suffix)) {
return true;
}
}
return false;
}
/**
* Mark the initial state if not already marked.
*/
private void markInitialStateIfNotMarked(UIComponent component) {
if (!component.isTransient()) {
if (!component.getAttributes().containsKey(RIConstants.DYNAMIC_COMPONENT) && !component.initialStateMarked()) {
component.markInitialState();
}
for (Iterator it = component.getFacetsAndChildren() ; it.hasNext() ; ) {
UIComponent child = it.next();
markInitialStateIfNotMarked(child);
}
}
}
/**
* Build the view.
* @param ctx the {@link FacesContext} for the current request
* @param view the {@link UIViewRoot} to populate based
* of the Facelet template
* @throws IOException if an error occurs building the view.
*/
@Override
public void buildView(FacesContext ctx, UIViewRoot view)
throws IOException {
StateContext stateCtx = StateContext.getStateContext(ctx);
if (Util.isViewPopulated(ctx, view)) {
Facelet f = faceletFactory.getFacelet(ctx, view.getViewId());
// Disable events from being intercepted by the StateContext by
// virute of re-applying the handlers.
try {
stateCtx.setTrackViewModifications(false);
f.apply(ctx, view);
reapplyDynamicActions(ctx);
if (stateCtx.isPartialStateSaving(ctx, view.getViewId())) {
markInitialStateIfNotMarked(view);
}
} finally {
stateCtx.setTrackViewModifications(true);
}
return;
}
view.setViewId(view.getViewId());
if (LOGGER.isLoggable(Level.FINE)) {
LOGGER.fine("Building View: " + view.getViewId());
}
if (faceletFactory == null) {
ApplicationAssociate associate = ApplicationAssociate.getInstance(ctx.getExternalContext());
faceletFactory = associate.getFaceletFactory();
assert (faceletFactory != null);
}
RequestStateManager.set(ctx,
RequestStateManager.FACELET_FACTORY,
faceletFactory);
Facelet f = faceletFactory.getFacelet(ctx, view.getViewId());
// populate UIViewRoot
try {
ctx.getAttributes().put(IS_BUILDING_INITIAL_STATE, Boolean.TRUE);
stateCtx.setTrackViewModifications(false);
f.apply(ctx, view);
if (f instanceof XMLFrontMatterSaver) {
XMLFrontMatterSaver frontMatterSaver = (XMLFrontMatterSaver) f;
String docType = frontMatterSaver.getSavedDoctype();
if (null != docType) {
Util.saveDOCTYPEToFacesContextAttributes(docType);
}
String XMLDECL = frontMatterSaver.getSavedXMLDecl();
if (null != XMLDECL) {
Util.saveXMLDECLToFacesContextAttributes(XMLDECL);
}
}
if (!stateCtx.isPartialStateSaving(ctx, view.getViewId())) {
reapplyDynamicActions(ctx);
}
doPostBuildActions(ctx, view);
} finally {
ctx.getAttributes().remove(IS_BUILDING_INITIAL_STATE);
}
ctx.getApplication().publishEvent(ctx,
PostAddToViewEvent.class,
UIViewRoot.class,
view);
markInitialState(ctx, view);
Util.setViewPopulated(ctx, view);
}
@Override
public boolean viewExists(FacesContext context,
String viewId) {
boolean result = false;
if (handlesViewId(viewId)) {
if (faceletFactory == null) {
faceletFactory = associate.getFaceletFactory();
assert (faceletFactory != null);
}
result = null != faceletFactory.getResourceResolver().resolveUrl(viewId);
}
return result;
}
@Override
public String getId() {
return FACELETS_VIEW_DECLARATION_LANGUAGE_ID;
}
// ------------------------------------------------------- Protected Methods
/**
* Initialize the core Facelets runtime.
*/
protected void initialize() {
if (LOGGER.isLoggable(Level.FINE)) {
LOGGER.fine("Initializing FaceletViewHandlingStrategy");
}
this.initializeMappings();
groovyAvailable = GroovyHelper.isGroovyAvailable(FacesContext.getCurrentInstance());
metadataCache = new Cache<>(new Factory() {
@Override
public BeanInfo newInstance(Resource ccResource) throws InterruptedException {
FacesContext context = FacesContext.getCurrentInstance();
return FaceletViewHandlingStrategy.this.createComponentMetadata(context, ccResource);
}
});
try {
responseBufferSizeSet = webConfig.isSet(FaceletsBufferSize);
responseBufferSize =
Integer.parseInt(webConfig.getOptionValue(FaceletsBufferSize));
} catch (NumberFormatException nfe) {
responseBufferSize = Integer.parseInt(FaceletsBufferSize.getDefaultValue());
}
if (LOGGER.isLoggable(Level.FINE)) {
LOGGER.fine("Initialization Successful");
}
vdlFactory = (ViewDeclarationLanguageFactory) FactoryFinder.getFactory(FactoryFinder.VIEW_DECLARATION_LANGUAGE_FACTORY);
FacesContext context = FacesContext.getCurrentInstance();
ExternalContext extContext = context.getExternalContext();
Map appMap = extContext.getApplicationMap();
Map> contractDataStructure =
(Map>)
appMap.remove(RESOURCE_LIBRARY_CONTRACT_DATA_STRUCTURE_KEY);
if (null != contractDataStructure && !contractDataStructure.isEmpty()) {
contractMappings = new ConcurrentHashMap<>();
for (Map.Entry> cur : contractDataStructure.entrySet()) {
contractMappings.put(cur.getKey(), new CopyOnWriteArrayList<>(cur.getValue()));
cur.getValue().clear();
}
contractDataStructure.clear();
}
if (null != context) {
StateManager stateManager = Util.getStateManager(context);
if (null != stateManager) {
isTrinidadStateManager = stateManager.getClass().getName().contains("trinidad");
}
}
}
/**
* Initialize mappings, during the first request.
*/
protected void initializeMappings() {
String viewMappings = webConfig.getOptionValue(FaceletsViewMappings);
if ((viewMappings != null) && (viewMappings.length() > 0)) {
Map appMap = FacesContext.getCurrentInstance().getExternalContext().getApplicationMap();
String[] mappingsArray = Util.split(appMap, viewMappings, ";");
List extensionsList = new ArrayList<>(mappingsArray.length);
List prefixesList = new ArrayList<>(mappingsArray.length);
for (String aMappingsArray : mappingsArray) {
String mapping = aMappingsArray.trim();
int mappingLength = mapping.length();
if (mappingLength <= 1) {
continue;
}
if (mapping.charAt(0) == '*') {
extensionsList.add(mapping.substring(1));
} else if (mapping.charAt(mappingLength - 1) == '*') {
prefixesList.add(mapping.substring(0, mappingLength - 1));
}
}
extensionsArray = new String[extensionsList.size()];
extensionsList.toArray(extensionsArray);
prefixesArray = new String[prefixesList.size()];
prefixesList.toArray(prefixesArray);
}
}
/**
* @param context the {@link FacesContext} for the current request
* @return a {@link ResponseWriter} for processing the request
* @throws IOException if the writer cannot be created
*/
protected ResponseWriter createResponseWriter(FacesContext context)
throws IOException {
ExternalContext extContext = context.getExternalContext();
RenderKit renderKit = context.getRenderKit();
// Avoid a cryptic NullPointerException when the renderkit ID
// is incorrectly set
if (renderKit == null) {
String id = context.getViewRoot().getRenderKitId();
throw new IllegalStateException(
"No render kit was available for id \"" + id + "\"");
}
if (responseBufferSizeSet) {
// set the buffer for content
extContext.setResponseBufferSize(responseBufferSize);
}
// get our content type
String contentType =
(String) context.getAttributes().get("facelets.ContentType");
// get the encoding
String encoding =
(String) context.getAttributes().get(RIConstants.FACELETS_ENCODING_KEY);
// Create a dummy ResponseWriter with a bogus writer,
// so we can figure out what content type the ReponseWriter
// is really going to ask for
ResponseWriter writer = renderKit.createResponseWriter(NullWriter.INSTANCE,
contentType,
encoding);
contentType = getResponseContentType(context, writer.getContentType());
encoding = getResponseEncoding(context, writer.getCharacterEncoding());
// apply them to the response
char[] buffer = new char[1028];
HtmlUtils.writeTextForXML(writer, contentType, buffer);
String str = String.valueOf(buffer).trim();
extContext.setResponseContentType(str);
extContext.setResponseCharacterEncoding(encoding);
// Now, clone with the real writer
writer = writer.cloneWithWriter(extContext.getResponseOutputWriter());
return writer;
}
/**
* Handles the case where rendering throws an Exception.
*
* @param context the {@link FacesContext} for the current request
* @param e the caught Exception
* @throws IOException if the custom debug content cannot be written
*/
protected void handleRenderException(FacesContext context, Exception e)
throws IOException {
// always log
if (LOGGER.isLoggable(Level.SEVERE)) {
UIViewRoot root = context.getViewRoot();
StringBuffer sb = new StringBuffer(64);
sb.append("Error Rendering View");
if (root != null) {
sb.append('[');
sb.append(root.getViewId());
sb.append(']');
}
LOGGER.log(Level.SEVERE, sb.toString(), e);
}
if (e instanceof RuntimeException) {
throw (RuntimeException) e;
} else if (e instanceof IOException) {
throw (IOException) e;
} else {
throw new FacesException(e.getMessage(), e);
}
}
/**
* Handles the case where a Facelet cannot be found.
*
* @param context the {@link FacesContext} for the current request
* @param viewId the view ID that was to be mapped to a Facelet
* @param message optional message to include in the 404
* @throws IOException if an error occurs sending the 404 to the client
*/
protected void handleFaceletNotFound(FacesContext context,
String viewId,
String message)
throws IOException {
context.getExternalContext().responseSendError(HttpServletResponse.SC_NOT_FOUND, ((message != null)
? (viewId + ": " + message)
: viewId));
context.responseComplete();
}
/**
* @param context the {@link FacesContext} for the current request
* @param orig the original encoding
* @return the encoding to be used for this response
*/
protected String getResponseEncoding(FacesContext context, String orig) {
String encoding = orig;
// 1. get it from request
encoding = context.getExternalContext().getRequestCharacterEncoding();
// 2. get it from the session
if (encoding == null) {
if (null != context.getExternalContext().getSession(false)) {
Map sessionMap = context.getExternalContext().getSessionMap();
encoding = (String) sessionMap.get(ViewHandler.CHARACTER_ENCODING_KEY);
if (LOGGER.isLoggable(Level.FINEST)) {
LOGGER.log(Level.FINEST,
"Session specified alternate encoding {0}",
encoding);
}
}
}
// see if we need to override the encoding
Map
© 2015 - 2025 Weber Informatics LLC | Privacy Policy