001
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
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 = (List<Theme>)PluginUtil.restrictPlugins(
205 themes, companyId, userId);
206
207 Iterator<Theme> itr = themes.iterator();
208
209 while (itr.hasNext()) {
210 Theme theme = itr.next();
211
212 if ((theme.getThemeId().equals("controlpanel")) ||
213 (!theme.isGroupAvailable(groupId)) ||
214 (theme.isWapTheme() != wapTheme)) {
215
216 itr.remove();
217 }
218 }
219
220 return themes;
221 }
222
223 public List<Theme> getWARThemes() {
224 List<Theme> themes = ListUtil.fromMapValues(_themes);
225
226 Iterator<Theme> itr = themes.iterator();
227
228 while (itr.hasNext()) {
229 Theme theme = itr.next();
230
231 if (!theme.isWARFile()) {
232 itr.remove();
233 }
234 }
235
236 return themes;
237 }
238
239 public List<String> init(
240 ServletContext servletContext, String themesPath,
241 boolean loadFromServletContext, String[] xmls,
242 PluginPackage pluginPackage) {
243
244 return init(
245 null, servletContext, themesPath, loadFromServletContext, xmls,
246 pluginPackage);
247 }
248
249 public List<String> init(
250 String servletContextName, ServletContext servletContext,
251 String themesPath, boolean loadFromServletContext, String[] xmls,
252 PluginPackage pluginPackage) {
253
254 List<String> themeIdsList = new ArrayList<String>();
255
256 try {
257 for (String xml : xmls) {
258 Set<String> themeIds = _readThemes(
259 servletContextName, servletContext, themesPath,
260 loadFromServletContext, xml, pluginPackage);
261
262 for (String themeId : themeIds) {
263 if (!themeIdsList.contains(themeId)) {
264 themeIdsList.add(themeId);
265 }
266 }
267 }
268 }
269 catch (Exception e) {
270 e.printStackTrace();
271 }
272
273 _themesPool.clear();
274
275 return themeIdsList;
276 }
277
278 public void uninstallThemes(List<String> themeIds) {
279 for (int i = 0; i < themeIds.size(); i++) {
280 String themeId = themeIds.get(i);
281
282 _themes.remove(themeId);
283
284 layoutTemplateLocalService.uninstallLayoutTemplates(themeId);
285 }
286
287 _themesPool.clear();
288 }
289
290 private List<ThemeCompanyId> _getCompanyLimitExcludes(Element element) {
291 List<ThemeCompanyId> includes = new ArrayList<ThemeCompanyId>();
292
293 if (element == null) {
294 return includes;
295 }
296
297 List<Element> companyIdsElements = element.elements("company-id");
298
299 for (int i = 0; i < companyIdsElements.size(); i++) {
300 Element companyIdElement = companyIdsElements.get(i);
301
302 String name = companyIdElement.attributeValue("name");
303 String pattern = companyIdElement.attributeValue("pattern");
304
305 ThemeCompanyId themeCompanyId = null;
306
307 if (Validator.isNotNull(name)) {
308 themeCompanyId = new ThemeCompanyId(name, false);
309 }
310 else if (Validator.isNotNull(pattern)) {
311 themeCompanyId = new ThemeCompanyId(pattern, true);
312 }
313
314 if (themeCompanyId != null) {
315 includes.add(themeCompanyId);
316 }
317 }
318
319 return includes;
320 }
321
322 private List<ThemeCompanyId> _getCompanyLimitIncludes(Element element) {
323 return _getCompanyLimitExcludes(element);
324 }
325
326 private List<ThemeGroupId> _getGroupLimitExcludes(Element element) {
327 List<ThemeGroupId> includes = new ArrayList<ThemeGroupId>();
328
329 if (element == null) {
330 return includes;
331 }
332
333 List<Element> groupIdsElements = element.elements("group-id");
334
335 for (int i = 0; i < groupIdsElements.size(); i++) {
336 Element groupIdElement = groupIdsElements.get(i);
337
338 String name = groupIdElement.attributeValue("name");
339 String pattern = groupIdElement.attributeValue("pattern");
340
341 ThemeGroupId themeGroupId = null;
342
343 if (Validator.isNotNull(name)) {
344 themeGroupId = new ThemeGroupId(name, false);
345 }
346 else if (Validator.isNotNull(pattern)) {
347 themeGroupId = new ThemeGroupId(pattern, true);
348 }
349
350 if (themeGroupId != null) {
351 includes.add(themeGroupId);
352 }
353 }
354
355 return includes;
356 }
357
358 private List<ThemeGroupId> _getGroupLimitIncludes(Element element) {
359 return _getGroupLimitExcludes(element);
360 }
361
362 private Map<String, Theme> _getThemes(long companyId) {
363 Map<String, Theme> themes = _themesPool.get(companyId);
364
365 if (themes != null) {
366 return themes;
367 }
368
369 themes = new ConcurrentHashMap<String, Theme>();
370
371 for (Map.Entry<String, Theme> entry : _themes.entrySet()) {
372 String themeId = entry.getKey();
373 Theme theme = entry.getValue();
374
375 if (theme.isCompanyAvailable(companyId)) {
376 themes.put(themeId, theme);
377 }
378 }
379
380 _themesPool.put(companyId, themes);
381
382 return themes;
383 }
384
385 private Version _getVersion(String version) {
386 if (version.equals("${current-version}")) {
387 version = ReleaseInfo.getVersion();
388 }
389
390 return Version.getInstance(version);
391 }
392
393 private void _readColorSchemes(
394 Element themeElement, Map<String, ColorScheme> colorSchemes,
395 ContextReplace themeContextReplace) {
396
397 List<Element> colorSchemeElements = themeElement.elements(
398 "color-scheme");
399
400 for (Element colorSchemeElement : colorSchemeElements) {
401 ContextReplace colorSchemeContextReplace =
402 (ContextReplace)themeContextReplace.clone();
403
404 String id = colorSchemeElement.attributeValue("id");
405
406 colorSchemeContextReplace.addValue("color-scheme-id", id);
407
408 ColorScheme colorSchemeModel = colorSchemes.get(id);
409
410 if (colorSchemeModel == null) {
411 colorSchemeModel = new ColorSchemeImpl(id);
412 }
413
414 String name = GetterUtil.getString(
415 colorSchemeElement.attributeValue("name"),
416 colorSchemeModel.getName());
417
418 name = colorSchemeContextReplace.replace(name);
419
420 boolean defaultCs = GetterUtil.getBoolean(
421 colorSchemeElement.elementText("default-cs"),
422 colorSchemeModel.isDefaultCs());
423
424 String cssClass = GetterUtil.getString(
425 colorSchemeElement.elementText("css-class"),
426 colorSchemeModel.getCssClass());
427
428 cssClass = colorSchemeContextReplace.replace(cssClass);
429
430 colorSchemeContextReplace.addValue("css-class", cssClass);
431
432 String colorSchemeImagesPath = GetterUtil.getString(
433 colorSchemeElement.elementText("color-scheme-images-path"),
434 colorSchemeModel.getColorSchemeImagesPath());
435
436 colorSchemeImagesPath = colorSchemeContextReplace.replace(
437 colorSchemeImagesPath);
438
439 colorSchemeContextReplace.addValue(
440 "color-scheme-images-path", colorSchemeImagesPath);
441
442 colorSchemeModel.setName(name);
443 colorSchemeModel.setDefaultCs(defaultCs);
444 colorSchemeModel.setCssClass(cssClass);
445 colorSchemeModel.setColorSchemeImagesPath(colorSchemeImagesPath);
446
447 colorSchemes.put(id, colorSchemeModel);
448 }
449 }
450
451 private Set<String> _readThemes(
452 String servletContextName, ServletContext servletContext,
453 String themesPath, boolean loadFromServletContext, String xml,
454 PluginPackage pluginPackage)
455 throws Exception {
456
457 Set<String> themeIds = new HashSet<String>();
458
459 if (xml == null) {
460 return themeIds;
461 }
462
463 Document document = SAXReaderUtil.read(xml, true);
464
465 Element rootElement = document.getRootElement();
466
467 Version portalVersion = _getVersion(ReleaseInfo.getVersion());
468
469 boolean compatible = false;
470
471 Element compatibilityElement = rootElement.element("compatibility");
472
473 if (compatibilityElement != null) {
474 List<Element> versionElements = compatibilityElement.elements(
475 "version");
476
477 for (Element versionElement : versionElements) {
478 Version version = _getVersion(versionElement.getTextTrim());
479
480 if (version.includes(portalVersion)) {
481 compatible = true;
482
483 break;
484 }
485 }
486 }
487
488 if (!compatible) {
489 _log.error(
490 "Themes in this WAR are not compatible with " +
491 ReleaseInfo.getServerInfo());
492
493 return themeIds;
494 }
495
496 ThemeCompanyLimit companyLimit = null;
497
498 Element companyLimitElement = rootElement.element("company-limit");
499
500 if (companyLimitElement != null) {
501 companyLimit = new ThemeCompanyLimit();
502
503 Element companyIncludesElement = companyLimitElement.element(
504 "company-includes");
505
506 if (companyIncludesElement != null) {
507 companyLimit.setIncludes(
508 _getCompanyLimitIncludes(companyIncludesElement));
509 }
510
511 Element companyExcludesElement = companyLimitElement.element(
512 "company-excludes");
513
514 if (companyExcludesElement != null) {
515 companyLimit.setExcludes(
516 _getCompanyLimitExcludes(companyExcludesElement));
517 }
518 }
519
520 ThemeGroupLimit groupLimit = null;
521
522 Element groupLimitElement = rootElement.element("group-limit");
523
524 if (groupLimitElement != null) {
525 groupLimit = new ThemeGroupLimit();
526
527 Element groupIncludesElement = groupLimitElement.element(
528 "group-includes");
529
530 if (groupIncludesElement != null) {
531 groupLimit.setIncludes(
532 _getGroupLimitIncludes(groupIncludesElement));
533 }
534
535 Element groupExcludesElement = groupLimitElement.element(
536 "group-excludes");
537
538 if (groupExcludesElement != null) {
539 groupLimit.setExcludes(
540 _getGroupLimitExcludes(groupExcludesElement));
541 }
542 }
543
544 long timestamp = ServletContextUtil.getLastModified(servletContext);
545
546 List<Element> themeElements = rootElement.elements("theme");
547
548 for (Element themeElement : themeElements) {
549 ContextReplace themeContextReplace = new ContextReplace();
550
551 themeContextReplace.addValue("themes-path", themesPath);
552
553 String themeId = themeElement.attributeValue("id");
554
555 if (servletContextName != null) {
556 themeId =
557 themeId + PortletConstants.WAR_SEPARATOR +
558 servletContextName;
559 }
560
561 themeId = PortalUtil.getJsSafePortletId(themeId);
562
563 themeContextReplace.addValue("theme-id", themeId);
564
565 themeIds.add(themeId);
566
567 Theme theme = _themes.get(themeId);
568
569 if (theme == null) {
570 theme = new ThemeImpl(themeId);
571 }
572
573 theme.setTimestamp(timestamp);
574
575 PluginSetting pluginSetting =
576 pluginSettingLocalService.getDefaultPluginSetting();
577
578 theme.setPluginPackage(pluginPackage);
579 theme.setDefaultPluginSetting(pluginSetting);
580
581 theme.setThemeCompanyLimit(companyLimit);
582 theme.setThemeGroupLimit(groupLimit);
583
584 if (servletContextName != null) {
585 theme.setServletContextName(servletContextName);
586 }
587
588 theme.setLoadFromServletContext(loadFromServletContext);
589
590 String name = GetterUtil.getString(
591 themeElement.attributeValue("name"), theme.getName());
592
593 String rootPath = GetterUtil.getString(
594 themeElement.elementText("root-path"), theme.getRootPath());
595
596 rootPath = themeContextReplace.replace(rootPath);
597
598 themeContextReplace.addValue("root-path", rootPath);
599
600 String templatesPath = GetterUtil.getString(
601 themeElement.elementText("templates-path"),
602 theme.getTemplatesPath());
603
604 templatesPath = themeContextReplace.replace(templatesPath);
605 templatesPath = StringUtil.safePath(templatesPath);
606
607 themeContextReplace.addValue("templates-path", templatesPath);
608
609 String cssPath = GetterUtil.getString(
610 themeElement.elementText("css-path"), theme.getCssPath());
611
612 cssPath = themeContextReplace.replace(cssPath);
613 cssPath = StringUtil.safePath(cssPath);
614
615 themeContextReplace.addValue("css-path", cssPath);
616
617 String imagesPath = GetterUtil.getString(
618 themeElement.elementText("images-path"), theme.getImagesPath());
619
620 imagesPath = themeContextReplace.replace(imagesPath);
621 imagesPath = StringUtil.safePath(imagesPath);
622
623 themeContextReplace.addValue("images-path", imagesPath);
624
625 String javaScriptPath = GetterUtil.getString(
626 themeElement.elementText("javascript-path"),
627 theme.getJavaScriptPath());
628
629 javaScriptPath = themeContextReplace.replace(javaScriptPath);
630 javaScriptPath = StringUtil.safePath(javaScriptPath);
631
632 themeContextReplace.addValue("javascript-path", javaScriptPath);
633
634 String virtualPath = GetterUtil.getString(
635 themeElement.elementText("virtual-path"),
636 theme.getVirtualPath());
637
638 String templateExtension = GetterUtil.getString(
639 themeElement.elementText("template-extension"),
640 theme.getTemplateExtension());
641
642 theme.setName(name);
643 theme.setRootPath(rootPath);
644 theme.setTemplatesPath(templatesPath);
645 theme.setCssPath(cssPath);
646 theme.setImagesPath(imagesPath);
647 theme.setJavaScriptPath(javaScriptPath);
648 theme.setVirtualPath(virtualPath);
649 theme.setTemplateExtension(templateExtension);
650
651 Element settingsElement = themeElement.element("settings");
652
653 if (settingsElement != null) {
654 List<Element> settingElements = settingsElement.elements(
655 "setting");
656
657 for (Element settingElement : settingElements) {
658 boolean configurable = GetterUtil.getBoolean(
659 settingElement.attributeValue("configurable"));
660 String key = settingElement.attributeValue("key");
661 String[] options = StringUtil.split(
662 settingElement.attributeValue("options"));
663 String type = settingElement.attributeValue("type");
664 String value = settingElement.attributeValue("value");
665 String script = settingElement.getTextTrim();
666
667 theme.addSetting(
668 key, value, configurable, type, options, script);
669 }
670 }
671
672 theme.setWapTheme(
673 GetterUtil.getBoolean(
674 themeElement.elementText("wap-theme"), theme.isWapTheme()));
675
676 Element rolesElement = themeElement.element("roles");
677
678 if (rolesElement != null) {
679 List<Element> roleNameElements = rolesElement.elements(
680 "role-name");
681
682 for (Element roleNameElement : roleNameElements) {
683 pluginSetting.addRole(roleNameElement.getText());
684 }
685 }
686
687 _readColorSchemes(
688 themeElement, theme.getColorSchemesMap(), themeContextReplace);
689 _readColorSchemes(
690 themeElement, theme.getColorSchemesMap(), themeContextReplace);
691
692 Element layoutTemplatesElement = themeElement.element(
693 "layout-templates");
694
695 if (layoutTemplatesElement != null) {
696 Element standardElement = layoutTemplatesElement.element(
697 "standard");
698
699 if (standardElement != null) {
700 layoutTemplateLocalService.readLayoutTemplate(
701 servletContextName, servletContext, null,
702 standardElement, true, themeId, pluginPackage);
703 }
704
705 Element customElement = layoutTemplatesElement.element(
706 "custom");
707
708 if (customElement != null) {
709 layoutTemplateLocalService.readLayoutTemplate(
710 servletContextName, servletContext, null,
711 customElement, false, themeId, pluginPackage);
712 }
713 }
714
715 if (!theme.isWapTheme()) {
716 _setSpriteImages(servletContext, theme, imagesPath);
717 }
718
719 if (!_themes.containsKey(themeId)) {
720 _themes.put(themeId, theme);
721 }
722 }
723
724 return themeIds;
725 }
726
727 private void _setSpriteImages(
728 ServletContext servletContext, Theme theme, String resourcePath)
729 throws Exception {
730
731 Set<String> resourcePaths = servletContext.getResourcePaths(
732 resourcePath);
733
734 if (resourcePaths == null) {
735 return;
736 }
737
738 List<File> imageFiles = new ArrayList<File>(resourcePaths.size());
739
740 for (String curResourcePath : resourcePaths) {
741 if (curResourcePath.endsWith(StringPool.SLASH)) {
742 _setSpriteImages(servletContext, theme, curResourcePath);
743 }
744 else if (curResourcePath.endsWith(".png")) {
745 String realPath = ServletContextUtil.getRealPath(
746 servletContext, curResourcePath);
747
748 if (realPath != null) {
749 File imageFile = new File(realPath);
750
751 imageFiles.add(imageFile);
752 }
753 else {
754 if (ServerDetector.isTomcat()) {
755 if (_log.isInfoEnabled()) {
756 _log.info(ServletContextUtil.LOG_INFO_SPRITES);
757 }
758 }
759 else {
760 _log.error(
761 "Real path for " + curResourcePath + " is null");
762 }
763 }
764 }
765 }
766
767 String spriteFileName = PropsValues.SPRITE_FILE_NAME;
768 String spritePropertiesFileName =
769 PropsValues.SPRITE_PROPERTIES_FILE_NAME;
770 String spritePropertiesRootPath = ServletContextUtil.getRealPath(
771 servletContext, theme.getImagesPath());
772
773 Properties spriteProperties = SpriteProcessorUtil.generate(
774 servletContext, imageFiles, spriteFileName,
775 spritePropertiesFileName, spritePropertiesRootPath, 16, 16, 10240);
776
777 if (spriteProperties == null) {
778 return;
779 }
780
781 spriteFileName =
782 resourcePath.substring(
783 theme.getImagesPath().length(), resourcePath.length()) +
784 spriteFileName;
785
786 theme.setSpriteImages(spriteFileName, spriteProperties);
787 }
788
789 private static Log _log = LogFactoryUtil.getLog(
790 ThemeLocalServiceImpl.class);
791
792 private static Map<String, Theme> _themes =
793 new ConcurrentHashMap<String, Theme>();
794 private static Map<Long, Map<String, Theme>> _themesPool =
795 new ConcurrentHashMap<Long, Map<String, Theme>>();
796
797 }