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.trinidad.context;
20  
21  import java.util.Map;
22  import java.util.MissingResourceException;
23  
24  import javax.faces.context.FacesContext;
25  
26  import org.apache.myfaces.trinidad.logging.TrinidadLogger;
27  
28  import org.apache.myfaces.trinidad.skin.Skin;
29  import org.apache.myfaces.trinidad.skin.Icon;
30  import org.apache.myfaces.trinidad.style.Styles;
31  import org.apache.myfaces.trinidad.util.ThreadLocalUtils;
32  
33  /**
34   * The RenderingContext holds context information about the current rendering.
35   * The RenderingContext is useful for Renderers. The 
36   * RenderingContext is passed in to the CoreRenderer. For example, 
37   * a renderer may need to render differently if it is rendering to a browser
38   * in right-to-left mode, or if accessibility mode is on, etc.
39   * Some values are promoted up from RequestContext for ease of use while rendering.
40   * @see org.apache.myfaces.trinidad.render.CoreRenderer#encodeAll
41   * @see RequestContext
42   */
43  abstract public class RenderingContext
44  {
45    /**
46     * Retrieves the RenderingContext active for the current thread.
47     */
48    static public RenderingContext getCurrentInstance()
49    {
50      return _CURRENT_CONTEXT.get();
51    }
52  
53    public RenderingContext()
54    {
55      attach();
56    }
57  
58    /**
59     * Get a map of properties specific to rendering. You can then call the
60     * Map's put to save things on the RenderingContext for later retrieval.
61     */
62    abstract public Map<Object, Object> getProperties();
63    /**
64     * Get the Agent attached to the RenderingContext.
65     * @return the Agent attached to the RenderingContext
66     */
67    abstract public Agent getAgent();
68    
69    /**
70     * Get the LocaleContext attached to the RenderingContext
71     * @return the LocaleContext attached to the RenderingContext
72     */  
73    abstract public LocaleContext getLocaleContext();
74  
75    /**
76     * Get the FormData that is on the RenderingContext. You can then add more
77     * form data once you have the FormData object. This is a way to render 
78     * hidden fields form data.
79     * @return returns the FormData that is on the RenderingContext. This could 
80     * return null if there is no FormData
81     */
82    abstract public FormData getFormData();
83    
84    /**
85     * Set FormData on the RenderingContext. This is a way to render hidden fields
86     * form data.  This is a cleaner way to handle form data than using the
87     * getProperties.put mechanism.
88     * @param data
89     */
90    abstract public void setFormData(FormData data);
91    
92    /**
93     * Clear the FormData that is on the RenderingContext
94     */
95    abstract public void clearFormData();
96  
97    //
98    // Skin methods.
99    //
100 
101   /**
102    * Get the Skin that is attached to this RenderingContext.  
103    * Icons, properties, etc. should never be retrieved directly
104    * from the skin, but always through the RenderingContext so they
105    * can be properly transformed.
106    * @return the Skin object attached to this RenderingContext
107    */
108   abstract public Skin getSkin();
109 
110   /**
111    * Get the translated String given a translation key.
112    * The default implementation
113    * gets the string from the Skin for the current LocaleContext
114    * that is used during this rendering.
115    * @param key
116    * @return the translated String attached to this RenderingContext
117    */
118   public String getTranslatedString(String key)
119   {
120     if (key == null)
121       return null;
122 
123     try
124     {
125       return getSkin().getTranslatedString(getLocaleContext(), key);
126     }
127     catch (MissingResourceException mre)
128     {
129       // Instead of halting execution, return "???<key>???",
130       // just like JSF and JSTL will do, and log a severe error
131       _LOG.severe("CANNOT_GET_RESOURCE_KEY", new String[]{key, getSkin().getId()});
132       return "???" + key + "???";
133     }
134   }
135   
136   /**
137    * Get the Icon attached to this RenderingContext, give the iconName.
138    * This could be the Icon that is on the Skin objec that is on the 
139    * current RenderingContext.
140    * @param iconName
141    * @return the Icon attached to this RenderingContext
142    */
143   abstract public Icon getIcon(String iconName);
144 
145   /**
146    * Get a styleClass given a styleClass. With other information that is on
147    * the RenderingContext, the styleClass may be transformed.
148    * For example, you might want to return a compressed styleclass 
149    * given the full styleClass.
150    * e.g., getStyleClass("SomLongName") could return "x1"
151    * You should always run your styleClass through this method before rendering
152    * it out.
153    * @param styleClass the styleClass name that you want to render 
154    * @return the StyleClass that may be the given styleClass transformed to
155    * be suitable for this rendering context.
156    */
157   abstract public String getStyleClass(String styleClass);
158   
159   /**
160    *  Get the Styles object that is attached to this RenderingContext. 
161    *  Styles is a useful object if you need to know the css properties for a given
162    *  selector. (For backward compatibility this is not an abstract method.)
163    * @return Styles or null if there are no Styles.
164    * 
165    */
166   public Styles getStyles() 
167   {
168     return null;
169   }
170   
171   /**
172    * Set the skin resource key map on the RenderingContext. 
173    * Store a Map that maps a skin's resource keys from one key to another 
174    * on the RenderingContext. This way we can share Rendering code, but use
175    * unique skinning keys for the Renderer. For example, we can use tree's 
176    * rendering code for treeTable, but we want to be sure to use tree skinning
177    * keys (aka selectors) for tree and treeTable skinning keys for the treeTable
178    * component. You can create a map of tree's selectors to treeTable's selectors,
179    * and then save off the current map (getSkinResourceKeyMap), 
180    * set the new map, render using the tree's renderer code, then set back
181    * the original map.
182    * @param mapping
183    * @see #getSkinResourceKeyMap()
184    */
185   abstract public void   setSkinResourceKeyMap(Map<String, String> mapping);
186   
187   /**
188    * Get the skin resource key map that is attached to the RenderingContext.
189    * This will usually be a Map of Skinning selectors. The key is the selector
190    * that the renderer code is rendering, and the value is the selector that
191    * that will be the actual selector to render. This facilitates sharing 
192    * renderer code between components but render unique selectors for each
193    * component. The convention is to have each component have their own unique
194    * skinning selectors. Tree has af|tree selectors, treeTable has af|treeTable
195    * selectors, for example.
196    * @return a Map of selector to selector to faciliate renderer-code sharing.
197    * @see #setSkinResourceKeyMap
198    */
199   abstract public Map<String, String> getSkinResourceKeyMap();
200   
201   /**
202    * Returns a boolean to indicate whether or not the RenderingContext is 
203    * in right-to-left reading direction mode. This can be true if the browser 
204    * requesting  rendering is set to a right-to-left language.
205    * @return true if right-to-left is true
206    */
207   abstract public boolean isRightToLeft();
208   /**
209    * Returns the output mode for this RenderingContext. Example output-modes 
210    * are printable and portlet.
211    * @return the outputMode for this RenderingContext.
212    */
213   abstract public String getOutputMode();
214   
215   /**
216    * Get the accessibility mode (e.g., DEFAULT, INACCESSIBLE, etc)
217    * that is attached to this RenderingContext
218    * @return RequestContext.Accessibility enum attached to this RenderingContext
219    */
220   abstract public RequestContext.Accessibility getAccessibilityMode();
221   
222   /**
223    * Get the AccessibilityProfile (a set of accessibility-related properties 
224    * that are applied to the current request, e.g., color contrast, font size, etc) 
225    * that is attached to this RenderingContext.
226    * @return AccessibilityProfile attached to this RenderingContext
227    */
228   abstract public AccessibilityProfile getAccessibilityProfile();
229   
230   /**
231    * Returns true or false for whether animation is enabled.
232    * @return true if animation is enabled for this RenderingContext
233    */
234   abstract public boolean isAnimationEnabled();
235 
236   /**
237    * Returns true if the current request is a design-time request.
238    * @return true if the current request is a design-time request.
239    */
240   public boolean isDesignTime()
241   {
242     return false;
243   }
244 
245   /**
246    * Access to FacesContext.
247    */
248   public FacesContext getFacesContext()
249   {
250     return FacesContext.getCurrentInstance();
251   }
252   
253   /**
254    * Access to RequestContext
255    */
256   public RequestContext getRequestContext()
257   {
258     return RequestContext.getCurrentInstance();
259   }
260 
261 
262   // TODO This is a hack API to enable caching of the client ID.
263   // All fine, but we should have a more general mechanism.
264   /**
265    * Get the current client id for this RenderingContext
266    * @return
267    */
268   public String getCurrentClientId() { return _currentClientId; }
269   /**
270    * Set the current client id for this RenderingContext
271    * @param currentClientId
272    */
273   public void setCurrentClientId(String currentClientId)
274   {
275     _currentClientId = currentClientId;
276   }
277 
278   private String _currentClientId;
279 
280 
281   /**
282    * Get the ParialPageContext that is attached to this RenderingContext
283    * @return
284    */
285   abstract public PartialPageContext getPartialPageContext();
286 
287 
288   public void release()
289   {
290     Object o = _CURRENT_CONTEXT.get();
291     // Clean up first...
292     _CURRENT_CONTEXT.remove();
293 
294     // Then see if there's a problem, and scream if there is one
295     if (o == null)
296       throw new IllegalStateException(_LOG.getMessage(
297         "RENDERINGCONTEXT_ALREADY_RELEASED_OR_NEVER_ATTACHED"));
298     if (o != this)
299       throw new IllegalStateException(_LOG.getMessage(
300         "TRY_RELEASING_DIFFERENT_RENDERINGCONTEXT"));
301   }
302 
303   /**
304    * Attaches an RenderingContext to the current thread.  This method is
305    * protected, and therefore can only be called by an RenderingContext
306    * object itself.
307    */
308   protected void attach()
309   {
310     Object o = _CURRENT_CONTEXT.get();
311     // We want to catch two different problems:
312     // (1) A failure to call release()
313     // (2) An attempt to attach an instance when the thread already has one
314     // For #1, anything more than a warning is dangerous, because throwing
315     // an exception would permanently make the thread unusable.
316     // For #2, I'd like to throw an exception, but I can't distinguish
317     // this scenario from #1.
318     if (o != null)
319     {
320       _LOG.warning("TRYING_ATTACH_RENDERERINGCONTEXT");
321     }
322 
323     _CURRENT_CONTEXT.set(this);
324   }
325 
326 
327   static private final ThreadLocal<RenderingContext> _CURRENT_CONTEXT = 
328                                                            ThreadLocalUtils.newRequestThreadLocal();  
329   
330   static private final TrinidadLogger _LOG =
331     TrinidadLogger.createTrinidadLogger(RenderingContext.class);
332 }