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  import org.apache.myfaces.trinidad.skin.Icon;
28  import org.apache.myfaces.trinidad.skin.Skin;
29  import org.apache.myfaces.trinidad.style.Styles;
30  import org.apache.myfaces.trinidad.util.ThreadLocalUtils;
31  
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     Skin skin = getSkin();
124 
125     try
126     {
127       return skin.getTranslatedString(getLocaleContext(), key);
128     }
129     catch (MissingResourceException mre)
130     {
131       // Instead of halting execution, return "???<key>???",
132       // just like JSF and JSTL will do, and log a severe error
133       _LOG.severe("CANNOT_GET_RESOURCE_KEY", new Object[]{key, skin});
134       return "???" + key + "???";
135     }
136   }
137   
138   /**
139    * Get the Icon attached to this RenderingContext, give the iconName.
140    * This could be the Icon that is on the Skin objec that is on the 
141    * current RenderingContext.
142    * @param iconName, should not contain the '.' prefix or ':alias' suffix
143    *                  even though the selector name contained it
144    * @return the Icon attached to this RenderingContext
145    */
146   abstract public Icon getIcon(String iconName);
147 
148   /**
149    * Get a styleClass given a styleClass. With other information that is on
150    * the RenderingContext, the styleClass may be transformed.
151    * For example, you might want to return a compressed styleclass 
152    * given the full styleClass.
153    * e.g., getStyleClass("SomLongName") could return "x1"
154    * You should always run your styleClass through this method before rendering
155    * it out.
156    * @param styleClass the styleClass name that you want to render 
157    * @return the StyleClass that may be the given styleClass transformed to
158    * be suitable for this rendering context.
159    */
160   abstract public String getStyleClass(String styleClass);
161   
162   /**
163    *  Get the Styles object that is attached to this RenderingContext. 
164    *  Styles is a useful object if you need to know the css properties for a given
165    *  selector. (For backward compatibility this is not an abstract method.)
166    * @return Styles or null if there are no Styles.
167    * 
168    */
169   public Styles getStyles() 
170   {
171     return null;
172   }
173   
174   /**
175    * Set the skin resource key map on the RenderingContext. 
176    * Store a Map that maps a skin's resource keys from one key to another 
177    * on the RenderingContext. This way we can share Rendering code, but use
178    * unique skinning keys for the Renderer. For example, we can use tree's 
179    * rendering code for treeTable, but we want to be sure to use tree skinning
180    * keys (aka selectors) for tree and treeTable skinning keys for the treeTable
181    * component. You can create a map of tree's selectors to treeTable's selectors,
182    * and then save off the current map (getSkinResourceKeyMap), 
183    * set the new map, render using the tree's renderer code, then set back
184    * the original map.
185    * @param mapping
186    * @see #getSkinResourceKeyMap()
187    */
188   abstract public void   setSkinResourceKeyMap(Map<String, String> mapping);
189   
190   /**
191    * Get the skin resource key map that is attached to the RenderingContext.
192    * This will usually be a Map of Skinning selectors. The key is the selector
193    * that the renderer code is rendering, and the value is the selector that
194    * that will be the actual selector to render. This facilitates sharing 
195    * renderer code between components but render unique selectors for each
196    * component. The convention is to have each component have their own unique
197    * skinning selectors. Tree has af|tree selectors, treeTable has af|treeTable
198    * selectors, for example.
199    * @return a Map of selector to selector to faciliate renderer-code sharing.
200    * @see #setSkinResourceKeyMap
201    */
202   abstract public Map<String, String> getSkinResourceKeyMap();
203   
204   /**
205    * Returns a boolean to indicate whether or not the RenderingContext is 
206    * in right-to-left reading direction mode. This can be true if the browser 
207    * requesting  rendering is set to a right-to-left language.
208    * @return true if right-to-left is true
209    */
210   abstract public boolean isRightToLeft();
211   /**
212    * Returns the output mode for this RenderingContext. Example output-modes 
213    * are printable and portlet.
214    * @return the outputMode for this RenderingContext.
215    */
216   abstract public String getOutputMode();
217   
218   /**
219    * Get the accessibility mode (e.g., DEFAULT, INACCESSIBLE, etc)
220    * that is attached to this RenderingContext
221    * @return RequestContext.Accessibility enum attached to this RenderingContext
222    */
223   abstract public RequestContext.Accessibility getAccessibilityMode();
224   
225   /**
226    * Get the AccessibilityProfile (a set of accessibility-related properties 
227    * that are applied to the current request, e.g., color contrast, font size, etc) 
228    * that is attached to this RenderingContext.
229    * @return AccessibilityProfile attached to this RenderingContext
230    */
231   abstract public AccessibilityProfile getAccessibilityProfile();
232   
233   /**
234    * Returns true or false for whether animation is enabled.
235    * @return true if animation is enabled for this RenderingContext
236    */
237   abstract public boolean isAnimationEnabled();
238 
239   /**
240    * Returns true if the current request is a design-time request.
241    * @return true if the current request is a design-time request.
242    */
243   public boolean isDesignTime()
244   {
245     return false;
246   }
247 
248   /**
249    * Access to FacesContext.
250    */
251   public FacesContext getFacesContext()
252   {
253     return FacesContext.getCurrentInstance();
254   }
255   
256   /**
257    * Access to RequestContext
258    */
259   public RequestContext getRequestContext()
260   {
261     return RequestContext.getCurrentInstance();
262   }
263 
264 
265   // TODO This is a hack API to enable caching of the client ID.
266   // All fine, but we should have a more general mechanism.
267   /**
268    * Get the current client id for this RenderingContext
269    * @return
270    */
271   public String getCurrentClientId() { return _currentClientId; }
272   /**
273    * Set the current client id for this RenderingContext
274    * @param currentClientId
275    */
276   public void setCurrentClientId(String currentClientId)
277   {
278     _currentClientId = currentClientId;
279   }
280 
281   private String _currentClientId;
282 
283 
284   /**
285    * Get the ParialPageContext that is attached to this RenderingContext
286    * @return
287    */
288   abstract public PartialPageContext getPartialPageContext();
289 
290 
291   public void release()
292   {
293     Object o = _CURRENT_CONTEXT.get();
294     // Clean up first...
295     _CURRENT_CONTEXT.remove();
296 
297     // Then see if there's a problem, and scream if there is one
298     if (o == null)
299       throw new IllegalStateException(_LOG.getMessage(
300         "RENDERINGCONTEXT_ALREADY_RELEASED_OR_NEVER_ATTACHED"));
301     if (o != this)
302       throw new IllegalStateException(_LOG.getMessage(
303         "TRY_RELEASING_DIFFERENT_RENDERINGCONTEXT"));
304   }
305 
306   /**
307    * Attaches an RenderingContext to the current thread.  This method is
308    * protected, and therefore can only be called by an RenderingContext
309    * object itself.
310    */
311   protected void attach()
312   {
313     Object o = _CURRENT_CONTEXT.get();
314     // We want to catch two different problems:
315     // (1) A failure to call release()
316     // (2) An attempt to attach an instance when the thread already has one
317     // For #1, anything more than a warning is dangerous, because throwing
318     // an exception would permanently make the thread unusable.
319     // For #2, I'd like to throw an exception, but I can't distinguish
320     // this scenario from #1.
321     if (o != null)
322     {
323       _LOG.warning("TRYING_ATTACH_RENDERERINGCONTEXT");
324     }
325 
326     _CURRENT_CONTEXT.set(this);
327   }
328 
329 
330   static private final ThreadLocal<RenderingContext> _CURRENT_CONTEXT = 
331                                                            ThreadLocalUtils.newRequestThreadLocal();  
332   
333   static private final TrinidadLogger _LOG =
334     TrinidadLogger.createTrinidadLogger(RenderingContext.class);
335 }