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