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