| /* |
| * 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; |
| } |
| } |