1 package org.apache.turbine.services.pull.util;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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/<SKIN>/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/<SKIN>/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/<SKIN> 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/<SKIN> 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 }