View Javadoc

1   package org.apache.turbine.services.pull.util;
2   
3   /*
4    * Copyright 2001-2004 The Apache Software Foundation.
5    *
6    * Licensed under the Apache License, Version 2.0 (the "License")
7    * you may not use this file except in compliance with the License.
8    * 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, software
13   * distributed under the License is distributed on an "AS IS" BASIS,
14   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15   * See the License for the specific language governing permissions and
16   * limitations under the License.
17   */
18  
19  import java.io.FileInputStream;
20  
21  import java.util.Properties;
22  
23  import org.apache.commons.logging.Log;
24  import org.apache.commons.logging.LogFactory;
25  
26  import org.apache.turbine.Turbine;
27  import org.apache.turbine.om.security.User;
28  import org.apache.turbine.services.pull.ApplicationTool;
29  import org.apache.turbine.services.pull.TurbinePull;
30  import org.apache.turbine.util.RunData;
31  import org.apache.turbine.util.ServerData;
32  import org.apache.turbine.util.uri.DataURI;
33  
34  /***
35   * UIManager.java
36   * <br>
37   * Manages all UI elements for a Turbine Application. Any
38   * UI element can be accessed in any template using the
39   * $ui handle (assuming you use the default PullService
40   * configuration). So, for example, you could access
41   * the background colour for your pages by using
42   * $ui.bgcolor
43   * <p>
44   * <h3>Questions:</h3>
45   * What is the best way to allow an application
46   * to be skinned. And how to allow the flexible
47   * altering of a particular UI element in certain
48   * parts of the template hierarchy. For example
49   * on one section of your site you might like
50   * a certain bgcolor, on another part of your
51   * site you might want another. How can be let
52   * the designer specify these properties and
53   * still use the single $app.ui.bgcolor in
54   * all the templates.
55   * <p>
56   * It would also be very cool to use some form
57   * of inheritence for UI elements. Say a $ui.bgcolor
58   * is used in a template where the bgcolor is not
59   * set for that part of hierarch, it would be cool
60   * if it could find the setting for the bgcolor
61   * in the parent directory. So you could override
62   * a UI element where you wanted and the system
63   * would fall back to the parent when necessary.
64   * <p>
65   * How to specify skins, how to deal with images,
66   * how could this be handled with a web app.
67   * <p>
68   *
69   * This is an application pull tool for the template system. You should <b>not</b>
70   * use it in a normal application!
71   *
72   *
73   * @author <a href="mailto:jvanzyl@periapt.com">Jason van Zyl</a>
74   * @author <a href="mailto:james_coltman@majorband.co.uk">James Coltman</a>
75   * @author <a href="mailto:hps@intermeta.de">Henning P. Schmiedehausen</a>
76   * @version $Id: UIManager.java,v 1.10.2.2 2004/05/20 03:06:47 seade Exp $
77   */
78  public class UIManager implements ApplicationTool
79  {
80      /*** Logging */
81      private static Log log = LogFactory.getLog(UIManager.class);
82  
83      /***
84       * The location of the skins within the application
85       * resources directory.
86       */
87      private static final String SKINS_DIRECTORY = "/ui/skins";
88  
89      /***
90       * The name of the directory where images are
91       * stored for this skin.
92       */
93      private static final String IMAGES_DIRECTORY = "/images";
94  
95      /***
96       * Property tag for the skin that is to be
97       * used for the web application.
98       */
99      private static final String SKIN_PROPERTY = "tool.ui.skin";
100 
101     /***
102      * Default skin name. This name actually represents
103      * a directory in the WEBAPP/resources/ui/skins
104      * directory. There is a file called skin.props
105      * which actually contains the name/value pairs.
106      */
107     private static final String SKIN_PROPERTY_DEFAULT = "default";
108 
109     /***
110      * Attribute name of skinName value in User's temp hashmap.
111      */
112     private static final String SKIN_ATTRIBUTE =
113         UIManager.class.getName()+ ".skin";
114 
115     /***
116      * The actual skin being used for the webapp.
117      */
118     private String skinName;
119 
120     /***
121      * The skins directory.
122      */
123     private String skinsDirectory;
124 
125     /***
126      * The file within the skin directory that actually
127      * contains the name/value pairs for the skin.
128      */
129     private static final String SKIN_PROPS_FILE = "skin.props";
130 
131     /***
132      * The file name for the skin style sheet.
133      */
134     private static final String SKIN_CSS_FILE = "skin.css";
135 
136     /***
137      * This the resources directory relative to the
138      * webapp context. Used for constructing correct
139      * URIs for retrieving images in image().
140      */
141     private String resourcesDirectory;
142 
143     /***
144      * Properties to hold the name/value pairs
145      * for the skin.
146      */
147     private Properties skinProperties;
148 
149     /***
150      * Initialize the UIManager object.
151      *
152      * @param data This is null, RunData or User depending upon specified tool scope.
153      */
154     public void init(Object data)
155     {
156         /***
157          * Store the resources directory for use in image().
158          */
159         resourcesDirectory = TurbinePull.getResourcesDirectory();
160 
161         if (data == null)
162         {
163             log.debug("UI Manager scope is global");
164             setSkin();
165         }
166         else if (data instanceof RunData)
167         {
168             log.debug("UI Manager scope is request");
169             setSkin((RunData) data);
170         }
171         else if (data instanceof User)
172         {
173             log.debug("UI Manager scope is session");
174             setSkin((User) data);
175         }
176 
177         skinsDirectory =
178                 TurbinePull.getAbsolutePathToResourcesDirectory() + SKINS_DIRECTORY;
179 
180         loadSkin();
181     }
182 
183     /***
184      * This lets the tool know that it should be
185      * refreshed. The tool can perform whatever actions
186      * are necessary to refresh itself. This is necessary
187      * for sane development where you probably want the
188      * tools to refresh themselves on every request.
189      */
190     public void refresh()
191     {
192         log.debug("Refreshing UI manager");
193 
194         loadSkin();
195     }
196 
197     /***
198      * Retrieve a property from the properties held
199      * within the properties file for this skin.
200      */
201     public String get(String key)
202     {
203         return skinProperties.getProperty(key);
204     }
205 
206     /***
207      * Retrieve the skin name.
208      */
209     public String getSkin()
210     {
211         return skinName;
212     }
213 
214     /***
215      * Retrieve the URL for an image that is part
216      * of a skin. The images are stored in the
217      * WEBAPP/resources/ui/skins/&lt;SKIN&gt;/images
218      * directory.
219      *
220      * Use this if for some reason your server name,
221      * server scheme, or server port change on a
222      * per request basis. I'm not sure if this
223      * would happend in a load balanced situation.
224      * I think in most cases the image(String image)
225      * method would probably be enough, but I'm not
226      * absolutely positive.
227      */
228     public String image(String imageId, RunData data)
229     {
230         DataURI du = new DataURI(data);
231 
232         StringBuffer sb = new StringBuffer();
233 
234         sb.append(resourcesDirectory).
235                 append(SKINS_DIRECTORY).
236                 append("/").
237                 append(getSkin()).
238                 append(IMAGES_DIRECTORY).
239                 append("/").
240                 append(imageId);
241 
242         du.setScriptName(sb.toString());
243         return du.getAbsoluteLink();
244     }
245 
246     /***
247      * Retrieve the URL for an image that is part
248      * of a skin. The images are stored in the
249      * WEBAPP/resources/ui/skins/&lt;SKIN&gt;/images
250      * directory.
251      */
252     public String image(String imageId)
253     {
254         ServerData sd = Turbine.getDefaultServerData();
255         DataURI du = new DataURI(sd);
256 
257         StringBuffer sb = new StringBuffer();
258 
259         sb.append(resourcesDirectory).
260            append(SKINS_DIRECTORY).
261            append("/").
262            append(getSkin()).
263            append(IMAGES_DIRECTORY).
264            append("/").
265            append(imageId);
266 
267         du.setScriptName(sb.toString());
268         return du.getAbsoluteLink();
269     }
270 
271     /***
272      * Retrieve the URL for the style sheet that is part
273      * of a skin. The style is stored in the
274      * WEBAPP/resources/ui/skins/&lt;SKIN&gt; directory with the
275      * filename skin.css
276      *
277      * Use this if for some reason your server name,
278      * server scheme, or server port change on a
279      * per request basis. I'm not sure if this
280      * would happend in a load balanced situation.
281      * I think in most cases the style()
282      * method would probably be enough, but I'm not
283      * absolutely positive.
284      */
285     public String getStylecss(RunData data)
286     {
287         DataURI du = new DataURI(data);
288         StringBuffer sb = new StringBuffer();
289 
290         sb.append(resourcesDirectory).
291                 append(SKINS_DIRECTORY).
292                 append("/").
293                 append(getSkin()).
294                 append("/").
295                 append(SKIN_CSS_FILE);
296 
297         du.setScriptName(sb.toString());
298         return du.getAbsoluteLink();
299     }
300 
301     /***
302      * Retrieve the URL for the style sheet that is part
303      * of a skin. The style is stored in the
304      * WEBAPP/resources/ui/skins/&lt;SKIN&gt; directory with the
305      * filename skin.css
306      */
307     public String getStylecss()
308     {
309         ServerData sd = Turbine.getDefaultServerData();
310         DataURI du = new DataURI(sd);
311 
312         StringBuffer sb = new StringBuffer();
313 
314         sb.append(resourcesDirectory).
315            append(SKINS_DIRECTORY).
316            append("/").
317            append(getSkin()).
318            append("/").
319            append(SKIN_CSS_FILE);
320 
321         du.setScriptName(sb.toString());
322         return du.getAbsoluteLink();
323     }
324 
325     /***
326      * Load the specified skin. In development mode
327      * this may occur frequently as the skin properties
328      * are being changed.
329      */
330     private void loadSkin()
331     {
332         skinProperties = new Properties();
333 
334         try
335         {
336             FileInputStream is = new FileInputStream(
337                     skinsDirectory + "/" + getSkin() + "/" + SKIN_PROPS_FILE);
338 
339             skinProperties.load(is);
340         }
341         catch (Exception e)
342         {
343             log.error("Cannot load skin: " + skinName);
344         }
345     }
346 
347     /***
348      * Set the skin name to the skin from the TR.props
349      * file. If the property is not present use the
350      * default skin.
351      */
352     public void setSkin()
353     {
354         this.skinName = Turbine.getConfiguration()
355                 .getString(SKIN_PROPERTY,
356                            SKIN_PROPERTY_DEFAULT);
357     }
358 
359     /***
360      * Set the skin name to the specified skin.
361      *
362      * @param skinName the skin name to use.
363      */
364     public void setSkin(String skinName)
365     {
366         this.skinName = skinName;
367     }
368 
369     /***
370      * Set the skin name when the tool is configured to be
371      * loaded on a per-request basis. By default it calls getSkin
372      * to return the skin specified in TR.properties. Developers can
373      * write a subclass of UIManager that overrides this method to
374      * determine the skin to use based on information held in the request.
375      *
376      * @param data a RunData instance
377      */
378     protected void setSkin(RunData data)
379     {
380         setSkin();
381     }
382 
383     /***
384      * Set the skin name when the tool is configured to be
385      * loaded on a per-session basis. It the user's temp hashmap contains
386      * a value in the attribute specified by the String constant SKIN_ATTRIBUTE
387      * then that is returned. Otherwise it calls getSkin to return the skin
388      * specified in TR.properties.
389      *
390      * @param user a User instance
391      */
392     protected void setSkin(User user)
393     {
394         if (user.getTemp(SKIN_ATTRIBUTE) == null)
395         {
396             setSkin();
397         }
398         else
399         {
400             setSkin((String) user.getTemp(SKIN_ATTRIBUTE));
401         }
402     }
403 
404     /***
405      * Set the skin name user's temp hashmap for the current session.
406      *
407      * @param user a User instance
408      * @param skin the skin name for the session
409      */
410     public static void setSkin(User user, String skin)
411     {
412         user.setTemp(SKIN_ATTRIBUTE, skin);
413     }
414 }