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.annotation.TurbineService;
025import org.apache.turbine.om.security.User;
026import org.apache.turbine.pipeline.PipelineData;
027import org.apache.turbine.services.pull.ApplicationTool;
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     * The UI service.
081     */
082    @TurbineService
083    private UIService uiService;
084
085    /**
086     * Refresh the tool.
087     */
088    @Override
089    public void refresh()
090    {
091        uiService.refresh(getSkin());
092        log.debug("UITool refreshed for skin: " + getSkin());
093    }
094
095    /**
096     * Provide access to the list of available skin names.
097     *
098     * @return the available skin names.
099     */
100    public String[] getSkinNames()
101    {
102        return uiService.getSkinNames();
103    }
104
105    /**
106     * Get the name of the default skin name for the web application from the
107     * TurbineResources.properties file. If the property is not present the
108     * name of the default skin will be returned.  Note that the web application
109     * skin name may be something other than default, in which case its
110     * properties will default to the skin with the name "default".
111     *
112     * @return the name of the default skin for the web application.
113     */
114    public String getWebappSkinName()
115    {
116        return uiService.getWebappSkinName();
117    }
118
119    /**
120     * Retrieve a skin property.  If the property is not defined in the current
121     * skin the value for the default skin will be provided.  If the current
122     * skin does not exist then the skin configured for the webapp will be used.
123     * If the webapp skin does not exist the default skin will be used.  If the
124     * default skin does not exist then <code>null</code> will be returned.
125     *
126     * @param key the key to retrieve from the skin.
127     * @return the value of the property for the named skin (defaulting to the
128     * default skin), the webapp skin, the default skin or <code>null</code>,
129     * depending on whether or not the property or skins exist.
130     */
131    public String get(String key)
132    {
133        return uiService.get(getSkin(), key);
134    }
135
136    /**
137     * Retrieve the skin name.
138     * @return the selected skin name
139     */
140    public String getSkin()
141    {
142        return skinName;
143    }
144
145    /**
146     * Set the skin name to the skin from the TurbineResources.properties file.
147     * If the property is not present use the "default" skin.
148     */
149    public void setSkin()
150    {
151        skinName = uiService.getWebappSkinName();
152    }
153
154    /**
155     * Set the skin name to the specified skin.
156     *
157     * @param skinName the skin name to use.
158     */
159    public void setSkin(String skinName)
160    {
161        this.skinName = skinName;
162    }
163
164    /**
165     * Set the skin name when the tool is configured to be loaded on a
166     * per-request basis. By default it calls getSkin to return the skin
167     * specified in TurbineResources.properties. Developers can write a subclass
168     * of UITool that overrides this method to determine the skin to use based
169     * on information held in the request.
170     *
171     * @param data a RunData instance
172     */
173    protected void setSkin(RunData data)
174    {
175        setSkin();
176    }
177
178    /**
179     * Set the skin name when the tool is configured to be loaded on a
180     * per-session basis. If the user's temp hashmap contains a value in the
181     * attribute specified by the String constant SKIN_ATTRIBUTE then that is
182     * returned. Otherwise it calls getSkin to return the skin specified in
183     * TurbineResources.properties.
184     *
185     * @param user a User instance
186     */
187    protected void setSkin(User user)
188    {
189        if (user.getTemp(SKIN_ATTRIBUTE) == null)
190        {
191            setSkin();
192        }
193        else
194        {
195            setSkin((String) user.getTemp(SKIN_ATTRIBUTE));
196        }
197    }
198
199    /**
200     * Set the skin name in the user's temp hashmap for the current session.
201     *
202     * @param user a User instance
203     * @param skin the skin name for the session
204     */
205    public static void setSkin(User user, String skin)
206    {
207        user.setTemp(SKIN_ATTRIBUTE, skin);
208    }
209
210    /**
211     * Retrieve the URL for an image that is part of the skin. The images are
212     * stored in the WEBAPP/resources/ui/skins/[SKIN]/images directory.
213     *
214     * <p>Use this if for some reason your server name, server scheme, or server
215     * port change on a per request basis. I'm not sure if this would happen in
216     * a load balanced situation. I think in most cases the image(String image)
217     * method would probably be enough, but I'm not absolutely positive.
218     *
219     * @param imageId the id of the image whose URL will be generated.
220     * @param data the RunData to use as the source of the ServerData to use as
221     * the basis for the URL.
222     * @return the image URL
223     */
224    public String image(String imageId, RunData data)
225    {
226        return image(imageId, data.getServerData());
227    }
228
229    /**
230     * Retrieve the URL for an image that is part of the skin. The images are
231     * stored in the WEBAPP/resources/ui/skins/[SKIN]/images directory.
232     *
233     * <p>Use this if for some reason your server name, server scheme, or server
234     * port change on a per request basis. I'm not sure if this would happen in
235     * a load balanced situation. I think in most cases the image(String image)
236     * method would probably be enough, but I'm not absolutely positive.
237     *
238     * @param imageId the id of the image whose URL will be generated.
239     * @param serverData the serverData to use as the basis for the URL.
240     * @return the image URL
241     */
242    public String image(String imageId, ServerData serverData)
243    {
244        return uiService.image(getSkin(), imageId, serverData);
245    }
246
247    /**
248     * Retrieve the URL for an image that is part of the skin. The images are
249     * stored in the WEBAPP/resources/ui/skins/[SKIN]/images directory.
250     *
251     * @param imageId the id of the image whose URL will be generated.
252     * @return the image URL
253     */
254    public String image(String imageId)
255    {
256        return uiService.image(getSkin(), imageId);
257    }
258
259    /**
260     * Retrieve the URL for the style sheet that is part of the skin. The style
261     * is stored in the WEBAPP/resources/ui/skins/[SKIN] directory with the
262     * filename skin.css
263     *
264     * <p>Use this if for some reason your server name, server scheme, or server
265     * port change on a per request basis. I'm not sure if this would happen in
266     * a load balanced situation. I think in most cases the style() method would
267     * probably be enough, but I'm not absolutely positive.
268     *
269     * @param data the RunData to use as the source of the ServerData to use as
270     * the basis for the URL.
271     * @return the CSS URL
272     */
273    public String getStylecss(RunData data)
274    {
275        return getStylecss(data.getServerData());
276    }
277
278    /**
279     * Retrieve the URL for the style sheet that is part of the skin. The style
280     * is stored in the WEBAPP/resources/ui/skins/[SKIN] directory with the
281     * filename skin.css
282     *
283     * <p>Use this if for some reason your server name, server scheme, or server
284     * port change on a per request basis. I'm not sure if this would happen in
285     * a load balanced situation. I think in most cases the style() method would
286     * probably be enough, but I'm not absolutely positive.
287     *
288     * @param serverData the serverData to use as the basis for the URL.
289     * @return the CSS URL
290     */
291    public String getStylecss(ServerData serverData)
292    {
293        return uiService.getStylecss(getSkin(), serverData);
294    }
295
296    /**
297     * Retrieve the URL for the style sheet that is part of the skin. The style
298     * is stored in the WEBAPP/resources/ui/skins/[SKIN] directory with the
299     * filename skin.css
300     * @return the CSS URL
301     */
302    public String getStylecss()
303    {
304        return uiService.getStylecss(getSkin());
305    }
306
307    /**
308     * Retrieve the URL for a given script that is part of the skin. The script
309     * is stored in the WEBAPP/resources/ui/skins/[SKIN] directory.
310     *
311     * <p>Use this if for some reason your server name, server scheme, or server
312     * port change on a per request basis. I'm not sure if this would happen in
313     * a load balanced situation. I think in most cases the image(String image)
314     * method would probably be enough, but I'm not absolutely positive.
315     *
316     * @param filename the name of the script file whose URL will be generated.
317     * @param data the RunDate to use as the source of the ServerData to use as
318     * the basis for the URL.
319     * @return the script URL
320     */
321    public String getScript(String filename, RunData data)
322    {
323        return getScript(filename, data.getServerData());
324    }
325
326    /**
327     * Retrieve the URL for a given script that is part of the skin. The script
328     * is stored in the WEBAPP/resources/ui/skins/[SKIN] directory.
329     *
330     * <p>Use this if for some reason your server name, server scheme, or server
331     * port change on a per request basis. I'm not sure if this would happen in
332     * a load balanced situation. I think in most cases the image(String image)
333     * method would probably be enough, but I'm not absolutely positive.
334     *
335     * @param filename the name of the script file whose URL will be generated.
336     * @param serverData the serverData to use as the basis for the URL.
337     * @return the script URL
338     */
339    public String getScript(String filename, ServerData serverData)
340    {
341        return uiService.getScript(getSkin(), filename, serverData);
342    }
343
344    /**
345     * Retrieve the URL for a given script that is part of the skin. The script
346     * is stored in the WEBAPP/resources/ui/skins/[SKIN] directory.
347     *
348     * @param filename the name of the script file whose URL will be generated.
349     * @return the script URL
350     */
351    public String getScript(String filename)
352    {
353        return uiService.getScript(getSkin(), filename);
354    }
355
356    /**
357     * Initialize the UITool object.
358     *
359     * @param data This is null, RunData or User depending upon specified tool
360     * scope.
361     */
362    @Override
363    public void init(Object data)
364    {
365        if (data == null)
366        {
367            log.debug("UITool scope is global");
368            setSkin();
369        }
370        else if (data instanceof RunData)
371        {
372            log.debug("UITool scope is request");
373            setSkin((RunData) data);
374        }
375        else if (data instanceof PipelineData)
376        {
377            PipelineData pipelineData = (PipelineData) data;
378            RunData runData = (RunData)pipelineData;
379            log.debug("UITool scope is request");
380            setSkin(runData);
381        }
382        else if (data instanceof User)
383        {
384            log.debug("UITool scope is session");
385            setSkin((User) data);
386        }
387    }
388
389}