View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.myfaces.context;
20  
21  import java.util.Collections;
22  import java.util.EnumSet;
23  import java.util.HashMap;
24  import java.util.Map;
25  import java.util.Set;
26  import java.util.Set;
27  
28  import javax.faces.application.ResourceDependency;
29  import javax.faces.component.UIComponent;
30  import javax.faces.component.UIViewRoot;
31  import javax.faces.component.visit.VisitCallback;
32  import javax.faces.component.visit.VisitContext;
33  import javax.faces.component.visit.VisitHint;
34  import javax.faces.component.visit.VisitResult;
35  import javax.faces.context.FacesContext;
36  
37  /**
38   *
39   * @author  Leonardo Uribe (latest modification by $Author: lu4242 $)
40   * @version $Revision: 1505865 $ $Date: 2013-07-22 19:19:31 -0500 (Mon, 22 Jul 2013) $
41   * @since 2.0.2
42   */
43  public class RequestViewContext
44  {
45  
46      public static final String VIEW_CONTEXT_KEY = "oam.VIEW_CONTEXT";
47      
48      public static final String RESOURCE_DEPENDENCY_INSPECTED_CLASS = "oam.RDClass";
49      
50      private static final String SKIP_ITERATION_HINT = "javax.faces.visit.SKIP_ITERATION";
51      
52      //private static final Set<VisitHint> VISIT_HINTS = Collections.unmodifiableSet( 
53      //        EnumSet.of(VisitHint.SKIP_ITERATION));
54      
55      private Map<ResourceDependency, Boolean> addedResources;
56      
57      // No lazy init: every view has one (UIView.class) or more classes to process   
58      private Map<Class<?>, Boolean> processedClasses = new HashMap<Class<?>,Boolean>();
59      
60      private Map<String, Boolean> renderTargetMap = null;
61  
62      static public RequestViewContext getCurrentInstance()
63      {
64          FacesContext ctx = FacesContext.getCurrentInstance();
65          return getCurrentInstance(ctx);
66      }
67      
68      static public RequestViewContext getCurrentInstance(FacesContext ctx)
69      {
70          return getCurrentInstance(ctx, ctx.getViewRoot());
71      }
72      
73      @SuppressWarnings("unchecked")
74      static public RequestViewContext getCurrentInstance(FacesContext ctx, UIViewRoot root)
75      {
76          Map<UIViewRoot, RequestViewContext> map = (Map<UIViewRoot, RequestViewContext>) ctx.getAttributes().get(VIEW_CONTEXT_KEY);
77          RequestViewContext rvc = null;        
78          if (map == null)
79          {
80              map = new HashMap<UIViewRoot, RequestViewContext>();
81              rvc = new RequestViewContext();
82              map.put(root, rvc);
83              ctx.getAttributes().put(VIEW_CONTEXT_KEY, map);
84              return rvc;
85          }
86          else
87          {
88              rvc = map.get(root); 
89              if (rvc == null)
90              {
91                  rvc = new RequestViewContext();
92                  map.put(root, rvc);
93              }
94              return rvc;
95          }
96      }
97  
98      public boolean isResourceDependencyAlreadyProcessed(ResourceDependency dependency)
99      {
100         if (addedResources == null)
101         {
102             return false;
103         }
104         return addedResources.containsKey(dependency); 
105     }
106     
107     public void setResourceDependencyAsProcessed(ResourceDependency dependency)
108     {
109         if (addedResources == null)
110         {
111             addedResources = new HashMap<ResourceDependency,Boolean>();
112         }
113         addedResources.put(dependency, true);
114     }
115 
116     public boolean isClassAlreadyProcessed(Class<?> inspectedClass)
117     {
118         return processedClasses.containsKey(inspectedClass);
119     }
120 
121     public void setClassProcessed(Class<?> inspectedClass)
122     {
123         processedClasses.put(inspectedClass, Boolean.TRUE);
124     }
125     
126     public boolean isRenderTarget(String target)
127     {
128         if (renderTargetMap != null)
129         {
130             return Boolean.TRUE.equals(renderTargetMap.get(target));
131         }
132         return false;
133     }
134     
135     public void setRenderTarget(String target, boolean value)
136     {
137         if (renderTargetMap == null)
138         {
139             renderTargetMap = new HashMap<String, Boolean>(8);
140         }
141         renderTargetMap.put(target, value);
142     }
143     
144     /**
145      * Scans UIViewRoot facets with added component resources by the effect of
146      * @ResourceDependency annotation, and register the associated inspected classes
147      * so new component resources will not be added to the component tree again and again.
148      * 
149      * @param facesContext
150      * @param root 
151      */
152     public void refreshRequestViewContext(FacesContext facesContext, UIViewRoot root)
153     {
154         for (Map.Entry<String, UIComponent> entry : root.getFacets().entrySet())
155         {
156             UIComponent facet = entry.getValue();
157             if (facet.getId() != null && facet.getId().startsWith("javax_faces_location_"))
158             {
159                 try
160                 {
161                     facesContext.getAttributes().put(SKIP_ITERATION_HINT, Boolean.TRUE);
162 
163                     VisitContext visitContext = VisitContext.createVisitContext(facesContext, null, null);
164                     facet.visitTree(visitContext, new RefreshViewContext());
165                 }
166                 finally
167                 {
168                     // We must remove hint in finally, because an exception can break this phase,
169                     // but lifecycle can continue, if custom exception handler swallows the exception
170                     facesContext.getAttributes().remove(SKIP_ITERATION_HINT);
171                 }
172             }
173         }
174     }
175     
176     private class RefreshViewContext implements VisitCallback
177     {
178 
179         public VisitResult visit(VisitContext context, UIComponent target)
180         {
181             Class<?> inspectedClass = (Class<?>)target.getAttributes().get(RESOURCE_DEPENDENCY_INSPECTED_CLASS);
182             if (inspectedClass != null)
183             {
184                 setClassProcessed(inspectedClass);
185             }            
186             return VisitResult.ACCEPT;
187         }
188     }
189 }