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