blob: ed4c20117841375d369c8c841d9e73f2129c0ca1 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.myfaces.context;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.faces.application.ResourceDependency;
import javax.faces.component.UIComponent;
import javax.faces.component.UIViewRoot;
import javax.faces.component.visit.VisitCallback;
import javax.faces.component.visit.VisitContext;
import javax.faces.component.visit.VisitResult;
import javax.faces.context.FacesContext;
import org.apache.myfaces.component.visit.MyFacesVisitHints;
import org.apache.myfaces.view.facelets.impl.FaceletCompositionContextImpl;
/**
*
* @author Leonardo Uribe (latest modification by $Author$)
* @version $Revision$ $Date$
* @since 2.0.2
*/
public class RequestViewContext
{
public static final String VIEW_CONTEXT_KEY = "oam.VIEW_CONTEXT";
public static final String RESOURCE_DEPENDENCY_INSPECTED_CLASS = "oam.RDClass";
private RequestViewMetadata requestViewMetadata;
private Map<String, Boolean> renderTargetMap = null;
private Map<String, List<UIComponent>> renderTargetMapComponents = null;
public RequestViewContext()
{
this.requestViewMetadata = new RequestViewMetadata();
}
public RequestViewContext(RequestViewMetadata rvm)
{
this.requestViewMetadata = new RequestViewMetadata();
}
public static RequestViewContext getCurrentInstance()
{
return getCurrentInstance(FacesContext.getCurrentInstance());
}
public static RequestViewContext getCurrentInstance(FacesContext ctx)
{
return getCurrentInstance(ctx, ctx.getViewRoot());
}
@SuppressWarnings("unchecked")
public static RequestViewContext getCurrentInstance(FacesContext ctx, UIViewRoot root)
{
return getCurrentInstance(ctx, root, true);
}
public static RequestViewContext getCurrentInstance(FacesContext ctx, UIViewRoot root, boolean create)
{
Map<UIViewRoot, RequestViewContext> map =
(Map<UIViewRoot, RequestViewContext>) ctx.getAttributes().get(VIEW_CONTEXT_KEY);
if (create && map == null)
{
map = new HashMap<>();
ctx.getAttributes().put(VIEW_CONTEXT_KEY, map);
}
if (map != null)
{
RequestViewContext rvc = map.get(root);
if (create && rvc == null)
{
rvc = new RequestViewContext();
map.put(root, rvc);
}
return rvc;
}
return null;
}
public static RequestViewContext newInstance(RequestViewMetadata rvm)
{
RequestViewContext clone = new RequestViewContext(rvm.cloneInstance());
return clone;
}
public static void setCurrentInstance(FacesContext ctx, UIViewRoot root, RequestViewContext rvc)
{
Map<UIViewRoot, RequestViewContext> map = (Map<UIViewRoot, RequestViewContext>) ctx.getAttributes()
.computeIfAbsent(VIEW_CONTEXT_KEY, k -> new HashMap<>());
map.put(root, rvc);
}
public boolean isResourceDependencyAlreadyProcessed(ResourceDependency dependency)
{
return requestViewMetadata.isResourceDependencyAlreadyProcessed(dependency);
}
public void setResourceDependencyAsProcessed(ResourceDependency dependency)
{
requestViewMetadata.setResourceDependencyAsProcessed(dependency);
}
public boolean isClassAlreadyProcessed(Class<?> inspectedClass)
{
return requestViewMetadata.isClassAlreadyProcessed(inspectedClass);
}
public void setClassProcessed(Class<?> inspectedClass)
{
requestViewMetadata.setClassProcessed(inspectedClass);
}
public boolean isRenderTarget(String target)
{
if (renderTargetMap != null)
{
return Boolean.TRUE.equals(renderTargetMap.get(target));
}
return false;
}
public void setRenderTarget(String target, boolean value, UIComponent component)
{
if (renderTargetMap == null)
{
renderTargetMap = new HashMap<>(8);
}
renderTargetMap.put(target, value);
if (renderTargetMapComponents == null)
{
renderTargetMapComponents = new HashMap<>(8);
}
List<UIComponent> componentList = renderTargetMapComponents.computeIfAbsent(target, k -> new ArrayList<>(8));
if (!componentList.contains(component))
{
componentList.add(component);
}
}
public List<UIComponent> getRenderTargetComponentList(String target)
{
if (renderTargetMapComponents == null)
{
return Collections.emptyList();
}
List<UIComponent> list = renderTargetMapComponents.get(target);
return list != null ? list : Collections.emptyList();
}
/**
* Scans UIViewRoot facets with added component resources by the effect of
* ResourceDependency annotation, and register the associated inspected classes
* so new component resources will not be added to the component tree again and again.
*
* @param facesContext
* @param root
*/
public void refreshRequestViewContext(FacesContext facesContext, UIViewRoot root)
{
RefreshViewContextCallback callback = null;
for (Map.Entry<String, UIComponent> entry : root.getFacets().entrySet())
{
UIComponent facet = entry.getValue();
if (facet.getId() != null
&& facet.getId().startsWith(FaceletCompositionContextImpl.JAVAX_FACES_LOCATION_PREFIX))
{
try
{
facesContext.getAttributes().put(MyFacesVisitHints.SKIP_ITERATION_HINT, Boolean.TRUE);
if (callback == null)
{
callback = new RefreshViewContextCallback();
}
VisitContext visitContext = VisitContext.createVisitContext(facesContext,
null, MyFacesVisitHints.SET_SKIP_ITERATION);
facet.visitTree(visitContext, callback);
}
finally
{
// We must remove hint in finally, because an exception can break this phase,
// but lifecycle can continue, if custom exception handler swallows the exception
facesContext.getAttributes().remove(MyFacesVisitHints.SKIP_ITERATION_HINT);
}
}
}
}
private class RefreshViewContextCallback implements VisitCallback
{
@Override
public VisitResult visit(VisitContext context, UIComponent target)
{
Class<?> inspectedClass = (Class<?>)target.getAttributes().get(RESOURCE_DEPENDENCY_INSPECTED_CLASS);
if (inspectedClass != null)
{
setClassProcessed(inspectedClass);
}
return VisitResult.ACCEPT;
}
}
public RequestViewMetadata getRequestViewMetadata()
{
return requestViewMetadata;
}
public void setRequestViewMetadata(RequestViewMetadata requestViewMetadata)
{
this.requestViewMetadata = requestViewMetadata;
}
}