001    /**
002     * Copyright (c) 2000-2012 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.ContextPathUtil;
026    import com.liferay.portal.kernel.util.GetterUtil;
027    import com.liferay.portal.kernel.util.ListUtil;
028    import com.liferay.portal.kernel.util.ReleaseInfo;
029    import com.liferay.portal.kernel.util.StringPool;
030    import com.liferay.portal.kernel.util.StringUtil;
031    import com.liferay.portal.kernel.util.Validator;
032    import com.liferay.portal.kernel.xml.Document;
033    import com.liferay.portal.kernel.xml.Element;
034    import com.liferay.portal.kernel.xml.SAXReaderUtil;
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.model.impl.ColorSchemeImpl;
040    import com.liferay.portal.model.impl.ThemeImpl;
041    import com.liferay.portal.plugin.PluginUtil;
042    import com.liferay.portal.service.base.ThemeLocalServiceBaseImpl;
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.List;
057    import java.util.Map;
058    import java.util.Properties;
059    import java.util.Set;
060    import java.util.concurrent.ConcurrentHashMap;
061    
062    import javax.servlet.ServletContext;
063    
064    /**
065     * @author Brian Wing Shun Chan
066     * @author Jorge Ferrer
067     * @author Raymond Augé
068     */
069    public class ThemeLocalServiceImpl extends ThemeLocalServiceBaseImpl {
070    
071            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            public Theme fetchTheme(long companyId, String themeId) {
088                    themeId = GetterUtil.getString(themeId);
089    
090                    Map<String, Theme> themes = _getThemes(companyId);
091    
092                    return themes.get(themeId);
093            }
094    
095            public ColorScheme getColorScheme(
096                            long companyId, String themeId, String colorSchemeId,
097                            boolean wapTheme)
098                    throws SystemException {
099    
100                    colorSchemeId = GetterUtil.getString(colorSchemeId);
101    
102                    Theme theme = getTheme(companyId, themeId, wapTheme);
103    
104                    Map<String, ColorScheme> colorSchemesMap = theme.getColorSchemesMap();
105    
106                    ColorScheme colorScheme = colorSchemesMap.get(colorSchemeId);
107    
108                    if (colorScheme == null) {
109                            List<ColorScheme> colorSchemes = theme.getColorSchemes();
110    
111                            if (colorSchemes.size() > 0) {
112                                    for (int i = (colorSchemes.size() - 1); i >= 0; i--) {
113                                            colorScheme = colorSchemes.get(i);
114    
115                                            if (colorScheme.isDefaultCs()) {
116                                                    break;
117                                            }
118                                    }
119                            }
120                    }
121    
122                    if (colorScheme == null) {
123                            if (wapTheme) {
124                                    colorSchemeId = ColorSchemeImpl.getDefaultWapColorSchemeId();
125                            }
126                            else {
127                                    colorSchemeId =
128                                            ColorSchemeImpl.getDefaultRegularColorSchemeId();
129                            }
130                    }
131    
132                    if (colorScheme == null) {
133                            colorScheme = ColorSchemeImpl.getNullColorScheme();
134                    }
135    
136                    return colorScheme;
137            }
138    
139            public Theme getTheme(long companyId, String themeId, boolean wapTheme)
140                    throws SystemException {
141    
142                    themeId = GetterUtil.getString(themeId);
143    
144                    Map<String, Theme> themes = _getThemes(companyId);
145    
146                    Theme theme = themes.get(themeId);
147    
148                    if (theme == null) {
149                            if (_log.isWarnEnabled()) {
150                                    _log.warn(
151                                            "No theme found for specified theme id " + themeId +
152                                                    ". Returning the default theme.");
153                            }
154    
155                            if (wapTheme) {
156                                    themeId = ThemeImpl.getDefaultWapThemeId(companyId);
157                            }
158                            else {
159                                    themeId = ThemeImpl.getDefaultRegularThemeId(companyId);
160                            }
161    
162                            theme = _themes.get(themeId);
163                    }
164    
165                    if (theme == null) {
166                            if (_themes.isEmpty()) {
167                                    if (_log.isDebugEnabled()) {
168                                            _log.debug("No themes are installed");
169                                    }
170    
171                                    return null;
172                            }
173    
174                            if (!themeId.contains(PortletConstants.WAR_SEPARATOR)) {
175                                    _log.error(
176                                            "No theme found for default theme id " + themeId +
177                                                    ". Returning a random theme.");
178                            }
179    
180                            for (Map.Entry<String, Theme> entry : _themes.entrySet()) {
181                                    theme = entry.getValue();
182                            }
183                    }
184    
185                    return theme;
186            }
187    
188            public List<Theme> getThemes(long companyId) {
189                    Map<String, Theme> themes = _getThemes(companyId);
190    
191                    List<Theme> themesList = ListUtil.fromMapValues(themes);
192    
193                    return ListUtil.sort(themesList);
194            }
195    
196            public List<Theme> getThemes(
197                            long companyId, long groupId, long userId, boolean wapTheme)
198                    throws SystemException {
199    
200                    List<Theme> themes = getThemes(companyId);
201    
202                    themes = PluginUtil.restrictPlugins(themes, companyId, userId);
203    
204                    Iterator<Theme> itr = themes.iterator();
205    
206                    while (itr.hasNext()) {
207                            Theme theme = itr.next();
208    
209                            if (theme.getThemeId().equals("controlpanel") ||
210                                    !theme.isGroupAvailable(groupId) ||
211                                    (theme.isWapTheme() != wapTheme)) {
212    
213                                    itr.remove();
214                            }
215                    }
216    
217                    return themes;
218            }
219    
220            public List<Theme> getWARThemes() {
221                    List<Theme> themes = ListUtil.fromMapValues(_themes);
222    
223                    Iterator<Theme> itr = themes.iterator();
224    
225                    while (itr.hasNext()) {
226                            Theme theme = itr.next();
227    
228                            if (!theme.isWARFile()) {
229                                    itr.remove();
230                            }
231                    }
232    
233                    return themes;
234            }
235    
236            public List<String> init(
237                    ServletContext servletContext, String themesPath,
238                    boolean loadFromServletContext, String[] xmls,
239                    PluginPackage pluginPackage) {
240    
241                    return init(
242                            null, servletContext, themesPath, loadFromServletContext, xmls,
243                            pluginPackage);
244            }
245    
246            public List<String> init(
247                    String servletContextName, ServletContext servletContext,
248                    String themesPath, boolean loadFromServletContext, String[] xmls,
249                    PluginPackage pluginPackage) {
250    
251                    List<String> themeIdsList = new ArrayList<String>();
252    
253                    try {
254                            for (String xml : xmls) {
255                                    Set<String> themeIds = _readThemes(
256                                            servletContextName, servletContext, themesPath,
257                                            loadFromServletContext, xml, pluginPackage);
258    
259                                    for (String themeId : themeIds) {
260                                            if (!themeIdsList.contains(themeId)) {
261                                                    themeIdsList.add(themeId);
262                                            }
263                                    }
264                            }
265                    }
266                    catch (Exception e) {
267                            e.printStackTrace();
268                    }
269    
270                    _themesPool.clear();
271    
272                    return themeIdsList;
273            }
274    
275            public void uninstallThemes(List<String> themeIds) {
276                    for (int i = 0; i < themeIds.size(); i++) {
277                            String themeId = themeIds.get(i);
278    
279                            _themes.remove(themeId);
280    
281                            layoutTemplateLocalService.uninstallLayoutTemplates(themeId);
282                    }
283    
284                    _themesPool.clear();
285            }
286    
287            private List<ThemeCompanyId> _getCompanyLimitExcludes(Element element) {
288                    List<ThemeCompanyId> includes = new ArrayList<ThemeCompanyId>();
289    
290                    if (element == null) {
291                            return includes;
292                    }
293    
294                    List<Element> companyIdsElements = element.elements("company-id");
295    
296                    for (int i = 0; i < companyIdsElements.size(); i++) {
297                            Element companyIdElement = companyIdsElements.get(i);
298    
299                            String name = companyIdElement.attributeValue("name");
300                            String pattern = companyIdElement.attributeValue("pattern");
301    
302                            ThemeCompanyId themeCompanyId = null;
303    
304                            if (Validator.isNotNull(name)) {
305                                    themeCompanyId = new ThemeCompanyId(name, false);
306                            }
307                            else if (Validator.isNotNull(pattern)) {
308                                    themeCompanyId = new ThemeCompanyId(pattern, true);
309                            }
310    
311                            if (themeCompanyId != null) {
312                                    includes.add(themeCompanyId);
313                            }
314                    }
315    
316                    return includes;
317            }
318    
319            private List<ThemeCompanyId> _getCompanyLimitIncludes(Element element) {
320                    return _getCompanyLimitExcludes(element);
321            }
322    
323            private List<ThemeGroupId> _getGroupLimitExcludes(Element element) {
324                    List<ThemeGroupId> includes = new ArrayList<ThemeGroupId>();
325    
326                    if (element == null) {
327                            return includes;
328                    }
329    
330                    List<Element> groupIdsElements = element.elements("group-id");
331    
332                    for (int i = 0; i < groupIdsElements.size(); i++) {
333                            Element groupIdElement = groupIdsElements.get(i);
334    
335                            String name = groupIdElement.attributeValue("name");
336                            String pattern = groupIdElement.attributeValue("pattern");
337    
338                            ThemeGroupId themeGroupId = null;
339    
340                            if (Validator.isNotNull(name)) {
341                                    themeGroupId = new ThemeGroupId(name, false);
342                            }
343                            else if (Validator.isNotNull(pattern)) {
344                                    themeGroupId = new ThemeGroupId(pattern, true);
345                            }
346    
347                            if (themeGroupId != null) {
348                                    includes.add(themeGroupId);
349                            }
350                    }
351    
352                    return includes;
353            }
354    
355            private List<ThemeGroupId> _getGroupLimitIncludes(Element element) {
356                    return _getGroupLimitExcludes(element);
357            }
358    
359            private Map<String, Theme> _getThemes(long companyId) {
360                    Map<String, Theme> themes = _themesPool.get(companyId);
361    
362                    if (themes != null) {
363                            return themes;
364                    }
365    
366                    themes = new ConcurrentHashMap<String, Theme>();
367    
368                    for (Map.Entry<String, Theme> entry : _themes.entrySet()) {
369                            String themeId = entry.getKey();
370                            Theme theme = entry.getValue();
371    
372                            if (theme.isCompanyAvailable(companyId)) {
373                                    themes.put(themeId, theme);
374                            }
375                    }
376    
377                    _themesPool.put(companyId, themes);
378    
379                    return themes;
380            }
381    
382            private Version _getVersion(String version) {
383                    if (version.equals("${current-version}")) {
384                            version = ReleaseInfo.getVersion();
385                    }
386    
387                    return Version.getInstance(version);
388            }
389    
390            private void _readColorSchemes(
391                    Element themeElement, Map<String, ColorScheme> colorSchemes,
392                    ContextReplace themeContextReplace) {
393    
394                    List<Element> colorSchemeElements = themeElement.elements(
395                            "color-scheme");
396    
397                    for (Element colorSchemeElement : colorSchemeElements) {
398                            ContextReplace colorSchemeContextReplace =
399                                    (ContextReplace)themeContextReplace.clone();
400    
401                            String id = colorSchemeElement.attributeValue("id");
402    
403                            colorSchemeContextReplace.addValue("color-scheme-id", id);
404    
405                            ColorScheme colorSchemeModel = colorSchemes.get(id);
406    
407                            if (colorSchemeModel == null) {
408                                    colorSchemeModel = new ColorSchemeImpl(id);
409                            }
410    
411                            String name = GetterUtil.getString(
412                                    colorSchemeElement.attributeValue("name"),
413                                    colorSchemeModel.getName());
414    
415                            name = colorSchemeContextReplace.replace(name);
416    
417                            boolean defaultCs = GetterUtil.getBoolean(
418                                    colorSchemeElement.elementText("default-cs"),
419                                    colorSchemeModel.isDefaultCs());
420    
421                            String cssClass = GetterUtil.getString(
422                                    colorSchemeElement.elementText("css-class"),
423                                    colorSchemeModel.getCssClass());
424    
425                            cssClass = colorSchemeContextReplace.replace(cssClass);
426    
427                            colorSchemeContextReplace.addValue("css-class", cssClass);
428    
429                            String colorSchemeImagesPath = GetterUtil.getString(
430                                    colorSchemeElement.elementText("color-scheme-images-path"),
431                                    colorSchemeModel.getColorSchemeImagesPath());
432    
433                            colorSchemeImagesPath = colorSchemeContextReplace.replace(
434                                    colorSchemeImagesPath);
435    
436                            colorSchemeContextReplace.addValue(
437                                    "color-scheme-images-path", colorSchemeImagesPath);
438    
439                            colorSchemeModel.setName(name);
440                            colorSchemeModel.setDefaultCs(defaultCs);
441                            colorSchemeModel.setCssClass(cssClass);
442                            colorSchemeModel.setColorSchemeImagesPath(colorSchemeImagesPath);
443    
444                            colorSchemes.put(id, colorSchemeModel);
445                    }
446            }
447    
448            private Set<String> _readThemes(
449                            String servletContextName, ServletContext servletContext,
450                            String themesPath, boolean loadFromServletContext, String xml,
451                            PluginPackage pluginPackage)
452                    throws Exception {
453    
454                    Set<String> themeIds = new HashSet<String>();
455    
456                    if (xml == null) {
457                            return themeIds;
458                    }
459    
460                    Document document = SAXReaderUtil.read(xml, true);
461    
462                    Element rootElement = document.getRootElement();
463    
464                    Version portalVersion = _getVersion(ReleaseInfo.getVersion());
465    
466                    boolean compatible = false;
467    
468                    Element compatibilityElement = rootElement.element("compatibility");
469    
470                    if (compatibilityElement != null) {
471                            List<Element> versionElements = compatibilityElement.elements(
472                                    "version");
473    
474                            for (Element versionElement : versionElements) {
475                                    Version version = _getVersion(versionElement.getTextTrim());
476    
477                                    if (version.includes(portalVersion)) {
478                                            compatible = true;
479    
480                                            break;
481                                    }
482                            }
483                    }
484    
485                    if (!compatible) {
486                            _log.error(
487                                    "Themes in this WAR are not compatible with " +
488                                            ReleaseInfo.getServerInfo());
489    
490                            return themeIds;
491                    }
492    
493                    ThemeCompanyLimit companyLimit = null;
494    
495                    Element companyLimitElement = rootElement.element("company-limit");
496    
497                    if (companyLimitElement != null) {
498                            companyLimit = new ThemeCompanyLimit();
499    
500                            Element companyIncludesElement = companyLimitElement.element(
501                                    "company-includes");
502    
503                            if (companyIncludesElement != null) {
504                                    companyLimit.setIncludes(
505                                            _getCompanyLimitIncludes(companyIncludesElement));
506                            }
507    
508                            Element companyExcludesElement = companyLimitElement.element(
509                                    "company-excludes");
510    
511                            if (companyExcludesElement != null) {
512                                    companyLimit.setExcludes(
513                                            _getCompanyLimitExcludes(companyExcludesElement));
514                            }
515                    }
516    
517                    ThemeGroupLimit groupLimit = null;
518    
519                    Element groupLimitElement = rootElement.element("group-limit");
520    
521                    if (groupLimitElement != null) {
522                            groupLimit = new ThemeGroupLimit();
523    
524                            Element groupIncludesElement = groupLimitElement.element(
525                                    "group-includes");
526    
527                            if (groupIncludesElement != null) {
528                                    groupLimit.setIncludes(
529                                            _getGroupLimitIncludes(groupIncludesElement));
530                            }
531    
532                            Element groupExcludesElement = groupLimitElement.element(
533                                    "group-excludes");
534    
535                            if (groupExcludesElement != null) {
536                                    groupLimit.setExcludes(
537                                            _getGroupLimitExcludes(groupExcludesElement));
538                            }
539                    }
540    
541                    long timestamp = ServletContextUtil.getLastModified(servletContext);
542    
543                    List<Element> themeElements = rootElement.elements("theme");
544    
545                    for (Element themeElement : themeElements) {
546                            ContextReplace themeContextReplace = new ContextReplace();
547    
548                            themeContextReplace.addValue("themes-path", themesPath);
549    
550                            String themeId = themeElement.attributeValue("id");
551    
552                            if (servletContextName != null) {
553                                    themeId =
554                                            themeId + PortletConstants.WAR_SEPARATOR +
555                                                    servletContextName;
556                            }
557    
558                            themeId = PortalUtil.getJsSafePortletId(themeId);
559    
560                            themeContextReplace.addValue("theme-id", themeId);
561    
562                            themeIds.add(themeId);
563    
564                            Theme theme = _themes.get(themeId);
565    
566                            if (theme == null) {
567                                    theme = new ThemeImpl(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    
722                    return themeIds;
723            }
724    
725            private void _setSpriteImages(
726                            ServletContext servletContext, Theme theme, String resourcePath)
727                    throws Exception {
728    
729                    if (!resourcePath.startsWith(StringPool.SLASH)) {
730                            resourcePath = StringPool.SLASH.concat(resourcePath);
731                    }
732    
733                    Set<String> resourcePaths = servletContext.getResourcePaths(
734                            resourcePath);
735    
736                    if ((resourcePaths == null) || resourcePaths.isEmpty()) {
737                            return;
738                    }
739    
740                    List<URL> imageURLs = new ArrayList<URL>(resourcePaths.size());
741    
742                    for (String curResourcePath : resourcePaths) {
743                            if (curResourcePath.endsWith(StringPool.SLASH)) {
744                                    _setSpriteImages(servletContext, theme, curResourcePath);
745                            }
746                            else if (curResourcePath.endsWith(".png")) {
747                                    URL imageURL = servletContext.getResource(curResourcePath);
748    
749                                    if (imageURL != null) {
750                                            imageURLs.add(imageURL);
751                                    }
752                                    else {
753                                            _log.error(
754                                                    "Resource URL for " + curResourcePath + " is null");
755                                    }
756                            }
757                    }
758    
759                    String spriteRootDirName = PropsValues.SPRITE_ROOT_DIR;
760                    String spriteFileName = resourcePath.concat(
761                            PropsValues.SPRITE_FILE_NAME);
762                    String spritePropertiesFileName = resourcePath.concat(
763                            PropsValues.SPRITE_PROPERTIES_FILE_NAME);
764                    String rootPath = ServletContextUtil.getRootPath(servletContext);
765    
766                    Properties spriteProperties = SpriteProcessorUtil.generate(
767                            servletContext, imageURLs, spriteRootDirName, spriteFileName,
768                            spritePropertiesFileName, rootPath, 16, 16, 10240);
769    
770                    if (spriteProperties == null) {
771                            return;
772                    }
773    
774                    String contextPath = ContextPathUtil.getContextPath(servletContext);
775    
776                    spriteFileName = contextPath.concat(SpriteProcessor.PATH).concat(
777                            spriteFileName);
778    
779                    theme.setSpriteImages(spriteFileName, spriteProperties);
780            }
781    
782            private static Log _log = LogFactoryUtil.getLog(
783                    ThemeLocalServiceImpl.class);
784    
785            private static Map<String, Theme> _themes =
786                    new ConcurrentHashMap<String, Theme>();
787            private static Map<Long, Map<String, Theme>> _themesPool =
788                    new ConcurrentHashMap<Long, Map<String, Theme>>();
789    
790    }