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