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 = 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 }