##### Coverage Report - org.apache.turbine.services.ui.TurbineUIService

Classes in this File | Line Coverage | Branch Coverage | Complexity
TurbineUIService |
43% | 39/90
19% | 5/26
| 1.9;1,9

1 |  |
     package org.apache.turbine.services.ui;
2 |  |
3 |  |
     /*
4 |  |
      * Licensed to the Apache Software Foundation (ASF) under one
5 |  |
      * or more contributor license agreements.  See the NOTICE file
6 |  |
      * distributed with this work for additional information
7 |  |
      * regarding copyright ownership.  The ASF licenses this file
8 |  |
      * to you under the Apache License, Version 2.0 (the
9 |  |
      * "License"); you may not use this file except in compliance
10 |  |
      * with the License.  You may obtain a copy of the License at
11 |  |
      *
12 |  |
      *   http://www.apache.org/licenses/LICENSE-2.0
13 |  |
      *
14 |  |
      * Unless required by applicable law or agreed to in writing,
15 |  |
      * software distributed under the License is distributed on an
16 |  |
      * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17 |  |
      * KIND, either express or implied.  See the License for the
18 |  |
      * specific language governing permissions and limitations
19 |  |
      * under the License.
20 |  |
      */
21 |  |
22 |  |
     import java.io.File;
23 |  |
     import java.io.InputStream;
24 |  |
     import java.util.Properties;
25 |  |
     import java.util.concurrent.ConcurrentHashMap;
26 |  |
27 |  |
     import org.apache.commons.configuration.Configuration;
28 |  |
     import org.apache.commons.io.IOUtils;
29 |  |
     import org.apache.commons.io.filefilter.DirectoryFileFilter;
30 |  |
     import org.apache.commons.lang.StringUtils;
31 |  |
     import org.apache.commons.logging.Log;
32 |  |
     import org.apache.commons.logging.LogFactory;
33 |  |
     import org.apache.turbine.Turbine;
34 |  |
     import org.apache.turbine.services.InitializationException;
35 |  |
     import org.apache.turbine.services.TurbineBaseService;
36 |  |
     import org.apache.turbine.services.TurbineServices;
37 |  |
     import org.apache.turbine.services.pull.PullService;
38 |  |
     import org.apache.turbine.services.pull.tools.UITool;
39 |  |
     import org.apache.turbine.services.servlet.ServletService;
40 |  |
     import org.apache.turbine.util.ServerData;
41 |  |
     import org.apache.turbine.util.uri.DataURI;
42 |  |
43 |  |
     /**
44 |  |
      * The UI service provides for shared access to User Interface (skin) files,
45 |  |
      * as well as the ability for non-default skin files to inherit properties from
46 |  |
      * a default skin.  Use TurbineUI to access skin properties from your screen
47 |  |
      * classes and action code. UITool is provided as a pull tool for accessing
48 |  |
      * skin properties from your templates.
49 |  |
      *
50 |  |
      * @author <a href="mailto:jvanzyl@periapt.com">Jason van Zyl</a>
51 |  |
      * @author <a href="mailto:james_coltman@majorband.co.uk">James Coltman</a>
52 |  |
      * @author <a href="mailto:hps@intermeta.de">Henning P. Schmiedehausen</a>
53 |  |
      * @author <a href="mailto:seade@backstagetech.com.au">Scott Eade</a>
54 |  |
      * @author <a href="thomas.vandahl@tewisoft.de">Thomas Vandahl</a>
55 |  |
      * @version $Id$
56 |  |
      * @see UIService
57 |  |
      * @see UITool
58 |  |
      */
59 | 17 |
     public class TurbineUIService
60 |  |
             extends TurbineBaseService
61 |  |
             implements UIService
62 |  |
     {
63 |  |
         /** Logging. */
64 | 17 |
         private static Log log = LogFactory.getLog(TurbineUIService.class);
65 |  |
66 |  |
         /**
67 |  |
          * The location of the skins within the application resources directory.
68 |  |
          */
69 |  |
         private static final String SKINS_DIRECTORY = "/ui/skins";
70 |  |
71 |  |
         /**
72 |  |
          * The name of the directory where images are stored for this skin.
73 |  |
          */
74 |  |
         private static final String IMAGES_DIRECTORY = "/images";
75 |  |
76 |  |
         /**
77 |  |
          * Property tag for the default skin that is to be used for the web
78 |  |
          * application.
79 |  |
          */
80 |  |
         private static final String SKIN_PROPERTY = "tool.ui.skin";
81 |  |
82 |  |
         /**
83 |  |
          * Property tag for the image directory inside the skin that is to be used
84 |  |
          * for the web application.
85 |  |
          */
86 |  |
         private static final String IMAGEDIR_PROPERTY = "tool.ui.dir.image";
87 |  |
88 |  |
         /**
89 |  |
          * Property tag for the skin directory that is to be used for the web
90 |  |
          * application.
91 |  |
          */
92 |  |
         private static final String SKINDIR_PROPERTY = "tool.ui.dir.skin";
93 |  |
94 |  |
         /**
95 |  |
          * Property tag for the css file that is to be used for the web application.
96 |  |
          */
97 |  |
         private static final String CSS_PROPERTY = "tool.ui.css";
98 |  |
99 |  |
         /**
100 |  |
          * Property tag for indicating if relative links are wanted for the web
101 |  |
          * application.
102 |  |
          */
103 |  |
         private static final String RELATIVE_PROPERTY = "tool.ui.want.relative";
104 |  |
105 |  |
         /**
106 |  |
          * Default skin name. This name refers to a directory in the
107 |  |
          * WEBAPP/resources/ui/skins directory. There is a file called skin.props
108 |  |
          * which contains the name/value pairs to be made available via the skin.
109 |  |
          */
110 |  |
         public static final String SKIN_PROPERTY_DEFAULT = "default";
111 |  |
112 |  |
         /**
113 |  |
          * The skins directory, qualified by the resources directory (which is
114 |  |
          * relative to the webapp context). This is used for constructing URIs and
115 |  |
          * for retrieving skin files.
116 |  |
          */
117 |  |
         private String skinsDirectory;
118 |  |
119 |  |
         /**
120 |  |
          * The file within the skin directory that contains the name/value pairs for
121 |  |
          * the skin.
122 |  |
          */
123 |  |
         private static final String SKIN_PROPS_FILE = "skin.props";
124 |  |
125 |  |
         /**
126 |  |
          * The file name for the skin style sheet.
127 |  |
          */
128 |  |
         private static final String DEFAULT_SKIN_CSS_FILE = "skin.css";
129 |  |
130 |  |
         /**
131 |  |
          * The servlet service.
132 |  |
          */
133 |  |
         private ServletService servletService;
134 |  |
135 |  |
         /**
136 |  |
          * The directory within the skin directory that contains the skin images.
137 |  |
          */
138 |  |
         private String imagesDirectory;
139 |  |
140 |  |
         /**
141 |  |
          * The name of the css file within the skin directory.
142 |  |
          */
143 |  |
         private String cssFile;
144 |  |
145 |  |
         /**
146 |  |
          * The flag that determines if the links that are returned are are absolute
147 |  |
          * or relative.
148 |  |
          */
149 | 17 |
         private boolean wantRelative = false;
150 |  |
151 |  |
         /**
152 |  |
          * The skin Properties store.
153 |  |
          */
154 | 17 |
         private ConcurrentHashMap<String, Properties> skins = new ConcurrentHashMap<String, Properties>();
155 |  |
156 |  |
         /**
157 |  |
          * Refresh the service by clearing all skins.
158 |  |
          */
159 |  |
         @Override
160 |  |
         public void refresh()
161 |  |
         {
162 | 0 |
             clearSkins();
163 | 0 |
         }
164 |  |
165 |  |
         /**
166 |  |
          * Refresh a particular skin by clearing it.
167 |  |
          *
168 |  |
          * @param skinName the name of the skin to clear.
169 |  |
          */
170 |  |
         @Override
171 |  |
         public void refresh(String skinName)
172 |  |
         {
173 | 10 |
             clearSkin(skinName);
174 | 10 |
         }
175 |  |
176 |  |
         /**
177 |  |
          * Retrieve the Properties for a specific skin.  If they are not yet loaded
178 |  |
          * they will be.  If the specified skin does not exist properties for the
179 |  |
          * default skin configured for the webapp will be returned and an error
180 |  |
          * level message will be written to the log.  If the webapp skin does not
181 |  |
          * exist the default skin will be used and id that doesn't exist an empty
182 |  |
          * Properties will be returned.
183 |  |
          *
184 |  |
          * @param skinName the name of the skin whose properties are to be
185 |  |
          * retrieved.
186 |  |
          * @return the Properties for the named skin or the properties for the
187 |  |
          * default skin configured for the webapp if the named skin does not exist.
188 |  |
          */
189 |  |
         private Properties getSkinProperties(String skinName)
190 |  |
         {
191 | 0 |
             Properties skinProperties = skins.get(skinName);
192 | 0 |
             return null != skinProperties ? skinProperties : loadSkin(skinName);
193 |  |
         }
194 |  |
195 |  |
         /**
196 |  |
          * Retrieve a skin property from the named skin.  If the property is not
197 |  |
          * defined in the named skin the value for the default skin will be
198 |  |
          * provided.  If the named skin does not exist then the skin configured for
199 |  |
          * the webapp will be used.  If the webapp skin does not exist the default
200 |  |
          * skin will be used.  If the default skin does not exist then
201 |  |
          * <code>null</code> will be returned.
202 |  |
          *
203 |  |
          * @param skinName the name of the skin to retrieve the property from.
204 |  |
          * @param key the key to retrieve from the skin.
205 |  |
          * @return the value of the property for the named skin (defaulting to the
206 |  |
          * default skin), the webapp skin, the default skin or <code>null</code>,
207 |  |
          * depending on whether or not the property or skins exist.
208 |  |
          */
209 |  |
         @Override
210 |  |
         public String get(String skinName, String key)
211 |  |
         {
212 | 0 |
             Properties skinProperties = getSkinProperties(skinName);
213 | 0 |
             return skinProperties.getProperty(key);
214 |  |
         }
215 |  |
216 |  |
         /**
217 |  |
          * Retrieve a skin property from the default skin for the webapp.  If the
218 |  |
          * property is not defined in the webapp skin the value for the default skin
219 |  |
          * will be provided.  If the webapp skin does not exist the default skin
220 |  |
          * will be used.  If the default skin does not exist then <code>null</code>
221 |  |
          * will be returned.
222 |  |
          *
223 |  |
          * @param key the key to retrieve.
224 |  |
          * @return the value of the property for the webapp skin (defaulting to the
225 |  |
          * default skin), the default skin or <code>null</code>, depending on
226 |  |
          * whether or not the property or skins exist.
227 |  |
          */
228 |  |
         @Override
229 |  |
         public String get(String key)
230 |  |
         {
231 | 0 |
             return get(getWebappSkinName(), key);
232 |  |
         }
233 |  |
234 |  |
         /**
235 |  |
          * Provide access to the list of available skin names.
236 |  |
          *
237 |  |
          * @return the available skin names.
238 |  |
          */
239 |  |
         @Override
240 |  |
         public String[] getSkinNames()
241 |  |
         {
242 | 0 |
             File skinsDir = new File(servletService.getRealPath(skinsDirectory));
243 | 0 |
             return skinsDir.list(DirectoryFileFilter.INSTANCE);
244 |  |
         }
245 |  |
246 |  |
         /**
247 |  |
          * Clear the map of stored skins.
248 |  |
          */
249 |  |
         private void clearSkins()
250 |  |
         {
251 | 19 |
             skins.clear();
252 | 19 |
             log.debug("All skins were cleared.");
253 | 19 |
         }
254 |  |
255 |  |
         /**
256 |  |
          * Clear a particular skin from the map of stored skins.
257 |  |
          *
258 |  |
          * @param skinName the name of the skin to clear.
259 |  |
          */
260 |  |
         private void clearSkin(String skinName)
261 |  |
         {
262 | 10 |
             if (!skinName.equals(SKIN_PROPERTY_DEFAULT))
263 |  |
             {
264 | 10 |
                 skins.remove(SKIN_PROPERTY_DEFAULT);
265 |  |
             }
266 | 10 |
             skins.remove(skinName);
267 | 10 |
             log.debug("The skin \"" + skinName
268 |  |
                     + "\" was cleared (will also clear \"default\" skin).");
269 | 10 |
         }
270 |  |
271 |  |
         /**
272 |  |
          * Load the specified skin.
273 |  |
          *
274 |  |
          * @param skinName the name of the skin to load.
275 |  |
          * @return the Properties for the named skin if it exists, or the skin
276 |  |
          * configured for the web application if it does not exist, or the default
277 |  |
          * skin if that does not exist, or an empty Parameters object if even that
278 |  |
          * cannot be found.
279 |  |
          */
280 |  |
         private Properties loadSkin(String skinName)
281 |  |
         {
282 | 0 |
             Properties defaultSkinProperties = null;
283 |  |
284 | 0 |
             if (!StringUtils.equals(skinName, SKIN_PROPERTY_DEFAULT))
285 |  |
             {
286 | 0 |
                 defaultSkinProperties = getSkinProperties(SKIN_PROPERTY_DEFAULT);
287 |  |
             }
288 |  |
289 |  |
             // The following line is okay even for default.
290 | 0 |
             Properties skinProperties = new Properties(defaultSkinProperties);
291 |  |
292 | 0 |
             StringBuilder sb = new StringBuilder();
293 | 0 |
             sb.append('/').append(skinsDirectory);
294 | 0 |
             sb.append('/').append(skinName);
295 | 0 |
             sb.append('/').append(SKIN_PROPS_FILE);
296 | 0 |
             if (log.isDebugEnabled())
297 |  |
             {
298 | 0 |
                 log.debug("Loading selected skin from: " + sb.toString());
299 |  |
             }
300 |  |
301 | 0 |
             InputStream is = null;
302 |  |
303 |  |
             try
304 |  |
             {
305 |  |
                 // This will NPE if the directory associated with the skin does not
306 |  |
                 // exist, but it is handled correctly below.
307 | 0 |
                 is = servletService.getResourceAsStream(sb.toString());
308 | 0 |
                 skinProperties.load(is);
309 |  |
             }
310 | 0 |
             catch (Exception e)
311 |  |
             {
312 | 0 |
                 log.error("Cannot load skin: " + skinName + ", from: "
313 |  |
                         + sb.toString(), e);
314 | 0 |
                 if (!StringUtils.equals(skinName, getWebappSkinName())
315 |  |
                         && !StringUtils.equals(skinName, SKIN_PROPERTY_DEFAULT))
316 |  |
                 {
317 | 0 |
                     log.error("Attempting to return the skin configured for "
318 |  |
                             + "webapp instead of " + skinName);
319 | 0 |
                     return getSkinProperties(getWebappSkinName());
320 |  |
                 }
321 | 0 |
                 else if (!StringUtils.equals(skinName, SKIN_PROPERTY_DEFAULT))
322 |  |
                 {
323 | 0 |
                     log.error("Return the default skin instead of " + skinName);
324 | 0 |
                     return skinProperties; // Already contains the default skin.
325 |  |
                 }
326 |  |
                 else
327 |  |
                 {
328 | 0 |
                     log.error("No skins available - returning an empty Properties");
329 | 0 |
                     return new Properties();
330 |  |
                 }
331 |  |
             }
332 |  |
             finally
333 |  |
             {
334 | 0 |
                 IOUtils.closeQuietly(is);
335 | 0 |
             }
336 |  |
337 |  |
             // Replace in skins HashMap
338 | 0 |
             skins.put(skinName, skinProperties);
339 |  |
340 | 0 |
             return skinProperties;
341 |  |
         }
342 |  |
343 |  |
         /**
344 |  |
          * Get the name of the default skin name for the web application from the
345 |  |
          * TurbineResources.properties file. If the property is not present the
346 |  |
          * name of the default skin will be returned.  Note that the web application
347 |  |
          * skin name may be something other than default, in which case its
348 |  |
          * properties will default to the skin with the name "default".
349 |  |
          *
350 |  |
          * @return the name of the default skin for the web application.
351 |  |
          */
352 |  |
         @Override
353 |  |
         public String getWebappSkinName()
354 |  |
         {
355 | 19 |
             return Turbine.getConfiguration()
356 |  |
                     .getString(SKIN_PROPERTY, SKIN_PROPERTY_DEFAULT);
357 |  |
         }
358 |  |
359 |  |
         /**
360 |  |
          * Retrieve the URL for an image that is part of a skin. The images are
361 |  |
          * stored in the WEBAPP/resources/ui/skins/[SKIN]/images directory.
362 |  |
          *
363 |  |
          * <p>Use this if for some reason your server name, server scheme, or server
364 |  |
          * port change on a per request basis. I'm not sure if this would happen in
365 |  |
          * a load balanced situation. I think in most cases the image(String image)
366 |  |
          * method would probably be enough, but I'm not absolutely positive.
367 |  |
          *
368 |  |
          * @param skinName the name of the skin to retrieve the image from.
369 |  |
          * @param imageId the id of the image whose URL will be generated.
370 |  |
          * @param serverData the serverData to use as the basis for the URL.
371 |  |
          */
372 |  |
         @Override
373 |  |
         public String image(String skinName, String imageId, ServerData serverData)
374 |  |
         {
375 | 0 |
             return getSkinResource(serverData, skinName, imagesDirectory, imageId);
376 |  |
         }
377 |  |
378 |  |
         /**
379 |  |
          * Retrieve the URL for an image that is part of a skin. The images are
380 |  |
          * stored in the WEBAPP/resources/ui/skins/[SKIN]/images directory.
381 |  |
          *
382 |  |
          * @param skinName the name of the skin to retrieve the image from.
383 |  |
          * @param imageId the id of the image whose URL will be generated.
384 |  |
          */
385 |  |
         @Override
386 |  |
         public String image(String skinName, String imageId)
387 |  |
         {
388 | 0 |
             return image(skinName, imageId, Turbine.getDefaultServerData());
389 |  |
         }
390 |  |
391 |  |
         /**
392 |  |
          * Retrieve the URL for the style sheet that is part of a skin. The style is
393 |  |
          * stored in the WEBAPP/resources/ui/skins/[SKIN] directory with the
394 |  |
          * filename skin.css
395 |  |
          *
396 |  |
          * <p>Use this if for some reason your server name, server scheme, or server
397 |  |
          * port change on a per request basis. I'm not sure if this would happen in
398 |  |
          * a load balanced situation. I think in most cases the style() method would
399 |  |
          * probably be enough, but I'm not absolutely positive.
400 |  |
          *
401 |  |
          * @param skinName the name of the skin to retrieve the style sheet from.
402 |  |
          * @param serverData the serverData to use as the basis for the URL.
403 |  |
          */
404 |  |
         @Override
405 |  |
         public String getStylecss(String skinName, ServerData serverData)
406 |  |
         {
407 | 0 |
             return getSkinResource(serverData, skinName, null, cssFile);
408 |  |
         }
409 |  |
410 |  |
         /**
411 |  |
          * Retrieve the URL for the style sheet that is part of a skin. The style is
412 |  |
          * stored in the WEBAPP/resources/ui/skins/[SKIN] directory with the
413 |  |
          * filename skin.css
414 |  |
          *
415 |  |
          * @param skinName the name of the skin to retrieve the style sheet from.
416 |  |
          */
417 |  |
         @Override
418 |  |
         public String getStylecss(String skinName)
419 |  |
         {
420 | 0 |
             return getStylecss(skinName, Turbine.getDefaultServerData());
421 |  |
         }
422 |  |
423 |  |
         /**
424 |  |
          * Retrieve the URL for a given script that is part of a skin. The script is
425 |  |
          * stored in the WEBAPP/resources/ui/skins/[SKIN] directory.
426 |  |
          *
427 |  |
          * <p>Use this if for some reason your server name, server scheme, or server
428 |  |
          * port change on a per request basis. I'm not sure if this would happen in
429 |  |
          * a load balanced situation. I think in most cases the style() method would
430 |  |
          * probably be enough, but I'm not absolutely positive.
431 |  |
          *
432 |  |
          * @param skinName the name of the skin to retrieve the image from.
433 |  |
          * @param filename the name of the script file.
434 |  |
          * @param serverData the serverData to use as the basis for the URL.
435 |  |
          */
436 |  |
         @Override
437 |  |
         public String getScript(String skinName, String filename,
438 |  |
                 ServerData serverData)
439 |  |
         {
440 | 0 |
             return getSkinResource(serverData, skinName, null, filename);
441 |  |
         }
442 |  |
443 |  |
         /**
444 |  |
          * Retrieve the URL for a given script that is part of a skin. The script is
445 |  |
          * stored in the WEBAPP/resources/ui/skins/[SKIN] directory.
446 |  |
          *
447 |  |
          * @param skinName the name of the skin to retrieve the image from.
448 |  |
          * @param filename the name of the script file.
449 |  |
          */
450 |  |
         @Override
451 |  |
         public String getScript(String skinName, String filename)
452 |  |
         {
453 | 0 |
             return getScript(skinName, filename, Turbine.getDefaultServerData());
454 |  |
         }
455 |  |
456 |  |
         private String stripSlashes(final String path)
457 |  |
         {
458 | 57 |
             if (StringUtils.isEmpty(path))
459 |  |
             {
460 | 0 |
                 return "";
461 |  |
             }
462 |  |
463 | 57 |
             String ret = path;
464 | 57 |
             int len = ret.length() - 1;
465 |  |
466 | 57 |
             if (ret.charAt(len) == '/')
467 |  |
             {
468 | 57 |
                 ret = ret.substring(0, len);
469 |  |
             }
470 |  |
471 | 57 |
             if (len > 0 && ret.charAt(0) == '/')
472 |  |
             {
473 | 57 |
                 ret = ret.substring(1);
474 |  |
             }
475 |  |
476 | 57 |
             return ret;
477 |  |
         }
478 |  |
479 |  |
         /**
480 |  |
          * Construct the URL to the skin resource.
481 |  |
          *
482 |  |
          * @param serverData the serverData to use as the basis for the URL.
483 |  |
          * @param skinName the name of the skin.
484 |  |
          * @param subDir the sub-directory in which the resource resides or
485 |  |
          * <code>null</code> if it is in the root directory of the skin.
486 |  |
          * @param resourceName the name of the resource to be retrieved.
487 |  |
          * @return the path to the resource.
488 |  |
          */
489 |  |
         private String getSkinResource(ServerData serverData, String skinName,
490 |  |
                 String subDir, String resourceName)
491 |  |
         {
492 | 0 |
             StringBuilder sb = new StringBuilder(skinsDirectory);
493 | 0 |
             sb.append("/").append(skinName);
494 | 0 |
             if (subDir != null)
495 |  |
             {
496 | 0 |
                 sb.append("/").append(subDir);
497 |  |
             }
498 | 0 |
             sb.append("/").append(stripSlashes(resourceName));
499 |  |
500 | 0 |
             DataURI du = new DataURI(serverData);
501 | 0 |
             du.setScriptName(sb.toString());
502 | 0 |
             return wantRelative ? du.getRelativeLink() : du.getAbsoluteLink();
503 |  |
         }
504 |  |
505 |  |
         // ---- Service initilization ------------------------------------------
506 |  |
507 |  |
         /**
508 |  |
          * Initializes the service.
509 |  |
          */
510 |  |
         @Override
511 |  |
         public void init() throws InitializationException
512 |  |
         {
513 | 19 |
             Configuration cfg = Turbine.getConfiguration();
514 |  |
515 | 19 |
             servletService = (ServletService)TurbineServices.getInstance().getService(ServletService.SERVICE_NAME);
516 | 19 |
             PullService pullService = (PullService)TurbineServices.getInstance().getService(PullService.SERVICE_NAME);
517 |  |
             // Get the resources directory that is specified in the TR.props or
518 |  |
             // default to "resources", relative to the webapp.
519 | 19 |
             StringBuilder sb = new StringBuilder();
520 | 19 |
             sb.append(stripSlashes(pullService.getResourcesDirectory()));
521 | 19 |
             sb.append("/");
522 | 19 |
             sb.append(stripSlashes(
523 |  |
                     cfg.getString(SKINDIR_PROPERTY, SKINS_DIRECTORY)));
524 | 19 |
             skinsDirectory = sb.toString();
525 |  |
526 | 19 |
             imagesDirectory = stripSlashes(
527 |  |
                     cfg.getString(IMAGEDIR_PROPERTY, IMAGES_DIRECTORY));
528 | 19 |
             cssFile = cfg.getString(CSS_PROPERTY, DEFAULT_SKIN_CSS_FILE);
529 | 19 |
             wantRelative = cfg.getBoolean(RELATIVE_PROPERTY, false);
530 |  |
531 | 19 |
             setInit(true);
532 | 19 |
         }
533 |  |
534 |  |
         /**
535 |  |
          * Returns to uninitialized state.
536 |  |
          */
537 |  |
         @Override
538 |  |
         public void shutdown()
539 |  |
         {
540 | 19 |
             clearSkins();
541 | 19 |
             setInit(false);
542 | 19 |
         }
543 |  |
     }