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