001package org.apache.turbine.services.pull.tools;
002
003/*
004 * Licensed to the Apache Software Foundation (ASF) under one
005 * or more contributor license agreements.  See the NOTICE file
006 * distributed with this work for additional information
007 * regarding copyright ownership.  The ASF licenses this file
008 * to you under the Apache License, Version 2.0 (the
009 * "License"); you may not use this file except in compliance
010 * with the License.  You may obtain a copy of the License at
011 *
012 *   http://www.apache.org/licenses/LICENSE-2.0
013 *
014 * Unless required by applicable law or agreed to in writing,
015 * software distributed under the License is distributed on an
016 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
017 * KIND, either express or implied.  See the License for the
018 * specific language governing permissions and limitations
019 * under the License.
020 */
021
022import org.apache.commons.logging.Log;
023import org.apache.commons.logging.LogFactory;
024import org.apache.turbine.om.security.User;
025import org.apache.turbine.pipeline.PipelineData;
026import org.apache.turbine.services.pull.ApplicationTool;
027import org.apache.turbine.services.ui.TurbineUI;
028import org.apache.turbine.services.ui.UIService;
029import org.apache.turbine.util.RunData;
030import org.apache.turbine.util.ServerData;
031
032/**
033 * Manages all UI elements for a Turbine Application. Any UI element can be
034 * accessed in any template using the $ui handle (assuming you use the default
035 * PullService configuration). So, for example, you could access the background
036 * color for your pages by using $ui.bgcolor
037 * <p>
038 * This implementation provides a single level of inheritance in that if a
039 * property does not exist in a non-default skin, the value from the default
040 * skin will be used. By only requiring values different to those stored in
041 * the default skin to appear in the non-default skins the amount of memory
042 * consumed in cases where the UserManager instance is used at a non-global
043 * scope will potentially be reduced due to the fact that a shared instance of
044 * the default skin properties can be used. Note that this inheritance only
045 * applies to property values - it does not apply to any images or stylesheets
046 * that may form part of your skins.
047 * <p>
048 * This is an application pull tool for the template system. You should not
049 * use it in a normal application!  Within Java code you should use TurbineUI.
050 * <p>
051 *
052 * This is an application pull tool for the template system. You should
053 * <strong>only</strong> use it in a normal application to set the skin
054 * attribute for a user (setSkin(User user, String skin)) and to initialize it
055 * for the user, otherwise use TurbineUI is probably the way to go.
056 *
057 * @author <a href="mailto:jvanzyl@periapt.com">Jason van Zyl</a>
058 * @author <a href="mailto:james_coltman@majorband.co.uk">James Coltman</a>
059 * @author <a href="mailto:hps@intermeta.de">Henning P. Schmiedehausen</a>
060 * @author <a href="mailto:seade@backstagetech.com.au">Scott Eade</a>
061 * @version $Id$
062 * @see UIService
063 */
064public class UITool implements ApplicationTool
065{
066    /** Logging */
067    private static Log log = LogFactory.getLog(UITool.class);
068
069    /**
070     * Attribute name of skinName value in User's temp hashmap.
071     */
072    public static final String SKIN_ATTRIBUTE = UITool.class.getName()+ ".skin";
073
074    /**
075     * The actual skin being used for the webapp.
076     */
077    private String skinName;
078
079    /**
080     * Refresh the tool.
081     */
082    @Override
083    public void refresh()
084    {
085        TurbineUI.refresh(getSkin());
086        log.debug("UITool refreshed for skin: " + getSkin());
087    }
088
089    /**
090     * Provide access to the list of available skin names.
091     *
092     * @return the available skin names.
093     */
094    public String[] getSkinNames()
095    {
096        return TurbineUI.getSkinNames();
097    }
098
099    /**
100     * Get the name of the default skin name for the web application from the
101     * TurbineResources.properties file. If the property is not present the
102     * name of the default skin will be returned.  Note that the web application
103     * skin name may be something other than default, in which case its
104     * properties will default to the skin with the name "default".
105     *
106     * @return the name of the default skin for the web application.
107     */
108    public String getWebappSkinName()
109    {
110        return TurbineUI.getWebappSkinName();
111    }
112
113    /**
114     * Retrieve a skin property.  If the property is not defined in the current
115     * skin the value for the default skin will be provided.  If the current
116     * skin does not exist then the skin configured for the webapp will be used.
117     * If the webapp skin does not exist the default skin will be used.  If the
118     * default skin does not exist then <code>null</code> will be returned.
119     *
120     * @param key the key to retrieve from the skin.
121     * @return the value of the property for the named skin (defaulting to the
122     * default skin), the webapp skin, the default skin or <code>null</code>,
123     * depending on whether or not the property or skins exist.
124     */
125    public String get(String key)
126    {
127        return TurbineUI.get(getSkin(), key);
128    }
129
130    /**
131     * Retrieve the skin name.
132     * @return the selected skin name
133     */
134    public String getSkin()
135    {
136        return skinName;
137    }
138
139    /**
140     * Set the skin name to the skin from the TurbineResources.properties file.
141     * If the property is not present use the "default" skin.
142     */
143    public void setSkin()
144    {
145        skinName = TurbineUI.getWebappSkinName();
146    }
147
148    /**
149     * Set the skin name to the specified skin.
150     *
151     * @param skinName the skin name to use.
152     */
153    public void setSkin(String skinName)
154    {
155        this.skinName = skinName;
156    }
157
158    /**
159     * Set the skin name when the tool is configured to be loaded on a
160     * per-request basis. By default it calls getSkin to return the skin
161     * specified in TurbineResources.properties. Developers can write a subclass
162     * of UITool that overrides this method to determine the skin to use based
163     * on information held in the request.
164     *
165     * @param data a RunData instance
166     */
167    protected void setSkin(RunData data)
168    {
169        setSkin();
170    }
171
172    /**
173     * Set the skin name when the tool is configured to be loaded on a
174     * per-session basis. If the user's temp hashmap contains a value in the
175     * attribute specified by the String constant SKIN_ATTRIBUTE then that is
176     * returned. Otherwise it calls getSkin to return the skin specified in
177     * TurbineResources.properties.
178     *
179     * @param user a User instance
180     */
181    protected void setSkin(User user)
182    {
183        if (user.getTemp(SKIN_ATTRIBUTE) == null)
184        {
185            setSkin();
186        }
187        else
188        {
189            setSkin((String) user.getTemp(SKIN_ATTRIBUTE));
190        }
191    }
192
193    /**
194     * Set the skin name in the user's temp hashmap for the current session.
195     *
196     * @param user a User instance
197     * @param skin the skin name for the session
198     */
199    public static void setSkin(User user, String skin)
200    {
201        user.setTemp(SKIN_ATTRIBUTE, skin);
202    }
203
204    /**
205     * Retrieve the URL for an image that is part of the skin. The images are
206     * stored in the WEBAPP/resources/ui/skins/[SKIN]/images directory.
207     *
208     * <p>Use this if for some reason your server name, server scheme, or server
209     * port change on a per request basis. I'm not sure if this would happen in
210     * a load balanced situation. I think in most cases the image(String image)
211     * method would probably be enough, but I'm not absolutely positive.
212     *
213     * @param imageId the id of the image whose URL will be generated.
214     * @param data the RunData to use as the source of the ServerData to use as
215     * the basis for the URL.
216     * @return the image URL
217     */
218    public String image(String imageId, RunData data)
219    {
220        return image(imageId, data.getServerData());
221    }
222
223    /**
224     * Retrieve the URL for an image that is part of the skin. The images are
225     * stored in the WEBAPP/resources/ui/skins/[SKIN]/images directory.
226     *
227     * <p>Use this if for some reason your server name, server scheme, or server
228     * port change on a per request basis. I'm not sure if this would happen in
229     * a load balanced situation. I think in most cases the image(String image)
230     * method would probably be enough, but I'm not absolutely positive.
231     *
232     * @param imageId the id of the image whose URL will be generated.
233     * @param serverData the serverData to use as the basis for the URL.
234     * @return the image URL
235     */
236    public String image(String imageId, ServerData serverData)
237    {
238        return TurbineUI.image(getSkin(), imageId, serverData);
239    }
240
241    /**
242     * Retrieve the URL for an image that is part of the skin. The images are
243     * stored in the WEBAPP/resources/ui/skins/[SKIN]/images directory.
244     *
245     * @param imageId the id of the image whose URL will be generated.
246     * @return the image URL
247     */
248    public String image(String imageId)
249    {
250        return TurbineUI.image(getSkin(), imageId);
251    }
252
253    /**
254     * Retrieve the URL for the style sheet that is part of the skin. The style
255     * is stored in the WEBAPP/resources/ui/skins/[SKIN] directory with the
256     * filename skin.css
257     *
258     * <p>Use this if for some reason your server name, server scheme, or server
259     * port change on a per request basis. I'm not sure if this would happen in
260     * a load balanced situation. I think in most cases the style() method would
261     * probably be enough, but I'm not absolutely positive.
262     *
263     * @param data the RunData to use as the source of the ServerData to use as
264     * the basis for the URL.
265     * @return the CSS URL
266     */
267    public String getStylecss(RunData data)
268    {
269        return getStylecss(data.getServerData());
270    }
271
272    /**
273     * Retrieve the URL for the style sheet that is part of the skin. The style
274     * is stored in the WEBAPP/resources/ui/skins/[SKIN] directory with the
275     * filename skin.css
276     *
277     * <p>Use this if for some reason your server name, server scheme, or server
278     * port change on a per request basis. I'm not sure if this would happen in
279     * a load balanced situation. I think in most cases the style() method would
280     * probably be enough, but I'm not absolutely positive.
281     *
282     * @param serverData the serverData to use as the basis for the URL.
283     * @return the CSS URL
284     */
285    public String getStylecss(ServerData serverData)
286    {
287        return TurbineUI.getStylecss(getSkin(), serverData);
288    }
289
290    /**
291     * Retrieve the URL for the style sheet that is part of the skin. The style
292     * is stored in the WEBAPP/resources/ui/skins/[SKIN] directory with the
293     * filename skin.css
294     * @return the CSS URL
295     */
296    public String getStylecss()
297    {
298        return TurbineUI.getStylecss(getSkin());
299    }
300
301    /**
302     * Retrieve the URL for a given script that is part of the skin. The script
303     * is stored in the WEBAPP/resources/ui/skins/[SKIN] directory.
304     *
305     * <p>Use this if for some reason your server name, server scheme, or server
306     * port change on a per request basis. I'm not sure if this would happen in
307     * a load balanced situation. I think in most cases the image(String image)
308     * method would probably be enough, but I'm not absolutely positive.
309     *
310     * @param filename the name of the script file whose URL will be generated.
311     * @param data the RunDate to use as the source of the ServerData to use as
312     * the basis for the URL.
313     * @return the script URL
314     */
315    public String getScript(String filename, RunData data)
316    {
317        return getScript(filename, data.getServerData());
318    }
319
320    /**
321     * Retrieve the URL for a given script that is part of the skin. The script
322     * is stored in the WEBAPP/resources/ui/skins/[SKIN] directory.
323     *
324     * <p>Use this if for some reason your server name, server scheme, or server
325     * port change on a per request basis. I'm not sure if this would happen in
326     * a load balanced situation. I think in most cases the image(String image)
327     * method would probably be enough, but I'm not absolutely positive.
328     *
329     * @param filename the name of the script file whose URL will be generated.
330     * @param serverData the serverData to use as the basis for the URL.
331     * @return the script URL
332     */
333    public String getScript(String filename, ServerData serverData)
334    {
335        return TurbineUI.getScript(getSkin(), filename, serverData);
336    }
337
338    /**
339     * Retrieve the URL for a given script that is part of the skin. The script
340     * is stored in the WEBAPP/resources/ui/skins/[SKIN] directory.
341     *
342     * @param filename the name of the script file whose URL will be generated.
343     * @return the script URL
344     */
345    public String getScript(String filename)
346    {
347        return TurbineUI.getScript(getSkin(), filename);
348    }
349
350    /**
351     * Initialize the UITool object.
352     *
353     * @param data This is null, RunData or User depending upon specified tool
354     * scope.
355     */
356    @Override
357    public void init(Object data)
358    {
359        if (data == null)
360        {
361            log.debug("UITool scope is global");
362            setSkin();
363        }
364        else if (data instanceof RunData)
365        {
366            log.debug("UITool scope is request");
367            setSkin((RunData) data);
368        }
369        else if (data instanceof PipelineData)
370        {
371            PipelineData pipelineData = (PipelineData) data;
372            RunData runData = (RunData)pipelineData;
373            log.debug("UITool scope is request");
374            setSkin(runData);
375        }
376        else if (data instanceof User)
377        {
378            log.debug("UITool scope is session");
379            setSkin((User) data);
380        }
381    }
382
383}