1   /**
2    * Copyright (c) 2000-2009 Liferay, Inc. All rights reserved.
3    *
4    *
5    *
6    *
7    * The contents of this file are subject to the terms of the Liferay Enterprise
8    * Subscription License ("License"). You may not use this file except in
9    * compliance with the License. You can obtain a copy of the License by
10   * contacting Liferay, Inc. See the License for the specific language governing
11   * permissions and limitations under the License, including but not limited to
12   * distribution rights of the Software.
13   *
14   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15   * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16   * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17   * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18   * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19   * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20   * SOFTWARE.
21   */
22  
23  package com.liferay.portal.service.impl;
24  
25  import com.liferay.portal.SystemException;
26  import com.liferay.portal.kernel.image.SpriteProcessorUtil;
27  import com.liferay.portal.kernel.log.Log;
28  import com.liferay.portal.kernel.log.LogFactoryUtil;
29  import com.liferay.portal.kernel.plugin.PluginPackage;
30  import com.liferay.portal.kernel.servlet.ServletContextUtil;
31  import com.liferay.portal.kernel.util.GetterUtil;
32  import com.liferay.portal.kernel.util.ListUtil;
33  import com.liferay.portal.kernel.util.ReleaseInfo;
34  import com.liferay.portal.kernel.util.ServerDetector;
35  import com.liferay.portal.kernel.util.StringPool;
36  import com.liferay.portal.kernel.util.StringUtil;
37  import com.liferay.portal.kernel.util.Validator;
38  import com.liferay.portal.kernel.xml.Document;
39  import com.liferay.portal.kernel.xml.Element;
40  import com.liferay.portal.kernel.xml.SAXReaderUtil;
41  import com.liferay.portal.model.ColorScheme;
42  import com.liferay.portal.model.PluginSetting;
43  import com.liferay.portal.model.PortletConstants;
44  import com.liferay.portal.model.Theme;
45  import com.liferay.portal.model.impl.ColorSchemeImpl;
46  import com.liferay.portal.model.impl.ThemeImpl;
47  import com.liferay.portal.plugin.PluginUtil;
48  import com.liferay.portal.service.base.ThemeLocalServiceBaseImpl;
49  import com.liferay.portal.theme.ThemeCompanyId;
50  import com.liferay.portal.theme.ThemeCompanyLimit;
51  import com.liferay.portal.theme.ThemeGroupId;
52  import com.liferay.portal.theme.ThemeGroupLimit;
53  import com.liferay.portal.util.PortalUtil;
54  import com.liferay.util.ContextReplace;
55  import com.liferay.util.Version;
56  
57  import java.io.File;
58  
59  import java.util.ArrayList;
60  import java.util.HashSet;
61  import java.util.Iterator;
62  import java.util.List;
63  import java.util.Map;
64  import java.util.Properties;
65  import java.util.Set;
66  import java.util.concurrent.ConcurrentHashMap;
67  
68  import javax.servlet.ServletContext;
69  
70  /**
71   * <a href="ThemeLocalServiceImpl.java.html"><b><i>View Source</i></b></a>
72   *
73   * @author Brian Wing Shun Chan
74   * @author Jorge Ferrer
75   */
76  public class ThemeLocalServiceImpl extends ThemeLocalServiceBaseImpl {
77  
78      public ColorScheme getColorScheme(
79              long companyId, String themeId, String colorSchemeId,
80              boolean wapTheme)
81          throws SystemException {
82  
83          colorSchemeId = GetterUtil.getString(colorSchemeId);
84  
85          Theme theme = getTheme(companyId, themeId, wapTheme);
86  
87          Map<String, ColorScheme> colorSchemesMap = theme.getColorSchemesMap();
88  
89          ColorScheme colorScheme = colorSchemesMap.get(colorSchemeId);
90  
91          if (colorScheme == null) {
92              List<ColorScheme> colorSchemes = theme.getColorSchemes();
93  
94              if (colorSchemes.size() > 0) {
95                  for (int i = (colorSchemes.size() - 1); i >= 0; i--) {
96                      colorScheme = colorSchemes.get(i);
97  
98                      if (colorScheme.isDefaultCs()) {
99                          break;
100                     }
101                 }
102             }
103         }
104 
105         if (colorScheme == null) {
106             if (wapTheme) {
107                 colorSchemeId = ColorSchemeImpl.getDefaultWapColorSchemeId();
108             }
109             else {
110                 colorSchemeId =
111                     ColorSchemeImpl.getDefaultRegularColorSchemeId();
112             }
113         }
114 
115         if (colorScheme == null) {
116             colorScheme = ColorSchemeImpl.getNullColorScheme();
117         }
118 
119         return colorScheme;
120     }
121 
122     public Theme getTheme(long companyId, String themeId, boolean wapTheme)
123         throws SystemException {
124 
125         themeId = GetterUtil.getString(themeId);
126 
127         Theme theme = _getThemes(companyId).get(themeId);
128 
129         if (theme == null) {
130             if (_log.isWarnEnabled()) {
131                 _log.warn(
132                     "No theme found for specified theme id " + themeId +
133                         ". Returning the default theme.");
134             }
135 
136             if (wapTheme) {
137                 themeId = ThemeImpl.getDefaultWapThemeId(companyId);
138             }
139             else {
140                 themeId = ThemeImpl.getDefaultRegularThemeId(companyId);
141             }
142 
143             theme = _themes.get(themeId);
144         }
145 
146         if (theme == null) {
147             if (_themes.isEmpty()) {
148                 if (_log.isDebugEnabled()) {
149                     _log.debug("No themes are installed");
150                 }
151 
152                 return null;
153             }
154 
155             _log.error(
156                 "No theme found for default theme id " + themeId +
157                     ". Returning a random theme.");
158 
159             Iterator<Map.Entry<String, Theme>> itr =
160                 _themes.entrySet().iterator();
161 
162             while (itr.hasNext()) {
163                 Map.Entry<String, Theme> entry = itr.next();
164 
165                 theme = entry.getValue();
166             }
167         }
168 
169         return theme;
170     }
171 
172     public List<Theme> getThemes(long companyId) {
173         List<Theme> themes = ListUtil.fromCollection(
174             _getThemes(companyId).values());
175 
176         return ListUtil.sort(themes);
177     }
178 
179     public List<Theme> getThemes(
180             long companyId, long groupId, long userId, boolean wapTheme)
181         throws SystemException {
182 
183         List<Theme> themes = getThemes(companyId);
184 
185         themes = PluginUtil.restrictPlugins(themes, companyId, userId);
186 
187         Iterator<Theme> itr = themes.iterator();
188 
189         while (itr.hasNext()) {
190             Theme theme = itr.next();
191 
192             if ((theme.getThemeId().equals("controlpanel")) ||
193                 (!theme.isGroupAvailable(groupId)) ||
194                 (theme.isWapTheme() != wapTheme)) {
195 
196                 itr.remove();
197             }
198         }
199 
200         return themes;
201     }
202 
203     public List<Theme> getWARThemes() {
204         List<Theme> themes = ListUtil.fromCollection(_themes.values());
205 
206         Iterator<Theme> itr = themes.iterator();
207 
208         while (itr.hasNext()) {
209             Theme theme = itr.next();
210 
211             if (!theme.isWARFile()) {
212                 itr.remove();
213             }
214         }
215 
216         return themes;
217     }
218 
219     public List<String> init(
220         ServletContext servletContext, String themesPath,
221         boolean loadFromServletContext, String[] xmls,
222         PluginPackage pluginPackage) {
223 
224         return init(
225             null, servletContext, themesPath, loadFromServletContext, xmls,
226             pluginPackage);
227     }
228 
229     public List<String> init(
230         String servletContextName, ServletContext servletContext,
231         String themesPath, boolean loadFromServletContext, String[] xmls,
232         PluginPackage pluginPackage) {
233 
234         List<String> themeIds = new ArrayList<String>();
235 
236         try {
237             for (int i = 0; i < xmls.length; i++) {
238                 Set<String> themes = _readThemes(
239                     servletContextName, servletContext, themesPath,
240                     loadFromServletContext, xmls[i], pluginPackage);
241 
242                 Iterator<String> itr = themes.iterator();
243 
244                 while (itr.hasNext()) {
245                     String themeId = itr.next();
246 
247                     if (!themeIds.contains(themeId)) {
248                         themeIds.add(themeId);
249                     }
250                 }
251             }
252         }
253         catch (Exception e) {
254             e.printStackTrace();
255         }
256 
257         _themesPool.clear();
258 
259         return themeIds;
260     }
261 
262     public void uninstallThemes(List<String> themeIds) {
263         for (int i = 0; i < themeIds.size(); i++) {
264             String themeId = themeIds.get(i);
265 
266             _themes.remove(themeId);
267 
268             layoutTemplateLocalService.uninstallLayoutTemplates(themeId);
269         }
270 
271         _themesPool.clear();
272     }
273 
274     private List<ThemeCompanyId> _getCompanyLimitExcludes(Element el) {
275         List<ThemeCompanyId> includes = new ArrayList<ThemeCompanyId>();
276 
277         if (el != null) {
278             List<Element> companyIds = el.elements("company-id");
279 
280             for (int i = 0; i < companyIds.size(); i++) {
281                 Element companyIdEl = companyIds.get(i);
282 
283                 String name = companyIdEl.attributeValue("name");
284                 String pattern = companyIdEl.attributeValue("pattern");
285 
286                 ThemeCompanyId themeCompanyId = null;
287 
288                 if (Validator.isNotNull(name)) {
289                     themeCompanyId = new ThemeCompanyId(name, false);
290                 }
291                 else if (Validator.isNotNull(pattern)) {
292                     themeCompanyId = new ThemeCompanyId(pattern, true);
293                 }
294 
295                 if (themeCompanyId != null) {
296                     includes.add(themeCompanyId);
297                 }
298             }
299         }
300 
301         return includes;
302     }
303 
304     private List<ThemeCompanyId> _getCompanyLimitIncludes(Element el) {
305         return _getCompanyLimitExcludes(el);
306     }
307 
308     private List<ThemeGroupId> _getGroupLimitExcludes(Element el) {
309         List<ThemeGroupId> includes = new ArrayList<ThemeGroupId>();
310 
311         if (el != null) {
312             List<Element> groupIds = el.elements("group-id");
313 
314             for (int i = 0; i < groupIds.size(); i++) {
315                 Element groupIdEl = groupIds.get(i);
316 
317                 String name = groupIdEl.attributeValue("name");
318                 String pattern = groupIdEl.attributeValue("pattern");
319 
320                 ThemeGroupId themeGroupId = null;
321 
322                 if (Validator.isNotNull(name)) {
323                     themeGroupId = new ThemeGroupId(name, false);
324                 }
325                 else if (Validator.isNotNull(pattern)) {
326                     themeGroupId = new ThemeGroupId(pattern, true);
327                 }
328 
329                 if (themeGroupId != null) {
330                     includes.add(themeGroupId);
331                 }
332             }
333         }
334 
335         return includes;
336     }
337 
338     private List<ThemeGroupId> _getGroupLimitIncludes(Element el) {
339         return _getGroupLimitExcludes(el);
340     }
341 
342     private Map<String, Theme> _getThemes(long companyId) {
343         Map<String, Theme> themes = _themesPool.get(companyId);
344 
345         if (themes == null) {
346             themes = new ConcurrentHashMap<String, Theme>();
347 
348             Iterator<Map.Entry<String, Theme>> itr =
349                 _themes.entrySet().iterator();
350 
351             while (itr.hasNext()) {
352                 Map.Entry<String, Theme> entry = itr.next();
353 
354                 String themeId = entry.getKey();
355                 Theme theme = entry.getValue();
356 
357                 if (theme.isCompanyAvailable(companyId)) {
358                     themes.put(themeId, theme);
359                 }
360             }
361 
362             _themesPool.put(companyId, themes);
363         }
364 
365         return themes;
366     }
367 
368     private Version _getVersion(String version) {
369         if (version.equals("${current-version}")) {
370             version = ReleaseInfo.getVersion();
371         }
372 
373         return Version.getInstance(version);
374     }
375 
376     private void _readColorSchemes(
377         Element theme, Map<String, ColorScheme> colorSchemes,
378         ContextReplace themeContextReplace) {
379 
380         Iterator<Element> itr = theme.elements("color-scheme").iterator();
381 
382         while (itr.hasNext()) {
383             Element colorScheme = itr.next();
384 
385             ContextReplace colorSchemeContextReplace =
386                 (ContextReplace)themeContextReplace.clone();
387 
388             String id = colorScheme.attributeValue("id");
389 
390             colorSchemeContextReplace.addValue("color-scheme-id", id);
391 
392             ColorScheme colorSchemeModel = colorSchemes.get(id);
393 
394             if (colorSchemeModel == null) {
395                 colorSchemeModel = new ColorSchemeImpl(id);
396             }
397 
398             String name = GetterUtil.getString(
399                 colorScheme.attributeValue("name"), colorSchemeModel.getName());
400 
401             name = colorSchemeContextReplace.replace(name);
402 
403             boolean defaultCs = GetterUtil.getBoolean(
404                 colorScheme.elementText("default-cs"),
405                 colorSchemeModel.isDefaultCs());
406 
407             String cssClass = GetterUtil.getString(
408                 colorScheme.elementText("css-class"),
409                 colorSchemeModel.getCssClass());
410 
411             cssClass = colorSchemeContextReplace.replace(cssClass);
412 
413             colorSchemeContextReplace.addValue("css-class", cssClass);
414 
415             String colorSchemeImagesPath = GetterUtil.getString(
416                 colorScheme.elementText("color-scheme-images-path"),
417                 colorSchemeModel.getColorSchemeImagesPath());
418 
419             colorSchemeImagesPath = colorSchemeContextReplace.replace(
420                 colorSchemeImagesPath);
421 
422             colorSchemeContextReplace.addValue(
423                 "color-scheme-images-path", colorSchemeImagesPath);
424 
425             colorSchemeModel.setName(name);
426             colorSchemeModel.setDefaultCs(defaultCs);
427             colorSchemeModel.setCssClass(cssClass);
428             colorSchemeModel.setColorSchemeImagesPath(colorSchemeImagesPath);
429 
430             colorSchemes.put(id, colorSchemeModel);
431         }
432     }
433 
434     private Set<String> _readThemes(
435             String servletContextName, ServletContext servletContext,
436             String themesPath, boolean loadFromServletContext, String xml,
437             PluginPackage pluginPackage)
438         throws Exception {
439 
440         Set<String> themeIds = new HashSet<String>();
441 
442         if (xml == null) {
443             return themeIds;
444         }
445 
446         Document doc = SAXReaderUtil.read(xml, true);
447 
448         Element root = doc.getRootElement();
449 
450         Version portalVersion = _getVersion(ReleaseInfo.getVersion());
451 
452         boolean compatible = false;
453 
454         Element compatibilityEl = root.element("compatibility");
455 
456         if (compatibilityEl != null) {
457             Iterator<Element> itr = compatibilityEl.elements(
458                 "version").iterator();
459 
460             while (itr.hasNext()) {
461                 Element versionEl = itr.next();
462 
463                 Version version = _getVersion(versionEl.getTextTrim());
464 
465                 if (version.includes(portalVersion)) {
466                     compatible = true;
467 
468                     break;
469                 }
470             }
471         }
472 
473         if (!compatible) {
474             _log.error(
475                 "Themes in this WAR are not compatible with " +
476                     ReleaseInfo.getServerInfo());
477 
478             return themeIds;
479         }
480 
481         ThemeCompanyLimit companyLimit = null;
482 
483         Element companyLimitEl = root.element("company-limit");
484 
485         if (companyLimitEl != null) {
486             companyLimit = new ThemeCompanyLimit();
487 
488             Element companyIncludesEl =
489                 companyLimitEl.element("company-includes");
490 
491             if (companyIncludesEl != null) {
492                 companyLimit.setIncludes(
493                     _getCompanyLimitIncludes(companyIncludesEl));
494             }
495 
496             Element companyExcludesEl =
497                 companyLimitEl.element("company-excludes");
498 
499             if (companyExcludesEl != null) {
500                 companyLimit.setExcludes(
501                     _getCompanyLimitExcludes(companyExcludesEl));
502             }
503         }
504 
505         ThemeGroupLimit groupLimit = null;
506 
507         Element groupLimitEl = root.element("group-limit");
508 
509         if (groupLimitEl != null) {
510             groupLimit = new ThemeGroupLimit();
511 
512             Element groupIncludesEl = groupLimitEl.element("group-includes");
513 
514             if (groupIncludesEl != null) {
515                 groupLimit.setIncludes(_getGroupLimitIncludes(groupIncludesEl));
516             }
517 
518             Element groupExcludesEl =
519                 groupLimitEl.element("group-excludes");
520 
521             if (groupExcludesEl != null) {
522                 groupLimit.setExcludes(_getGroupLimitExcludes(groupExcludesEl));
523             }
524         }
525 
526         long timestamp = ServletContextUtil.getLastModified(servletContext);
527 
528         Iterator<Element> itr1 = root.elements("theme").iterator();
529 
530         while (itr1.hasNext()) {
531             Element theme = itr1.next();
532 
533             ContextReplace themeContextReplace = new ContextReplace();
534 
535             themeContextReplace.addValue("themes-path", themesPath);
536 
537             String themeId = theme.attributeValue("id");
538 
539             if (servletContextName != null) {
540                 themeId =
541                     themeId + PortletConstants.WAR_SEPARATOR +
542                         servletContextName;
543             }
544 
545             themeId = PortalUtil.getJsSafePortletId(themeId);
546 
547             themeContextReplace.addValue("theme-id", themeId);
548 
549             themeIds.add(themeId);
550 
551             Theme themeModel = _themes.get(themeId);
552 
553             if (themeModel == null) {
554                 themeModel = new ThemeImpl(themeId);
555 
556                 _themes.put(themeId, themeModel);
557             }
558 
559             themeModel.setTimestamp(timestamp);
560 
561             PluginSetting pluginSetting =
562                 pluginSettingLocalService.getDefaultPluginSetting();
563 
564             themeModel.setPluginPackage(pluginPackage);
565             themeModel.setDefaultPluginSetting(pluginSetting);
566 
567             themeModel.setThemeCompanyLimit(companyLimit);
568             themeModel.setThemeGroupLimit(groupLimit);
569 
570             if (servletContextName != null) {
571                 themeModel.setServletContextName(servletContextName);
572             }
573 
574             themeModel.setLoadFromServletContext(loadFromServletContext);
575 
576             String name = GetterUtil.getString(
577                 theme.attributeValue("name"), themeModel.getName());
578 
579             String rootPath = GetterUtil.getString(
580                 theme.elementText("root-path"), themeModel.getRootPath());
581 
582             rootPath = themeContextReplace.replace(rootPath);
583 
584             themeContextReplace.addValue("root-path", rootPath);
585 
586             String templatesPath = GetterUtil.getString(
587                 theme.elementText("templates-path"),
588                 themeModel.getTemplatesPath());
589 
590             templatesPath = themeContextReplace.replace(templatesPath);
591             templatesPath = StringUtil.safePath(templatesPath);
592 
593             themeContextReplace.addValue("templates-path", templatesPath);
594 
595             String cssPath = GetterUtil.getString(
596                 theme.elementText("css-path"), themeModel.getCssPath());
597 
598             cssPath = themeContextReplace.replace(cssPath);
599             cssPath = StringUtil.safePath(cssPath);
600 
601             themeContextReplace.addValue("css-path", cssPath);
602 
603             String imagesPath = GetterUtil.getString(
604                 theme.elementText("images-path"),
605                 themeModel.getImagesPath());
606 
607             imagesPath = themeContextReplace.replace(imagesPath);
608             imagesPath = StringUtil.safePath(imagesPath);
609 
610             themeContextReplace.addValue("images-path", imagesPath);
611 
612             String javaScriptPath = GetterUtil.getString(
613                 theme.elementText("javascript-path"),
614                 themeModel.getJavaScriptPath());
615 
616             javaScriptPath = themeContextReplace.replace(javaScriptPath);
617             javaScriptPath = StringUtil.safePath(javaScriptPath);
618 
619             themeContextReplace.addValue("javascript-path", javaScriptPath);
620 
621             String virtualPath = GetterUtil.getString(
622                 theme.elementText("virtual-path"), themeModel.getVirtualPath());
623 
624             String templateExtension = GetterUtil.getString(
625                 theme.elementText("template-extension"),
626                 themeModel.getTemplateExtension());
627 
628             themeModel.setName(name);
629             themeModel.setRootPath(rootPath);
630             themeModel.setTemplatesPath(templatesPath);
631             themeModel.setCssPath(cssPath);
632             themeModel.setImagesPath(imagesPath);
633             themeModel.setJavaScriptPath(javaScriptPath);
634             themeModel.setVirtualPath(virtualPath);
635             themeModel.setTemplateExtension(templateExtension);
636 
637             Element settingsEl = theme.element("settings");
638 
639             if (settingsEl != null) {
640                 Iterator<Element> itr2 = settingsEl.elements(
641                     "setting").iterator();
642 
643                 while (itr2.hasNext()) {
644                     Element settingEl = itr2.next();
645 
646                     String key = settingEl.attributeValue("key");
647                     String value = settingEl.attributeValue("value");
648 
649                     themeModel.setSetting(key, value);
650                 }
651             }
652 
653             themeModel.setWapTheme(GetterUtil.getBoolean(
654                 theme.elementText("wap-theme"), themeModel.isWapTheme()));
655 
656             Element rolesEl = theme.element("roles");
657 
658             if (rolesEl != null) {
659                 Iterator<Element> itr2 = rolesEl.elements(
660                     "role-name").iterator();
661 
662                 while (itr2.hasNext()) {
663                     Element roleNameEl = itr2.next();
664 
665                     pluginSetting.addRole(roleNameEl.getText());
666                 }
667             }
668 
669             _readColorSchemes(
670                 theme, themeModel.getColorSchemesMap(), themeContextReplace);
671             _readColorSchemes(
672                 theme, themeModel.getColorSchemesMap(), themeContextReplace);
673 
674             Element layoutTemplatesEl = theme.element("layout-templates");
675 
676             if (layoutTemplatesEl != null) {
677                 Element standardEl = layoutTemplatesEl.element("standard");
678 
679                 if (standardEl != null) {
680                     layoutTemplateLocalService.readLayoutTemplate(
681                         servletContextName, servletContext, null,
682                         standardEl, true, themeId, pluginPackage);
683                 }
684 
685                 Element customEl = layoutTemplatesEl.element("custom");
686 
687                 if (customEl != null) {
688                     layoutTemplateLocalService.readLayoutTemplate(
689                         servletContextName, servletContext, null,
690                         customEl, false, themeId, pluginPackage);
691                 }
692             }
693 
694             if (!themeModel.isWapTheme()) {
695                 _setSpriteImages(servletContext, themeModel, imagesPath);
696             }
697         }
698 
699         return themeIds;
700     }
701 
702     private void _setSpriteImages(
703             ServletContext servletContext, Theme theme, String resourcePath)
704         throws Exception {
705 
706         Set<String> resourcePaths = servletContext.getResourcePaths(
707             resourcePath);
708 
709         if (resourcePaths == null) {
710             return;
711         }
712 
713         List<File> images = new ArrayList<File>(resourcePaths.size());
714 
715         for (String curResourcePath : resourcePaths) {
716             if (curResourcePath.endsWith(StringPool.SLASH)) {
717                 _setSpriteImages(servletContext, theme, curResourcePath);
718             }
719             else if (curResourcePath.endsWith(".png")) {
720                 String realPath = ServletContextUtil.getRealPath(
721                     servletContext, curResourcePath);
722 
723                 if (realPath != null) {
724                     images.add(new File(realPath));
725                 }
726                 else {
727                     if (ServerDetector.isTomcat()) {
728                         if (_log.isInfoEnabled()) {
729                             _log.info(ServletContextUtil.LOG_INFO_SPRITES);
730                         }
731                     }
732                     else {
733                         _log.error(
734                             "Real path for " + curResourcePath + " is null");
735                     }
736                 }
737             }
738         }
739 
740         String spriteFileName = ".sprite.png";
741         String spritePropertiesFileName = ".sprite.properties";
742         String spritePropertiesRootPath = ServletContextUtil.getRealPath(
743             servletContext, theme.getImagesPath());
744 
745         Properties spriteProperties = SpriteProcessorUtil.generate(
746             images, spriteFileName, spritePropertiesFileName,
747             spritePropertiesRootPath, 16, 16, 10240);
748 
749         if (spriteProperties == null) {
750             return;
751         }
752 
753         spriteFileName =
754             resourcePath.substring(
755                 theme.getImagesPath().length(), resourcePath.length()) +
756             spriteFileName;
757 
758         theme.setSpriteImages(spriteFileName, spriteProperties);
759     }
760 
761     private static Log _log =
762         LogFactoryUtil.getLog(ThemeLocalServiceImpl.class);
763 
764     private static Map<String, Theme> _themes =
765         new ConcurrentHashMap<String, Theme>();
766     private static Map<Long, Map<String, Theme>> _themesPool =
767         new ConcurrentHashMap<Long, Map<String, Theme>>();
768 
769 }