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.servlet;
20  
21  import java.util.ArrayList;
22  import java.util.Collections;
23  import java.util.HashMap;
24  import java.util.List;
25  import java.util.Map;
26  
27  import javax.el.ELContext;
28  import javax.el.ELContextEvent;
29  import javax.el.ELContextListener;
30  import javax.faces.FactoryFinder;
31  import javax.faces.application.Application;
32  import javax.faces.application.ApplicationFactory;
33  import javax.faces.component.UINamingContainer;
34  import javax.faces.component.UIViewRoot;
35  import javax.faces.context.ExceptionHandler;
36  import javax.faces.context.ExternalContext;
37  import javax.faces.context.FacesContext;
38  import javax.faces.render.RenderKit;
39  import javax.faces.render.RenderKitFactory;
40  
41  import org.apache.myfaces.context.ReleaseableExternalContext;
42  import org.apache.myfaces.el.unified.FacesELContext;
43  import org.apache.myfaces.view.facelets.FaceletViewDeclarationLanguage;
44  
45  /**
46   * Provides a base implementation of the FacesContext for the use
47   * in FacesContextImpl and StartupFacesContextImpl.
48   * 
49   * @author Jakob Korherr (latest modification by $Author$)
50   * @version $Revision$ $Date$
51   */
52  public abstract class FacesContextImplBase extends FacesContext
53  {
54      private Application _application;
55      private ExternalContext _externalContext;
56      private ReleaseableExternalContext _defaultExternalContext;
57      private UIViewRoot _viewRoot;
58      private RenderKitFactory _renderKitFactory;
59      private ELContext _elContext;
60      private Map<Object, Object> _attributes = null;
61      private boolean _processingEvents = true;
62      private ExceptionHandler _exceptionHandler = null;
63      
64      // Variables used to cache values
65      private RenderKit _cachedRenderKit = null;
66      private String _cachedRenderKitId = null;
67      
68      protected boolean _released = false;
69      
70      private ApplicationFactory _applicationFactory = null;
71      
72      private List<String> _resourceLibraryContracts;
73      private Character _separatorChar;
74      private FacesContext _currentFacesContext;
75  
76      /**
77       * Base constructor.
78       * Calls FacesContext.setCurrentInstance(this);
79       */
80      public FacesContextImplBase(final ExternalContext externalContext,
81              final ReleaseableExternalContext defaultExternalContext)
82      {
83          _externalContext = externalContext;
84          _defaultExternalContext = defaultExternalContext;
85          
86          // this FacesContext impl is now the current instance
87          // note that because this method is protected, it has to be called from here
88          FacesContext.setCurrentInstance(this);
89      }
90      
91      public FacesContextImplBase(final ExternalContext externalContext,
92              final ReleaseableExternalContext defaultExternalContext,
93              final ApplicationFactory applicationFactory,
94              final RenderKitFactory renderKitFactory)
95      {
96          _externalContext = externalContext;
97          _defaultExternalContext = defaultExternalContext;
98          
99          _applicationFactory = applicationFactory;
100         _renderKitFactory = renderKitFactory;
101         
102         // this FacesContext impl is now the current instance
103         // note that because this method is protected, it has to be called from here
104         FacesContext.setCurrentInstance(this);
105     }
106     
107     /**
108      * Releases the instance fields on FacesContextImplBase.
109      * Must be called by sub-classes, when overriding it!
110      */
111     @Override
112     public void release()
113     {
114         _applicationFactory = null;
115         _currentFacesContext = null;
116         if (_defaultExternalContext != null)
117         {
118             _defaultExternalContext.release();
119             _defaultExternalContext = null;
120         }
121         
122         _application = null;
123         _externalContext = null;
124         _viewRoot = null;
125         _renderKitFactory = null;
126         _elContext = null;
127         _exceptionHandler = null;
128         _cachedRenderKit = null;
129         _cachedRenderKitId = null;
130         _separatorChar = null;
131         
132         // Spec JSF 2 section getAttributes when release is called the attributes map
133         // must!!! be cleared! (probably to trigger some clearance methods on possible
134         // added entries before nullifying everything)
135         if (_attributes != null)
136         {
137             _attributes.clear();
138             _attributes = null;
139         }
140         
141         _released = true;
142         FacesContext.setCurrentInstance(null);
143     }
144     
145     @Override
146     public boolean isReleased()
147     {
148         return _released;
149     }
150 
151     @Override
152     public final ExternalContext getExternalContext()
153     {
154         assertNotReleased();
155 
156         return _externalContext;
157     }
158     
159     @Override
160     public final Application getApplication()
161     {
162         assertNotReleased();
163         
164         if (_application == null)
165         {
166             if (_applicationFactory == null)
167             {
168                 _applicationFactory = (ApplicationFactory) FactoryFinder.getFactory(
169                     FactoryFinder.APPLICATION_FACTORY);
170             }
171             _application = _applicationFactory.getApplication();
172         }
173         
174         return _application;
175     }
176     
177     /**
178      * 
179      */
180     public void purgeFacesContext()
181     {
182         _application = null;
183         _renderKitFactory = null;
184         _cachedRenderKit = null;
185         _cachedRenderKitId = null;
186     }
187     
188     @Override
189     public final ExceptionHandler getExceptionHandler()
190     {
191         assertNotReleased();
192         
193         return _exceptionHandler;
194     }
195     
196     @Override
197     public final void setExceptionHandler(ExceptionHandler exceptionHandler)
198     {
199         assertNotReleased();
200         
201         _exceptionHandler = exceptionHandler;
202     }
203     
204     @Override
205     public final boolean isProcessingEvents()
206     {
207         assertNotReleased();
208         
209         return _processingEvents;
210     }
211     
212     @Override
213     public final void setProcessingEvents(boolean processingEvents)
214     {
215         assertNotReleased();
216         
217         _processingEvents = processingEvents;
218     }
219     
220     @Override
221     public final ELContext getELContext()
222     {
223         assertNotReleased();
224 
225         if (_elContext != null)
226         {
227             return _elContext;
228         }
229 
230         _elContext = new FacesELContext(getApplication().getELResolver(), getCurrentFacesContext());
231 
232         ELContextEvent event = new ELContextEvent(_elContext);
233         for (ELContextListener listener : getApplication().getELContextListeners())
234         {
235             listener.contextCreated(event);
236         }
237 
238         return _elContext;
239     }
240 
241     /**
242      * Returns a mutable map of attributes associated with this faces context when
243      * {@link javax.faces.context.FacesContext#release()} is called the map must be cleared!
244      * 
245      * Note this map is not associated with the request map the request map still is accessible via the
246      * {@link javax.faces.context.ExternalContext#getRequestMap()} method!
247      * 
248      * Also the scope is different to the request map, this map has the scope of the context, and is cleared once the
249      * release method on the context is called!
250      * 
251      * Also the map does not cause any events according to the spec!
252      * 
253      * @since JSF 2.0
254      * 
255      * @throws IllegalStateException
256      *             if the current context already is released!
257      */
258     @Override
259     public final Map<Object, Object> getAttributes()
260     {
261         assertNotReleased();
262 
263         if (_attributes == null)
264         {
265             _attributes = new HashMap<Object, Object>();
266         }
267         return _attributes;
268     }
269     
270     @Override
271     public UIViewRoot getViewRoot()
272     {
273         assertNotReleased();
274 
275         return _viewRoot;
276     }
277     
278     @Override
279     public final void setViewRoot(final UIViewRoot viewRoot)
280     {
281         assertNotReleased();
282 
283         if (viewRoot == null)
284         {
285             throw new NullPointerException("viewRoot");
286         }
287         // If the current UIViewRoot is non-null, and calling equals() on the argument root,
288         // passing the current UIViewRoot returns false
289         // the clear method must be called on the Map returned from UIViewRoot.getViewMap().
290         if (_viewRoot != null && !_viewRoot.equals(viewRoot))
291         {
292             // if we're currently building view metadata, skip clearing the view map
293             if (!Boolean.TRUE.equals(getAttributes().get(FaceletViewDeclarationLanguage.BUILDING_VIEW_METADATA)))
294             {
295                 //call getViewMap(false) to prevent unnecessary map creation
296                 Map<String, Object> viewMap = _viewRoot.getViewMap(false);
297                 if (viewMap != null)
298                 {
299                     viewMap.clear();
300                 }
301             }
302         }
303         _viewRoot = viewRoot;
304     }
305     
306     @Override
307     public final RenderKit getRenderKit()
308     {
309         assertNotReleased();
310 
311         if (getViewRoot() == null)
312         {
313             return null;
314         }
315 
316         String renderKitId = getViewRoot().getRenderKitId();
317 
318         if (renderKitId == null)
319         {
320             return null;
321         }
322         
323         if (_cachedRenderKitId == null || !renderKitId.equals(_cachedRenderKitId))
324         {
325             _cachedRenderKitId = renderKitId;
326             if (_renderKitFactory == null)
327             {
328                 _renderKitFactory = (RenderKitFactory) FactoryFinder.getFactory(FactoryFinder.RENDER_KIT_FACTORY);
329             }
330             _cachedRenderKit = _renderKitFactory.getRenderKit(getCurrentFacesContext(), renderKitId);
331         }
332         
333         return _cachedRenderKit;
334     }
335 
336     @Override
337     public List<String> getResourceLibraryContracts()
338     {
339         assertNotReleased();
340         
341         if (_resourceLibraryContracts == null)
342         {
343             return Collections.emptyList();
344         }
345         else
346         {
347             return _resourceLibraryContracts;
348         }
349     }
350     
351     @Override
352     public void setResourceLibraryContracts(List<String> contracts)
353     {
354         assertNotReleased();
355      
356         if (contracts == null)
357         {
358             _resourceLibraryContracts = null;
359         }
360         else if (contracts.isEmpty())
361         {
362             _resourceLibraryContracts = null;
363         }
364         else
365         {
366             _resourceLibraryContracts = new ArrayList<String>(contracts);
367         }
368     }
369 
370     @Override
371     public char getNamingContainerSeparatorChar()
372     {
373         if (_separatorChar == null)
374         {
375             _separatorChar = UINamingContainer.getSeparatorChar(this);
376         }
377         return _separatorChar;
378     }
379     
380     /**
381      * has to be thrown in many of the methods if the method is called after the instance has been released!
382      */
383     protected final void assertNotReleased()
384     {
385         if (_released)
386         {
387             throw new IllegalStateException("Error the FacesContext is already released!");
388         }
389     }
390     
391     protected FacesContext getCurrentFacesContext()
392     {
393         if (_currentFacesContext == null)
394         {
395             _currentFacesContext = FacesContext.getCurrentInstance();
396         }
397         return _currentFacesContext;
398     }
399 }