001    /**
002     * Copyright (c) 2000-2013 Liferay, Inc. All rights reserved.
003     *
004     * This library is free software; you can redistribute it and/or modify it under
005     * the terms of the GNU Lesser General Public License as published by the Free
006     * Software Foundation; either version 2.1 of the License, or (at your option)
007     * any later version.
008     *
009     * This library is distributed in the hope that it will be useful, but WITHOUT
010     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
011     * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
012     * details.
013     */
014    
015    package com.liferay.portal.service.impl;
016    
017    import com.liferay.portal.kernel.exception.SystemException;
018    import com.liferay.portal.kernel.image.SpriteProcessor;
019    import com.liferay.portal.kernel.image.SpriteProcessorUtil;
020    import com.liferay.portal.kernel.log.Log;
021    import com.liferay.portal.kernel.log.LogFactoryUtil;
022    import com.liferay.portal.kernel.plugin.PluginPackage;
023    import com.liferay.portal.kernel.plugin.Version;
024    import com.liferay.portal.kernel.servlet.ServletContextUtil;
025    import com.liferay.portal.kernel.util.ColorSchemeFactoryUtil;
026    import com.liferay.portal.kernel.util.ContextPathUtil;
027    import com.liferay.portal.kernel.util.GetterUtil;
028    import com.liferay.portal.kernel.util.ListUtil;
029    import com.liferay.portal.kernel.util.ReleaseInfo;
030    import com.liferay.portal.kernel.util.StringPool;
031    import com.liferay.portal.kernel.util.StringUtil;
032    import com.liferay.portal.kernel.util.ThemeFactoryUtil;
033    import com.liferay.portal.kernel.util.Validator;
034    import com.liferay.portal.kernel.xml.Document;
035    import com.liferay.portal.kernel.xml.Element;
036    import com.liferay.portal.kernel.xml.SAXReaderUtil;
037    import com.liferay.portal.model.ColorScheme;
038    import com.liferay.portal.model.PluginSetting;
039    import com.liferay.portal.model.PortletConstants;
040    import com.liferay.portal.model.Theme;
041    import com.liferay.portal.plugin.PluginUtil;
042    import com.liferay.portal.service.base.ThemeLocalServiceBaseImpl;
043    import com.liferay.portal.theme.ThemeCompanyId;
044    import com.liferay.portal.theme.ThemeCompanyLimit;
045    import com.liferay.portal.theme.ThemeGroupId;
046    import com.liferay.portal.theme.ThemeGroupLimit;
047    import com.liferay.portal.util.PortalUtil;
048    import com.liferay.portal.util.PropsValues;
049    import com.liferay.util.ContextReplace;
050    
051    import java.net.URL;
052    
053    import java.util.ArrayList;
054    import java.util.HashSet;
055    import java.util.Iterator;
056    import java.util.List;
057    import java.util.Map;
058    import java.util.Properties;
059    import java.util.Set;
060    import java.util.concurrent.ConcurrentHashMap;
061    
062    import javax.servlet.ServletContext;
063    
064    /**
065     * @author Brian Wing Shun Chan
066     * @author Jorge Ferrer
067     * @author Raymond Augé
068     */
069    public class ThemeLocalServiceImpl extends ThemeLocalServiceBaseImpl {
070    
071            public ColorScheme fetchColorScheme(
072                    long companyId, String themeId, String colorSchemeId) {
073    
074                    colorSchemeId = GetterUtil.getString(colorSchemeId);
075    
076                    Theme theme = fetchTheme(companyId, themeId);
077    
078                    if (theme == null) {
079                            return null;
080                    }
081    
082                    Map<String, ColorScheme> colorSchemesMap = theme.getColorSchemesMap();
083    
084                    return colorSchemesMap.get(colorSchemeId);
085            }
086    
087            public Theme fetchTheme(long companyId, String themeId) {
088                    themeId = GetterUtil.getString(themeId);
089    
090                    Map<String, Theme> themes = _getThemes(companyId);
091    
092                    return themes.get(themeId);
093            }
094    
095            public ColorScheme getColorScheme(
096                            long companyId, String themeId, String colorSchemeId,
097                            boolean wapTheme)
098                    throws SystemException {
099    
100                    colorSchemeId = GetterUtil.getString(colorSchemeId);
101    
102                    Theme theme = getTheme(companyId, themeId, wapTheme);
103    
104                    Map<String, ColorScheme> colorSchemesMap = theme.getColorSchemesMap();
105    
106                    ColorScheme colorScheme = colorSchemesMap.get(colorSchemeId);
107    
108                    if (colorScheme == null) {
109                            List<ColorScheme> colorSchemes = theme.getColorSchemes();
110    
111                            if (colorSchemes.size() > 0) {
112                                    for (int i = (colorSchemes.size() - 1); i >= 0; i--) {
113                                            colorScheme = colorSchemes.get(i);
114    
115                                            if (colorScheme.isDefaultCs()) {
116                                                    break;
117                                            }
118                                    }
119                            }
120                    }
121    
122                    if (colorScheme == null) {
123                            if (wapTheme) {
124                                    colorScheme = ColorSchemeFactoryUtil.getDefaultWapColorScheme();
125                            }
126                            else {
127                                    colorScheme =
128                                            ColorSchemeFactoryUtil.getDefaultRegularColorScheme();
129                            }
130                    }
131    
132                    return colorScheme;
133            }
134    
135            public Theme getTheme(long companyId, String themeId, boolean wapTheme)
136                    throws SystemException {
137    
138                    themeId = GetterUtil.getString(themeId);
139    
140                    Map<String, Theme> themes = _getThemes(companyId);
141    
142                    Theme theme = themes.get(themeId);
143    
144                    if (theme == null) {
145                            if (_log.isWarnEnabled()) {
146                                    _log.warn(
147                                            "No theme found for specified theme id " + themeId +
148                                                    ". Returning the default theme.");
149                            }
150    
151                            if (wapTheme) {
152                                    themeId = ThemeFactoryUtil.getDefaultWapThemeId(companyId);
153                            }
154                            else {
155                                    themeId = ThemeFactoryUtil.getDefaultRegularThemeId(companyId);
156                            }
157    
158                            theme = _themes.get(themeId);
159                    }
160    
161                    if (theme == null) {
162                            if (_themes.isEmpty()) {
163                                    if (_log.isDebugEnabled()) {
164                                            _log.debug("No themes are installed");
165                                    }
166    
167                                    return null;
168                            }
169    
170                            if (!themeId.contains(PortletConstants.WAR_SEPARATOR)) {
171                                    _log.error(
172                                            "No theme found for default theme id " + themeId +
173                                                    ". Returning a random theme.");
174                            }
175    
176                            for (Map.Entry<String, Theme> entry : _themes.entrySet()) {
177                                    theme = entry.getValue();
178                            }
179                    }
180    
181                    return theme;
182            }
183    
184            public List<Theme> getThemes(long companyId) {
185                    Map<String, Theme> themes = _getThemes(companyId);
186    
187                    List<Theme> themesList = ListUtil.fromMapValues(themes);
188    
189                    return ListUtil.sort(themesList);
190            }
191    
192            public List<Theme> getThemes(
193                            long companyId, long groupId, long userId, boolean wapTheme)
194                    throws SystemException {
195    
196                    List<Theme> themes = getThemes(companyId);
197    
198                    themes = PluginUtil.restrictPlugins(themes, companyId, userId);
199    
200                    Iterator<Theme> itr = themes.iterator();
201    
202                    while (itr.hasNext()) {
203                            Theme theme = itr.next();
204    
205                            if (theme.getThemeId().equals("controlpanel") ||
206                                    !theme.isGroupAvailable(groupId) ||
207                                    (theme.isWapTheme() != wapTheme)) {
208    
209                                    itr.remove();
210                            }
211                    }
212    
213                    return themes;
214            }
215    
216            public List<Theme> getWARThemes() {
217                    List<Theme> themes = ListUtil.fromMapValues(_themes);
218    
219                    Iterator<Theme> itr = themes.iterator();
220    
221                    while (itr.hasNext()) {
222                            Theme theme = itr.next();
223    
224                            if (!theme.isWARFile()) {
225                                    itr.remove();
226                            }
227                    }
228    
229                    return themes;
230            }
231    
232            public List<String> init(
233                    ServletContext servletContext, String themesPath,
234                    boolean loadFromServletContext, String[] xmls,
235                    PluginPackage pluginPackage) {
236    
237                    return init(
238                            null, servletContext, themesPath, loadFromServletContext, xmls,
239                            pluginPackage);
240            }
241    
242            public List<String> init(
243                    String servletContextName, ServletContext servletContext,
244                    String themesPath, boolean loadFromServletContext, String[] xmls,
245                    PluginPackage pluginPackage) {
246    
247                    List<String> themeIdsList = new ArrayList<String>();
248    
249                    try {
250                            for (String xml : xmls) {
251                                    Set<String> themeIds = _readThemes(
252                                            servletContextName, servletContext, themesPath,
253                                            loadFromServletContext, xml, pluginPackage);
254    
255                                    for (String themeId : themeIds) {
256                                            if (!themeIdsList.contains(themeId)) {
257                                                    themeIdsList.add(themeId);
258                                            }
259                                    }
260                            }
261                    }
262                    catch (Exception e) {
263                            e.printStackTrace();
264                    }
265    
266                    _themesPool.clear();
267    
268                    return themeIdsList;
269            }
270    
271            public void uninstallThemes(List<String> themeIds) {
272                    for (int i = 0; i < themeIds.size(); i++) {
273                            String themeId = themeIds.get(i);
274    
275                            _themes.remove(themeId);
276    
277                            layoutTemplateLocalService.uninstallLayoutTemplates(themeId);
278                    }
279    
280                    _themesPool.clear();
281            }
282    
283            private List<ThemeCompanyId> _getCompanyLimitExcludes(Element element) {
284                    List<ThemeCompanyId> includes = new ArrayList<ThemeCompanyId>();
285    
286                    if (element == null) {
287                            return includes;
288                    }
289    
290                    List<Element> companyIdsElements = element.elements("company-id");
291    
292                    for (int i = 0; i < companyIdsElements.size(); i++) {
293                            Element companyIdElement = companyIdsElements.get(i);
294    
295                            String name = companyIdElement.attributeValue("name");
296                            String pattern = companyIdElement.attributeValue("pattern");
297    
298                            ThemeCompanyId themeCompanyId = null;
299    
300                            if (Validator.isNotNull(name)) {
301                                    themeCompanyId = new ThemeCompanyId(name, false);
302                            }
303                            else if (Validator.isNotNull(pattern)) {
304                                    themeCompanyId = new ThemeCompanyId(pattern, true);
305                            }
306    
307                            if (themeCompanyId != null) {
308                                    includes.add(themeCompanyId);
309                            }
310                    }
311    
312                    return includes;
313            }
314    
315            private List<ThemeCompanyId> _getCompanyLimitIncludes(Element element) {
316                    return _getCompanyLimitExcludes(element);
317            }
318    
319            private List<ThemeGroupId> _getGroupLimitExcludes(Element element) {
320                    List<ThemeGroupId> includes = new ArrayList<ThemeGroupId>();
321    
322                    if (element == null) {
323                            return includes;
324                    }
325    
326                    List<Element> groupIdsElements = element.elements("group-id");
327    
328                    for (int i = 0; i < groupIdsElements.size(); i++) {
329                            Element groupIdElement = groupIdsElements.get(i);
330    
331                            String name = groupIdElement.attributeValue("name");
332                            String pattern = groupIdElement.attributeValue("pattern");
333    
334                            ThemeGroupId themeGroupId = null;
335    
336                            if (Validator.isNotNull(name)) {
337                                    themeGroupId = new ThemeGroupId(name, false);
338                            }
339                            else if (Validator.isNotNull(pattern)) {
340                                    themeGroupId = new ThemeGroupId(pattern, true);
341                            }
342    
343                            if (themeGroupId != null) {
344                                    includes.add(themeGroupId);
345                            }
346                    }
347    
348                    return includes;
349            }
350    
351            private List<ThemeGroupId> _getGroupLimitIncludes(Element element) {
352                    return _getGroupLimitExcludes(element);
353            }
354    
355            private Map<String, Theme> _getThemes(long companyId) {
356                    Map<String, Theme> themes = _themesPool.get(companyId);
357    
358                    if (themes != null) {
359                            return themes;
360                    }
361    
362                    themes = new ConcurrentHashMap<String, Theme>();
363    
364                    for (Map.Entry<String, Theme> entry : _themes.entrySet()) {
365                            String themeId = entry.getKey();
366                            Theme theme = entry.getValue();
367    
368                            if (theme.isCompanyAvailable(companyId)) {
369                                    themes.put(themeId, theme);
370                            }
371                    }
372    
373                    _themesPool.put(companyId, themes);
374    
375                    return themes;
376            }
377    
378            private Version _getVersion(String version) {
379                    if (version.equals("${current-version}")) {
380                            version = ReleaseInfo.getVersion();
381                    }
382    
383                    return Version.getInstance(version);
384            }
385    
386            private void _readColorSchemes(
387                    Element themeElement, Map<String, ColorScheme> colorSchemes,
388                    ContextReplace themeContextReplace) {
389    
390                    List<Element> colorSchemeElements = themeElement.elements(
391                            "color-scheme");
392    
393                    for (Element colorSchemeElement : colorSchemeElements) {
394                            ContextReplace colorSchemeContextReplace =
395                                    (ContextReplace)themeContextReplace.clone();
396    
397                            String id = colorSchemeElement.attributeValue("id");
398    
399                            colorSchemeContextReplace.addValue("color-scheme-id", id);
400    
401                            ColorScheme colorSchemeModel = colorSchemes.get(id);
402    
403                            if (colorSchemeModel == null) {
404                                    colorSchemeModel = ColorSchemeFactoryUtil.getColorScheme(id);
405                            }
406    
407                            String name = GetterUtil.getString(
408                                    colorSchemeElement.attributeValue("name"),
409                                    colorSchemeModel.getName());
410    
411                            name = colorSchemeContextReplace.replace(name);
412    
413                            boolean defaultCs = GetterUtil.getBoolean(
414                                    colorSchemeElement.elementText("default-cs"),
415                                    colorSchemeModel.isDefaultCs());
416    
417                            String cssClass = GetterUtil.getString(
418                                    colorSchemeElement.elementText("css-class"),
419                                    colorSchemeModel.getCssClass());
420    
421                            cssClass = colorSchemeContextReplace.replace(cssClass);
422    
423                            colorSchemeContextReplace.addValue("css-class", cssClass);
424    
425                            String colorSchemeImagesPath = GetterUtil.getString(
426                                    colorSchemeElement.elementText("color-scheme-images-path"),
427                                    colorSchemeModel.getColorSchemeImagesPath());
428    
429                            colorSchemeImagesPath = colorSchemeContextReplace.replace(
430                                    colorSchemeImagesPath);
431    
432                            colorSchemeContextReplace.addValue(
433                                    "color-scheme-images-path", colorSchemeImagesPath);
434    
435                            colorSchemeModel.setName(name);
436                            colorSchemeModel.setDefaultCs(defaultCs);
437                            colorSchemeModel.setCssClass(cssClass);
438                            colorSchemeModel.setColorSchemeImagesPath(colorSchemeImagesPath);
439    
440                            colorSchemes.put(id, colorSchemeModel);
441                    }
442            }
443    
444            private Set<String> _readThemes(
445                            String servletContextName, ServletContext servletContext,
446                            String themesPath, boolean loadFromServletContext, String xml,
447                            PluginPackage pluginPackage)
448                    throws Exception {
449    
450                    Set<String> themeIds = new HashSet<String>();
451    
452                    if (xml == null) {
453                            return themeIds;
454                    }
455    
456                    Document document = SAXReaderUtil.read(xml, true);
457    
458                    Element rootElement = document.getRootElement();
459    
460                    Version portalVersion = _getVersion(ReleaseInfo.getVersion());
461    
462                    boolean compatible = false;
463    
464                    Element compatibilityElement = rootElement.element("compatibility");
465    
466                    if (compatibilityElement != null) {
467                            List<Element> versionElements = compatibilityElement.elements(
468                                    "version");
469    
470                            for (Element versionElement : versionElements) {
471                                    Version version = _getVersion(versionElement.getTextTrim());
472    
473                                    if (version.includes(portalVersion)) {
474                                            compatible = true;
475    
476                                            break;
477                                    }
478                            }
479                    }
480    
481                    if (!compatible) {
482                            _log.error(
483                                    "Themes in this WAR are not compatible with " +
484                                            ReleaseInfo.getServerInfo());
485    
486                            return themeIds;
487                    }
488    
489                    ThemeCompanyLimit companyLimit = null;
490    
491                    Element companyLimitElement = rootElement.element("company-limit");
492    
493                    if (companyLimitElement != null) {
494                            companyLimit = new ThemeCompanyLimit();
495    
496                            Element companyIncludesElement = companyLimitElement.element(
497                                    "company-includes");
498    
499                            if (companyIncludesElement != null) {
500                                    companyLimit.setIncludes(
501                                            _getCompanyLimitIncludes(companyIncludesElement));
502                            }
503    
504                            Element companyExcludesElement = companyLimitElement.element(
505                                    "company-excludes");
506    
507                            if (companyExcludesElement != null) {
508                                    companyLimit.setExcludes(
509                                            _getCompanyLimitExcludes(companyExcludesElement));
510                            }
511                    }
512    
513                    ThemeGroupLimit groupLimit = null;
514    
515                    Element groupLimitElement = rootElement.element("group-limit");
516    
517                    if (groupLimitElement != null) {
518                            groupLimit = new ThemeGroupLimit();
519    
520                            Element groupIncludesElement = groupLimitElement.element(
521                                    "group-includes");
522    
523                            if (groupIncludesElement != null) {
524                                    groupLimit.setIncludes(
525                                            _getGroupLimitIncludes(groupIncludesElement));
526                            }
527    
528                            Element groupExcludesElement = groupLimitElement.element(
529                                    "group-excludes");
530    
531                            if (groupExcludesElement != null) {
532                                    groupLimit.setExcludes(
533                                            _getGroupLimitExcludes(groupExcludesElement));
534                            }
535                    }
536    
537                    long timestamp = ServletContextUtil.getLastModified(servletContext);
538    
539                    List<Element> themeElements = rootElement.elements("theme");
540    
541                    for (Element themeElement : themeElements) {
542                            ContextReplace themeContextReplace = new ContextReplace();
543    
544                            themeContextReplace.addValue("themes-path", themesPath);
545    
546                            String themeId = themeElement.attributeValue("id");
547    
548                            if (servletContextName != null) {
549                                    themeId =
550                                            themeId + PortletConstants.WAR_SEPARATOR +
551                                                    servletContextName;
552                            }
553    
554                            themeId = PortalUtil.getJsSafePortletId(themeId);
555    
556                            themeContextReplace.addValue("theme-id", themeId);
557    
558                            themeIds.add(themeId);
559    
560                            Theme theme = _themes.get(themeId);
561    
562                            if (theme == null) {
563                                    theme = ThemeFactoryUtil.getTheme(themeId);
564                            }
565    
566                            theme.setTimestamp(timestamp);
567    
568                            PluginSetting pluginSetting =
569                                    pluginSettingLocalService.getDefaultPluginSetting();
570    
571                            theme.setPluginPackage(pluginPackage);
572                            theme.setDefaultPluginSetting(pluginSetting);
573    
574                            theme.setThemeCompanyLimit(companyLimit);
575                            theme.setThemeGroupLimit(groupLimit);
576    
577                            if (servletContextName != null) {
578                                    theme.setServletContextName(servletContextName);
579                            }
580    
581                            theme.setLoadFromServletContext(loadFromServletContext);
582    
583                            String name = GetterUtil.getString(
584                                    themeElement.attributeValue("name"), theme.getName());
585    
586                            String rootPath = GetterUtil.getString(
587                                    themeElement.elementText("root-path"), theme.getRootPath());
588    
589                            rootPath = themeContextReplace.replace(rootPath);
590    
591                            themeContextReplace.addValue("root-path", rootPath);
592    
593                            String templatesPath = GetterUtil.getString(
594                                    themeElement.elementText("templates-path"),
595                                    theme.getTemplatesPath());
596    
597                            templatesPath = themeContextReplace.replace(templatesPath);
598                            templatesPath = StringUtil.safePath(templatesPath);
599    
600                            themeContextReplace.addValue("templates-path", templatesPath);
601    
602                            String cssPath = GetterUtil.getString(
603                                    themeElement.elementText("css-path"), theme.getCssPath());
604    
605                            cssPath = themeContextReplace.replace(cssPath);
606                            cssPath = StringUtil.safePath(cssPath);
607    
608                            themeContextReplace.addValue("css-path", cssPath);
609    
610                            String imagesPath = GetterUtil.getString(
611                                    themeElement.elementText("images-path"), theme.getImagesPath());
612    
613                            imagesPath = themeContextReplace.replace(imagesPath);
614                            imagesPath = StringUtil.safePath(imagesPath);
615    
616                            themeContextReplace.addValue("images-path", imagesPath);
617    
618                            String javaScriptPath = GetterUtil.getString(
619                                    themeElement.elementText("javascript-path"),
620                                    theme.getJavaScriptPath());
621    
622                            javaScriptPath = themeContextReplace.replace(javaScriptPath);
623                            javaScriptPath = StringUtil.safePath(javaScriptPath);
624    
625                            themeContextReplace.addValue("javascript-path", javaScriptPath);
626    
627                            String virtualPath = GetterUtil.getString(
628                                    themeElement.elementText("virtual-path"),
629                                    theme.getVirtualPath());
630    
631                            String templateExtension = GetterUtil.getString(
632                                    themeElement.elementText("template-extension"),
633                                    theme.getTemplateExtension());
634    
635                            theme.setName(name);
636                            theme.setRootPath(rootPath);
637                            theme.setTemplatesPath(templatesPath);
638                            theme.setCssPath(cssPath);
639                            theme.setImagesPath(imagesPath);
640                            theme.setJavaScriptPath(javaScriptPath);
641                            theme.setVirtualPath(virtualPath);
642                            theme.setTemplateExtension(templateExtension);
643    
644                            Element settingsElement = themeElement.element("settings");
645    
646                            if (settingsElement != null) {
647                                    List<Element> settingElements = settingsElement.elements(
648                                            "setting");
649    
650                                    for (Element settingElement : settingElements) {
651                                            boolean configurable = GetterUtil.getBoolean(
652                                                    settingElement.attributeValue("configurable"));
653                                            String key = settingElement.attributeValue("key");
654                                            String[] options = StringUtil.split(
655                                                    settingElement.attributeValue("options"));
656                                            String type = settingElement.attributeValue("type", "text");
657                                            String value = settingElement.attributeValue(
658                                                    "value", StringPool.BLANK);
659                                            String script = settingElement.getTextTrim();
660    
661                                            theme.addSetting(
662                                                    key, value, configurable, type, options, script);
663                                    }
664                            }
665    
666                            theme.setWapTheme(
667                                    GetterUtil.getBoolean(
668                                            themeElement.elementText("wap-theme"), theme.isWapTheme()));
669    
670                            Element rolesElement = themeElement.element("roles");
671    
672                            if (rolesElement != null) {
673                                    List<Element> roleNameElements = rolesElement.elements(
674                                            "role-name");
675    
676                                    for (Element roleNameElement : roleNameElements) {
677                                            pluginSetting.addRole(roleNameElement.getText());
678                                    }
679                            }
680    
681                            _readColorSchemes(
682                                    themeElement, theme.getColorSchemesMap(), themeContextReplace);
683                            _readColorSchemes(
684                                    themeElement, theme.getColorSchemesMap(), themeContextReplace);
685    
686                            Element layoutTemplatesElement = themeElement.element(
687                                    "layout-templates");
688    
689                            if (layoutTemplatesElement != null) {
690                                    Element standardElement = layoutTemplatesElement.element(
691                                            "standard");
692    
693                                    if (standardElement != null) {
694                                            layoutTemplateLocalService.readLayoutTemplate(
695                                                    servletContextName, servletContext, null,
696                                                    standardElement, true, themeId, pluginPackage);
697                                    }
698    
699                                    Element customElement = layoutTemplatesElement.element(
700                                            "custom");
701    
702                                    if (customElement != null) {
703                                            layoutTemplateLocalService.readLayoutTemplate(
704                                                    servletContextName, servletContext, null, customElement,
705                                                    false, themeId, pluginPackage);
706                                    }
707                            }
708    
709                            if (!theme.isWapTheme()) {
710                                    _setSpriteImages(servletContext, theme, imagesPath);
711                            }
712    
713                            if (!_themes.containsKey(themeId)) {
714                                    _themes.put(themeId, theme);
715                            }
716                    }
717    
718                    return themeIds;
719            }
720    
721            private void _setSpriteImages(
722                            ServletContext servletContext, Theme theme, String resourcePath)
723                    throws Exception {
724    
725                    if (!resourcePath.startsWith(StringPool.SLASH)) {
726                            resourcePath = StringPool.SLASH.concat(resourcePath);
727                    }
728    
729                    Set<String> resourcePaths = servletContext.getResourcePaths(
730                            resourcePath);
731    
732                    if ((resourcePaths == null) || resourcePaths.isEmpty()) {
733                            return;
734                    }
735    
736                    List<URL> imageURLs = new ArrayList<URL>(resourcePaths.size());
737    
738                    for (String curResourcePath : resourcePaths) {
739                            if (curResourcePath.endsWith(StringPool.SLASH)) {
740                                    _setSpriteImages(servletContext, theme, curResourcePath);
741                            }
742                            else if (curResourcePath.endsWith(".png")) {
743                                    URL imageURL = servletContext.getResource(curResourcePath);
744    
745                                    if (imageURL != null) {
746                                            imageURLs.add(imageURL);
747                                    }
748                                    else {
749                                            _log.error(
750                                                    "Resource URL for " + curResourcePath + " is null");
751                                    }
752                            }
753                    }
754    
755                    String spriteRootDirName = PropsValues.SPRITE_ROOT_DIR;
756                    String spriteFileName = resourcePath.concat(
757                            PropsValues.SPRITE_FILE_NAME);
758                    String spritePropertiesFileName = resourcePath.concat(
759                            PropsValues.SPRITE_PROPERTIES_FILE_NAME);
760                    String rootPath = ServletContextUtil.getRootPath(servletContext);
761    
762                    Properties spriteProperties = SpriteProcessorUtil.generate(
763                            servletContext, imageURLs, spriteRootDirName, spriteFileName,
764                            spritePropertiesFileName, rootPath, 16, 16, 10240);
765    
766                    if (spriteProperties == null) {
767                            return;
768                    }
769    
770                    String contextPath = ContextPathUtil.getContextPath(servletContext);
771    
772                    spriteFileName = contextPath.concat(SpriteProcessor.PATH).concat(
773                            spriteFileName);
774    
775                    theme.setSpriteImages(spriteFileName, spriteProperties);
776            }
777    
778            private static Log _log = LogFactoryUtil.getLog(
779                    ThemeLocalServiceImpl.class);
780    
781            private static Map<String, Theme> _themes =
782                    new ConcurrentHashMap<String, Theme>();
783            private static Map<Long, Map<String, Theme>> _themesPool =
784                    new ConcurrentHashMap<Long, Map<String, Theme>>();
785    
786    }