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