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.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.GetterUtil;
025    import com.liferay.portal.kernel.util.ListUtil;
026    import com.liferay.portal.kernel.util.ReleaseInfo;
027    import com.liferay.portal.kernel.util.ServerDetector;
028    import com.liferay.portal.kernel.util.StringPool;
029    import com.liferay.portal.kernel.util.StringUtil;
030    import com.liferay.portal.kernel.util.Validator;
031    import com.liferay.portal.kernel.xml.Document;
032    import com.liferay.portal.kernel.xml.Element;
033    import com.liferay.portal.kernel.xml.SAXReaderUtil;
034    import com.liferay.portal.model.ColorScheme;
035    import com.liferay.portal.model.PluginSetting;
036    import com.liferay.portal.model.PortletConstants;
037    import com.liferay.portal.model.Theme;
038    import com.liferay.portal.model.impl.ColorSchemeImpl;
039    import com.liferay.portal.model.impl.ThemeImpl;
040    import com.liferay.portal.plugin.PluginUtil;
041    import com.liferay.portal.service.base.ThemeLocalServiceBaseImpl;
042    import com.liferay.portal.theme.ThemeCompanyId;
043    import com.liferay.portal.theme.ThemeCompanyLimit;
044    import com.liferay.portal.theme.ThemeGroupId;
045    import com.liferay.portal.theme.ThemeGroupLimit;
046    import com.liferay.portal.util.PortalUtil;
047    import com.liferay.portal.util.PropsValues;
048    import com.liferay.util.ContextReplace;
049    
050    import java.io.File;
051    
052    import java.util.ArrayList;
053    import java.util.HashSet;
054    import java.util.Iterator;
055    import java.util.List;
056    import java.util.Map;
057    import java.util.Properties;
058    import java.util.Set;
059    import java.util.concurrent.ConcurrentHashMap;
060    
061    import javax.servlet.ServletContext;
062    
063    /**
064     * @author Brian Wing Shun Chan
065     * @author Jorge Ferrer
066     * @author Raymond Augé
067     */
068    public class ThemeLocalServiceImpl extends ThemeLocalServiceBaseImpl {
069    
070            public ColorScheme fetchColorScheme(
071                    long companyId, String themeId, String colorSchemeId) {
072    
073                    colorSchemeId = GetterUtil.getString(colorSchemeId);
074    
075                    Theme theme = fetchTheme(companyId, themeId);
076    
077                    if (theme == null) {
078                            return null;
079                    }
080    
081                    Map<String, ColorScheme> colorSchemesMap = theme.getColorSchemesMap();
082    
083                    return colorSchemesMap.get(colorSchemeId);
084            }
085    
086            public Theme fetchTheme(long companyId, String themeId) {
087                    themeId = GetterUtil.getString(themeId);
088    
089                    Map<String, Theme> themes = _getThemes(companyId);
090    
091                    return themes.get(themeId);
092            }
093    
094            public ColorScheme getColorScheme(
095                            long companyId, String themeId, String colorSchemeId,
096                            boolean wapTheme)
097                    throws SystemException {
098    
099                    colorSchemeId = GetterUtil.getString(colorSchemeId);
100    
101                    Theme theme = getTheme(companyId, themeId, wapTheme);
102    
103                    Map<String, ColorScheme> colorSchemesMap = theme.getColorSchemesMap();
104    
105                    ColorScheme colorScheme = colorSchemesMap.get(colorSchemeId);
106    
107                    if (colorScheme == null) {
108                            List<ColorScheme> colorSchemes = theme.getColorSchemes();
109    
110                            if (colorSchemes.size() > 0) {
111                                    for (int i = (colorSchemes.size() - 1); i >= 0; i--) {
112                                            colorScheme = colorSchemes.get(i);
113    
114                                            if (colorScheme.isDefaultCs()) {
115                                                    break;
116                                            }
117                                    }
118                            }
119                    }
120    
121                    if (colorScheme == null) {
122                            if (wapTheme) {
123                                    colorSchemeId = ColorSchemeImpl.getDefaultWapColorSchemeId();
124                            }
125                            else {
126                                    colorSchemeId =
127                                            ColorSchemeImpl.getDefaultRegularColorSchemeId();
128                            }
129                    }
130    
131                    if (colorScheme == null) {
132                            colorScheme = ColorSchemeImpl.getNullColorScheme();
133                    }
134    
135                    return colorScheme;
136            }
137    
138            public Theme getTheme(long companyId, String themeId, boolean wapTheme)
139                    throws SystemException {
140    
141                    themeId = GetterUtil.getString(themeId);
142    
143                    Map<String, Theme> themes = _getThemes(companyId);
144    
145                    Theme theme = themes.get(themeId);
146    
147                    if (theme == null) {
148                            if (_log.isWarnEnabled()) {
149                                    _log.warn(
150                                            "No theme found for specified theme id " + themeId +
151                                                    ". Returning the default theme.");
152                            }
153    
154                            if (wapTheme) {
155                                    themeId = ThemeImpl.getDefaultWapThemeId(companyId);
156                            }
157                            else {
158                                    themeId = ThemeImpl.getDefaultRegularThemeId(companyId);
159                            }
160    
161                            theme = _themes.get(themeId);
162                    }
163    
164                    if (theme == null) {
165                            if (_themes.isEmpty()) {
166                                    if (_log.isDebugEnabled()) {
167                                            _log.debug("No themes are installed");
168                                    }
169    
170                                    return null;
171                            }
172    
173                            _log.error(
174                                    "No theme found for default theme id " + themeId +
175                                            ". Returning a random theme.");
176    
177                            Iterator<Map.Entry<String, Theme>> itr =
178                                    _themes.entrySet().iterator();
179    
180                            while (itr.hasNext()) {
181                                    Map.Entry<String, Theme> entry = itr.next();
182    
183                                    theme = entry.getValue();
184                            }
185                    }
186    
187                    return theme;
188            }
189    
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            public List<Theme> getThemes(
199                            long companyId, long groupId, long userId, boolean wapTheme)
200                    throws SystemException {
201    
202                    List<Theme> themes = getThemes(companyId);
203    
204                    themes = PluginUtil.restrictPlugins(themes, companyId, userId);
205    
206                    Iterator<Theme> itr = themes.iterator();
207    
208                    while (itr.hasNext()) {
209                            Theme theme = itr.next();
210    
211                            if ((theme.getThemeId().equals("controlpanel")) ||
212                                    (!theme.isGroupAvailable(groupId)) ||
213                                    (theme.isWapTheme() != wapTheme)) {
214    
215                                    itr.remove();
216                            }
217                    }
218    
219                    return themes;
220            }
221    
222            public List<Theme> getWARThemes() {
223                    List<Theme> themes = ListUtil.fromMapValues(_themes);
224    
225                    Iterator<Theme> itr = themes.iterator();
226    
227                    while (itr.hasNext()) {
228                            Theme theme = itr.next();
229    
230                            if (!theme.isWARFile()) {
231                                    itr.remove();
232                            }
233                    }
234    
235                    return themes;
236            }
237    
238            public List<String> init(
239                    ServletContext servletContext, String themesPath,
240                    boolean loadFromServletContext, String[] xmls,
241                    PluginPackage pluginPackage) {
242    
243                    return init(
244                            null, servletContext, themesPath, loadFromServletContext, xmls,
245                            pluginPackage);
246            }
247    
248            public List<String> init(
249                    String servletContextName, ServletContext servletContext,
250                    String themesPath, boolean loadFromServletContext, String[] xmls,
251                    PluginPackage pluginPackage) {
252    
253                    List<String> themeIdsList = new ArrayList<String>();
254    
255                    try {
256                            for (String xml : xmls) {
257                                    Set<String> themeIds = _readThemes(
258                                            servletContextName, servletContext, themesPath,
259                                            loadFromServletContext, xml, pluginPackage);
260    
261                                    for (String themeId : themeIds) {
262                                            if (!themeIdsList.contains(themeId)) {
263                                                    themeIdsList.add(themeId);
264                                            }
265                                    }
266                            }
267                    }
268                    catch (Exception e) {
269                            e.printStackTrace();
270                    }
271    
272                    _themesPool.clear();
273    
274                    return themeIdsList;
275            }
276    
277            public void uninstallThemes(List<String> themeIds) {
278                    for (int i = 0; i < themeIds.size(); i++) {
279                            String themeId = themeIds.get(i);
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 = new ColorSchemeImpl(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<String> _readThemes(
451                            String servletContextName, ServletContext servletContext,
452                            String themesPath, boolean loadFromServletContext, String xml,
453                            PluginPackage pluginPackage)
454                    throws Exception {
455    
456                    Set<String> themeIds = new HashSet<String>();
457    
458                    if (xml == null) {
459                            return themeIds;
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 themeIds;
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                            themeIds.add(themeId);
565    
566                            Theme theme = _themes.get(themeId);
567    
568                            if (theme == null) {
569                                    theme = new ThemeImpl(themeId);
570                            }
571    
572                            theme.setTimestamp(timestamp);
573    
574                            PluginSetting pluginSetting =
575                                    pluginSettingLocalService.getDefaultPluginSetting();
576    
577                            theme.setPluginPackage(pluginPackage);
578                            theme.setDefaultPluginSetting(pluginSetting);
579    
580                            theme.setThemeCompanyLimit(companyLimit);
581                            theme.setThemeGroupLimit(groupLimit);
582    
583                            if (servletContextName != null) {
584                                    theme.setServletContextName(servletContextName);
585                            }
586    
587                            theme.setLoadFromServletContext(loadFromServletContext);
588    
589                            String name = GetterUtil.getString(
590                                    themeElement.attributeValue("name"), theme.getName());
591    
592                            String rootPath = GetterUtil.getString(
593                                    themeElement.elementText("root-path"), theme.getRootPath());
594    
595                            rootPath = themeContextReplace.replace(rootPath);
596    
597                            themeContextReplace.addValue("root-path", rootPath);
598    
599                            String templatesPath = GetterUtil.getString(
600                                    themeElement.elementText("templates-path"),
601                                    theme.getTemplatesPath());
602    
603                            templatesPath = themeContextReplace.replace(templatesPath);
604                            templatesPath = StringUtil.safePath(templatesPath);
605    
606                            themeContextReplace.addValue("templates-path", templatesPath);
607    
608                            String cssPath = GetterUtil.getString(
609                                    themeElement.elementText("css-path"), theme.getCssPath());
610    
611                            cssPath = themeContextReplace.replace(cssPath);
612                            cssPath = StringUtil.safePath(cssPath);
613    
614                            themeContextReplace.addValue("css-path", cssPath);
615    
616                            String imagesPath = GetterUtil.getString(
617                                    themeElement.elementText("images-path"), theme.getImagesPath());
618    
619                            imagesPath = themeContextReplace.replace(imagesPath);
620                            imagesPath = StringUtil.safePath(imagesPath);
621    
622                            themeContextReplace.addValue("images-path", imagesPath);
623    
624                            String javaScriptPath = GetterUtil.getString(
625                                    themeElement.elementText("javascript-path"),
626                                    theme.getJavaScriptPath());
627    
628                            javaScriptPath = themeContextReplace.replace(javaScriptPath);
629                            javaScriptPath = StringUtil.safePath(javaScriptPath);
630    
631                            themeContextReplace.addValue("javascript-path", javaScriptPath);
632    
633                            String virtualPath = GetterUtil.getString(
634                                    themeElement.elementText("virtual-path"),
635                                    theme.getVirtualPath());
636    
637                            String templateExtension = GetterUtil.getString(
638                                    themeElement.elementText("template-extension"),
639                                    theme.getTemplateExtension());
640    
641                            theme.setName(name);
642                            theme.setRootPath(rootPath);
643                            theme.setTemplatesPath(templatesPath);
644                            theme.setCssPath(cssPath);
645                            theme.setImagesPath(imagesPath);
646                            theme.setJavaScriptPath(javaScriptPath);
647                            theme.setVirtualPath(virtualPath);
648                            theme.setTemplateExtension(templateExtension);
649    
650                            Element settingsElement = themeElement.element("settings");
651    
652                            if (settingsElement != null) {
653                                    List<Element> settingElements = settingsElement.elements(
654                                            "setting");
655    
656                                    for (Element settingElement : settingElements) {
657                                            boolean configurable = GetterUtil.getBoolean(
658                                                    settingElement.attributeValue("configurable"));
659                                            String key = settingElement.attributeValue("key");
660                                            String[] options = StringUtil.split(
661                                                    settingElement.attributeValue("options"));
662                                            String type = settingElement.attributeValue("type");
663                                            String value = settingElement.attributeValue("value");
664                                            String script = settingElement.getTextTrim();
665    
666                                            theme.addSetting(
667                                                    key, value, configurable, type, options, script);
668                                    }
669                            }
670    
671                            theme.setWapTheme(
672                                    GetterUtil.getBoolean(
673                                            themeElement.elementText("wap-theme"), theme.isWapTheme()));
674    
675                            Element rolesElement = themeElement.element("roles");
676    
677                            if (rolesElement != null) {
678                                    List<Element> roleNameElements = rolesElement.elements(
679                                            "role-name");
680    
681                                    for (Element roleNameElement : roleNameElements) {
682                                            pluginSetting.addRole(roleNameElement.getText());
683                                    }
684                            }
685    
686                            _readColorSchemes(
687                                    themeElement, theme.getColorSchemesMap(), themeContextReplace);
688                            _readColorSchemes(
689                                    themeElement, theme.getColorSchemesMap(), themeContextReplace);
690    
691                            Element layoutTemplatesElement = themeElement.element(
692                                    "layout-templates");
693    
694                            if (layoutTemplatesElement != null) {
695                                    Element standardElement = layoutTemplatesElement.element(
696                                            "standard");
697    
698                                    if (standardElement != null) {
699                                            layoutTemplateLocalService.readLayoutTemplate(
700                                                    servletContextName, servletContext, null,
701                                                    standardElement, true, themeId, pluginPackage);
702                                    }
703    
704                                    Element customElement = layoutTemplatesElement.element(
705                                            "custom");
706    
707                                    if (customElement != null) {
708                                            layoutTemplateLocalService.readLayoutTemplate(
709                                                    servletContextName, servletContext, null, customElement,
710                                                    false, themeId, pluginPackage);
711                                    }
712                            }
713    
714                            if (!theme.isWapTheme()) {
715                                    _setSpriteImages(servletContext, theme, imagesPath);
716                            }
717    
718                            if (!_themes.containsKey(themeId)) {
719                                    _themes.put(themeId, theme);
720                            }
721                    }
722    
723                    return themeIds;
724            }
725    
726            private void _setSpriteImages(
727                            ServletContext servletContext, Theme theme, String resourcePath)
728                    throws Exception {
729    
730                    Set<String> resourcePaths = servletContext.getResourcePaths(
731                            resourcePath);
732    
733                    if (resourcePaths == null) {
734                            return;
735                    }
736    
737                    List<File> imageFiles = new ArrayList<File>(resourcePaths.size());
738    
739                    for (String curResourcePath : resourcePaths) {
740                            if (curResourcePath.endsWith(StringPool.SLASH)) {
741                                    _setSpriteImages(servletContext, theme, curResourcePath);
742                            }
743                            else if (curResourcePath.endsWith(".png")) {
744                                    String realPath = ServletContextUtil.getRealPath(
745                                            servletContext, curResourcePath);
746    
747                                    if (realPath != null) {
748                                            File imageFile = new File(realPath);
749    
750                                            imageFiles.add(imageFile);
751                                    }
752                                    else {
753                                            if (ServerDetector.isTomcat()) {
754                                                    if (_log.isInfoEnabled()) {
755                                                            _log.info(ServletContextUtil.LOG_INFO_SPRITES);
756                                                    }
757                                            }
758                                            else {
759                                                    _log.error(
760                                                            "Real path for " + curResourcePath + " is null");
761                                            }
762                                    }
763                            }
764                    }
765    
766                    String spriteFileName = PropsValues.SPRITE_FILE_NAME;
767                    String spritePropertiesFileName =
768                            PropsValues.SPRITE_PROPERTIES_FILE_NAME;
769                    String spritePropertiesRootPath = ServletContextUtil.getRealPath(
770                            servletContext, theme.getImagesPath());
771    
772                    Properties spriteProperties = SpriteProcessorUtil.generate(
773                            servletContext, imageFiles, spriteFileName,
774                            spritePropertiesFileName, spritePropertiesRootPath, 16, 16, 10240);
775    
776                    if (spriteProperties == null) {
777                            return;
778                    }
779    
780                    spriteFileName =
781                            resourcePath.substring(
782                                    theme.getImagesPath().length(), resourcePath.length()) +
783                            spriteFileName;
784    
785                    theme.setSpriteImages(spriteFileName, spriteProperties);
786            }
787    
788            private static Log _log = LogFactoryUtil.getLog(
789                    ThemeLocalServiceImpl.class);
790    
791            private static Map<String, Theme> _themes =
792                    new ConcurrentHashMap<String, Theme>();
793            private static Map<Long, Map<String, Theme>> _themesPool =
794                    new ConcurrentHashMap<Long, Map<String, Theme>>();
795    
796    }