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