1
22
23 package com.liferay.portal.service.impl;
24
25 import com.liferay.portal.PortalException;
26 import com.liferay.portal.SystemException;
27 import com.liferay.portal.kernel.plugin.PluginPackage;
28 import com.liferay.portal.kernel.util.GetterUtil;
29 import com.liferay.portal.kernel.util.ReleaseInfo;
30 import com.liferay.portal.kernel.util.StringUtil;
31 import com.liferay.portal.kernel.util.Validator;
32 import com.liferay.portal.model.ColorScheme;
33 import com.liferay.portal.model.PluginSetting;
34 import com.liferay.portal.model.Theme;
35 import com.liferay.portal.model.impl.ColorSchemeImpl;
36 import com.liferay.portal.model.impl.PortletImpl;
37 import com.liferay.portal.model.impl.ThemeImpl;
38 import com.liferay.portal.plugin.PluginUtil;
39 import com.liferay.portal.service.PluginSettingLocalServiceUtil;
40 import com.liferay.portal.theme.ThemeCompanyId;
41 import com.liferay.portal.theme.ThemeCompanyLimit;
42 import com.liferay.portal.theme.ThemeGroupId;
43 import com.liferay.portal.theme.ThemeGroupLimit;
44 import com.liferay.portal.util.DocumentUtil;
45 import com.liferay.portal.util.PortalUtil;
46 import com.liferay.util.ContextReplace;
47 import com.liferay.util.ListUtil;
48 import com.liferay.util.Version;
49
50 import java.io.IOException;
51
52 import java.util.ArrayList;
53 import java.util.Collections;
54 import java.util.HashSet;
55 import java.util.Iterator;
56 import java.util.List;
57 import java.util.Map;
58 import java.util.Set;
59 import java.util.concurrent.ConcurrentHashMap;
60
61 import javax.servlet.ServletContext;
62
63 import org.apache.commons.logging.Log;
64 import org.apache.commons.logging.LogFactory;
65
66 import org.dom4j.Document;
67 import org.dom4j.DocumentException;
68 import org.dom4j.Element;
69
70
77 public class ThemeLocalUtil {
78
79 public static ColorScheme getColorScheme(
80 long companyId, String themeId, String colorSchemeId,
81 boolean wapTheme)
82 throws PortalException, SystemException {
83
84 colorSchemeId = GetterUtil.getString(colorSchemeId);
85
86 Theme theme = getTheme(companyId, themeId, wapTheme);
87
88 Map<String, ColorScheme> colorSchemesMap = theme.getColorSchemesMap();
89
90 ColorScheme colorScheme = colorSchemesMap.get(colorSchemeId);
91
92 if (colorScheme == null) {
93 List<ColorScheme> colorSchemes = theme.getColorSchemes();
94
95 if (colorSchemes.size() > 0) {
96 for (int i = (colorSchemes.size() - 1); i >= 0; i--) {
97 colorScheme = colorSchemes.get(i);
98
99 if (colorScheme.isDefaultCs()) {
100 break;
101 }
102 }
103 }
104 }
105
106 if (colorScheme == null) {
107 if (wapTheme) {
108 colorSchemeId = ColorSchemeImpl.getDefaultWapColorSchemeId();
109 }
110 else {
111 colorSchemeId =
112 ColorSchemeImpl.getDefaultRegularColorSchemeId();
113 }
114 }
115
116 if (colorScheme == null) {
117 colorScheme = ColorSchemeImpl.getNullColorScheme();
118 }
119
120 return colorScheme;
121 }
122
123 public static Theme getTheme(
124 long companyId, String themeId, boolean wapTheme)
125 throws PortalException, SystemException {
126
127 themeId = GetterUtil.getString(themeId);
128
129 Theme theme = _getThemes(companyId).get(themeId);
130
131 if (theme == null) {
132 if (_log.isWarnEnabled()) {
133 _log.warn(
134 "No theme found for specified theme id " + themeId +
135 ". Returning the default theme.");
136 }
137
138 if (wapTheme) {
139 themeId = ThemeImpl.getDefaultWapThemeId();
140 }
141 else {
142 themeId = ThemeImpl.getDefaultRegularThemeId();
143 }
144
145 theme = _themes.get(themeId);
146 }
147
148 if (theme == null) {
149 _log.error(
150 "No theme found for default theme id " + themeId +
151 ". Returning a random theme.");
152
153 Iterator<Map.Entry<String, Theme>> itr =
154 _themes.entrySet().iterator();
155
156 while (itr.hasNext()) {
157 Map.Entry<String, Theme> entry = itr.next();
158
159 theme = entry.getValue();
160 }
161 }
162
163 return theme;
164 }
165
166 public static List<Theme> getThemes(long companyId) {
167 List<Theme> themes = ListUtil.fromCollection(
168 _getThemes(companyId).values());
169
170 Collections.sort(themes);
171
172 return themes;
173 }
174
175 public static List<Theme> getThemes(
176 long companyId, long groupId, long userId, boolean wapTheme)
177 throws PortalException, SystemException {
178
179 List<Theme> themes = getThemes(companyId);
180
181 themes = PluginUtil.restrictPlugins(themes, companyId, userId);
182
183 Iterator<Theme> itr = themes.iterator();
184
185 while (itr.hasNext()) {
186 Theme theme = itr.next();
187
188 if ((!theme.isGroupAvailable(groupId)) ||
189 (theme.isWapTheme() != wapTheme)) {
190
191 itr.remove();
192 }
193 }
194
195 return themes;
196 }
197
198 public static List<String> init(
199 ServletContext ctx, String themesPath, boolean loadFromServletContext,
200 String[] xmls, PluginPackage pluginPackage) {
201
202 return init(
203 null, ctx, themesPath, loadFromServletContext, xmls, pluginPackage);
204 }
205
206 public static List<String> init(
207 String servletContextName, ServletContext ctx, String themesPath,
208 boolean loadFromServletContext, String[] xmls,
209 PluginPackage pluginPackage) {
210
211 List<String> themeIds = new ArrayList<String>();
212
213 try {
214 for (int i = 0; i < xmls.length; i++) {
215 Set<String> themes = _readThemes(
216 servletContextName, ctx, themesPath, loadFromServletContext,
217 xmls[i], pluginPackage);
218
219 Iterator<String> itr = themes.iterator();
220
221 while (itr.hasNext()) {
222 String themeId = itr.next();
223
224 if (!themeIds.contains(themeId)) {
225 themeIds.add(themeId);
226 }
227 }
228 }
229 }
230 catch (Exception e) {
231 e.printStackTrace();
232 }
233
234 _themesPool.clear();
235
236 return themeIds;
237 }
238
239 public static void uninstallThemes(List<String> themeIds) {
240 for (int i = 0; i < themeIds.size(); i++) {
241 String themeId = themeIds.get(i);
242
243 _themes.remove(themeId);
244
245 LayoutTemplateLocalUtil.uninstallLayoutTemplates(themeId);
246 }
247
248 _themesPool.clear();
249 }
250
251 private static List<ThemeCompanyId> _getCompanyLimitExcludes(Element el) {
252 List<ThemeCompanyId> includes = new ArrayList<ThemeCompanyId>();
253
254 if (el != null) {
255 List<Element> companyIds = el.elements("company-id");
256
257 for (int i = 0; i < companyIds.size(); i++) {
258 Element companyIdEl = companyIds.get(i);
259
260 String name = companyIdEl.attributeValue("name");
261 String pattern = companyIdEl.attributeValue("pattern");
262
263 ThemeCompanyId themeCompanyId = null;
264
265 if (Validator.isNotNull(name)) {
266 themeCompanyId = new ThemeCompanyId(name, false);
267 }
268 else if (Validator.isNotNull(pattern)) {
269 themeCompanyId = new ThemeCompanyId(pattern, true);
270 }
271
272 if (themeCompanyId != null) {
273 includes.add(themeCompanyId);
274 }
275 }
276 }
277
278 return includes;
279 }
280
281 private static List<ThemeCompanyId> _getCompanyLimitIncludes(Element el) {
282 return _getCompanyLimitExcludes(el);
283 }
284
285 private static List<ThemeGroupId> _getGroupLimitExcludes(Element el) {
286 List<ThemeGroupId> includes = new ArrayList<ThemeGroupId>();
287
288 if (el != null) {
289 List<Element> groupIds = el.elements("group-id");
290
291 for (int i = 0; i < groupIds.size(); i++) {
292 Element groupIdEl = groupIds.get(i);
293
294 String name = groupIdEl.attributeValue("name");
295 String pattern = groupIdEl.attributeValue("pattern");
296
297 ThemeGroupId themeGroupId = null;
298
299 if (Validator.isNotNull(name)) {
300 themeGroupId = new ThemeGroupId(name, false);
301 }
302 else if (Validator.isNotNull(pattern)) {
303 themeGroupId = new ThemeGroupId(pattern, true);
304 }
305
306 if (themeGroupId != null) {
307 includes.add(themeGroupId);
308 }
309 }
310 }
311
312 return includes;
313 }
314
315 private static List<ThemeGroupId> _getGroupLimitIncludes(Element el) {
316 return _getGroupLimitExcludes(el);
317 }
318
319 private static Map<String, Theme> _getThemes(long companyId) {
320 Map<String, Theme> themes = _themesPool.get(companyId);
321
322 if (themes == null) {
323 themes = new ConcurrentHashMap();
324
325 Iterator<Map.Entry<String, Theme>> itr =
326 _themes.entrySet().iterator();
327
328 while (itr.hasNext()) {
329 Map.Entry<String, Theme> entry = itr.next();
330
331 String themeId = entry.getKey();
332 Theme theme = entry.getValue();
333
334 if (theme.isCompanyAvailable(companyId)) {
335 themes.put(themeId, theme);
336 }
337 }
338
339 _themesPool.put(companyId, themes);
340 }
341
342 return themes;
343 }
344
345 private static Version _getVersion(String version) {
346 if (version.equals("${current-version}")) {
347 version = ReleaseInfo.getVersion();
348 }
349
350 return Version.getInstance(version);
351 }
352
353 private static void _readColorSchemes(
354 Element theme, Map<String, ColorScheme> colorSchemes,
355 ContextReplace themeContextReplace)
356 throws IOException {
357
358 Iterator<Element> itr = theme.elements("color-scheme").iterator();
359
360 while (itr.hasNext()) {
361 Element colorScheme = itr.next();
362
363 ContextReplace colorSchemeContextReplace =
364 (ContextReplace)themeContextReplace.clone();
365
366 String id = colorScheme.attributeValue("id");
367
368 colorSchemeContextReplace.addValue("color-scheme-id", id);
369
370 ColorScheme colorSchemeModel = colorSchemes.get(id);
371
372 if (colorSchemeModel == null) {
373 colorSchemeModel = new ColorSchemeImpl(id);
374 }
375
376 String name = GetterUtil.getString(
377 colorScheme.attributeValue("name"), colorSchemeModel.getName());
378
379 name = colorSchemeContextReplace.replace(name);
380
381 boolean defaultCs = GetterUtil.getBoolean(
382 colorScheme.elementText("default-cs"),
383 colorSchemeModel.isDefaultCs());
384
385 String cssClass = GetterUtil.getString(
386 colorScheme.elementText("css-class"),
387 colorSchemeModel.getCssClass());
388
389 cssClass = colorSchemeContextReplace.replace(cssClass);
390
391 colorSchemeContextReplace.addValue("css-class", cssClass);
392
393 String colorSchemeImagesPath = GetterUtil.getString(
394 colorScheme.elementText("color-scheme-images-path"),
395 colorSchemeModel.getColorSchemeImagesPath());
396
397 colorSchemeImagesPath = colorSchemeContextReplace.replace(
398 colorSchemeImagesPath);
399
400 colorSchemeContextReplace.addValue(
401 "color-scheme-images-path", colorSchemeImagesPath);
402
403 colorSchemeModel.setName(name);
404 colorSchemeModel.setDefaultCs(defaultCs);
405 colorSchemeModel.setCssClass(cssClass);
406 colorSchemeModel.setColorSchemeImagesPath(colorSchemeImagesPath);
407
408 colorSchemes.put(id, colorSchemeModel);
409 }
410 }
411
412 private static Set<String> _readThemes(
413 String servletContextName, ServletContext ctx, String themesPath,
414 boolean loadFromServletContext, String xml,
415 PluginPackage pluginPackage)
416 throws DocumentException, IOException {
417
418 Set<String> themeIds = new HashSet<String>();
419
420 if (xml == null) {
421 return themeIds;
422 }
423
424 Document doc = DocumentUtil.readDocumentFromXML(xml, true);
425
426 Element root = doc.getRootElement();
427
428 Version portalVersion = _getVersion(ReleaseInfo.getVersion());
429
430 boolean compatible = false;
431
432 Element compatibilityEl = root.element("compatibility");
433
434 if (compatibilityEl != null) {
435 Iterator<Element> itr = compatibilityEl.elements(
436 "version").iterator();
437
438 while (itr.hasNext()) {
439 Element versionEl = itr.next();
440
441 Version version = _getVersion(versionEl.getTextTrim());
442
443 if (version.includes(portalVersion)) {
444 compatible = true;
445
446 break;
447 }
448 }
449 }
450
451 if (!compatible) {
452 _log.error(
453 "Themes in this WAR are not compatible with " +
454 ReleaseInfo.getServerInfo());
455
456 return themeIds;
457 }
458
459 ThemeCompanyLimit companyLimit = null;
460
461 Element companyLimitEl = root.element("company-limit");
462
463 if (companyLimitEl != null) {
464 companyLimit = new ThemeCompanyLimit();
465
466 Element companyIncludesEl =
467 companyLimitEl.element("company-includes");
468
469 if (companyIncludesEl != null) {
470 companyLimit.setIncludes(
471 _getCompanyLimitIncludes(companyIncludesEl));
472 }
473
474 Element companyExcludesEl =
475 companyLimitEl.element("company-excludes");
476
477 if (companyExcludesEl != null) {
478 companyLimit.setExcludes(
479 _getCompanyLimitExcludes(companyExcludesEl));
480 }
481 }
482
483 ThemeGroupLimit groupLimit = null;
484
485 Element groupLimitEl = root.element("group-limit");
486
487 if (groupLimitEl != null) {
488 groupLimit = new ThemeGroupLimit();
489
490 Element groupIncludesEl = groupLimitEl.element("group-includes");
491
492 if (groupIncludesEl != null) {
493 groupLimit.setIncludes(_getGroupLimitIncludes(groupIncludesEl));
494 }
495
496 Element groupExcludesEl =
497 groupLimitEl.element("group-excludes");
498
499 if (groupExcludesEl != null) {
500 groupLimit.setExcludes(_getGroupLimitExcludes(groupExcludesEl));
501 }
502 }
503
504 Iterator<Element> itr1 = root.elements("theme").iterator();
505
506 while (itr1.hasNext()) {
507 Element theme = itr1.next();
508
509 ContextReplace themeContextReplace = new ContextReplace();
510
511 themeContextReplace.addValue("themes-path", themesPath);
512
513 String themeId = theme.attributeValue("id");
514
515 if (servletContextName != null) {
516 themeId =
517 themeId + PortletImpl.WAR_SEPARATOR + servletContextName;
518 }
519
520 themeId = PortalUtil.getJsSafePortletId(themeId);
521
522 themeContextReplace.addValue("theme-id", themeId);
523
524 themeIds.add(themeId);
525
526 Theme themeModel = _themes.get(themeId);
527
528 if (themeModel == null) {
529 themeModel = new ThemeImpl(themeId);
530
531 _themes.put(themeId, themeModel);
532 }
533
534 PluginSetting pluginSetting =
535 PluginSettingLocalServiceUtil.getDefaultPluginSetting();
536
537 themeModel.setPluginPackage(pluginPackage);
538 themeModel.setDefaultPluginSetting(pluginSetting);
539
540 themeModel.setThemeCompanyLimit(companyLimit);
541 themeModel.setThemeGroupLimit(groupLimit);
542
543 if (servletContextName != null) {
544 themeModel.setServletContextName(servletContextName);
545 }
546
547 themeModel.setLoadFromServletContext(loadFromServletContext);
548
549 themeModel.setTimestamp(System.currentTimeMillis());
550
551 String name = GetterUtil.getString(
552 theme.attributeValue("name"), themeModel.getName());
553
554 String rootPath = GetterUtil.getString(
555 theme.elementText("root-path"), themeModel.getRootPath());
556
557 rootPath = themeContextReplace.replace(rootPath);
558
559 themeContextReplace.addValue("root-path", rootPath);
560
561 String templatesPath = GetterUtil.getString(
562 theme.elementText("templates-path"),
563 themeModel.getTemplatesPath());
564
565 templatesPath = themeContextReplace.replace(templatesPath);
566 templatesPath = StringUtil.safePath(templatesPath);
567
568 themeContextReplace.addValue("templates-path", templatesPath);
569
570 String cssPath = GetterUtil.getString(
571 theme.elementText("css-path"), themeModel.getCssPath());
572
573 cssPath = themeContextReplace.replace(cssPath);
574 cssPath = StringUtil.safePath(cssPath);
575
576 themeContextReplace.addValue("css-path", cssPath);
577
578 String imagesPath = GetterUtil.getString(
579 theme.elementText("images-path"),
580 themeModel.getImagesPath());
581
582 imagesPath = themeContextReplace.replace(imagesPath);
583 imagesPath = StringUtil.safePath(imagesPath);
584
585 themeContextReplace.addValue("images-path", imagesPath);
586
587 String javaScriptPath = GetterUtil.getString(
588 theme.elementText("javascript-path"),
589 themeModel.getJavaScriptPath());
590
591 javaScriptPath = themeContextReplace.replace(javaScriptPath);
592 javaScriptPath = StringUtil.safePath(javaScriptPath);
593
594 themeContextReplace.addValue("javascript-path", javaScriptPath);
595
596 String virtualPath = GetterUtil.getString(
597 theme.elementText("virtual-path"), themeModel.getVirtualPath());
598
599 String templateExtension = GetterUtil.getString(
600 theme.elementText("template-extension"),
601 themeModel.getTemplateExtension());
602
603 themeModel.setName(name);
604 themeModel.setRootPath(rootPath);
605 themeModel.setTemplatesPath(templatesPath);
606 themeModel.setCssPath(cssPath);
607 themeModel.setImagesPath(imagesPath);
608 themeModel.setJavaScriptPath(javaScriptPath);
609 themeModel.setVirtualPath(virtualPath);
610 themeModel.setTemplateExtension(templateExtension);
611
612 Element settingsEl = theme.element("settings");
613
614 if (settingsEl != null) {
615 Iterator<Element> itr2 = settingsEl.elements(
616 "setting").iterator();
617
618 while (itr2.hasNext()) {
619 Element settingEl = itr2.next();
620
621 String key = settingEl.attributeValue("key");
622 String value = settingEl.attributeValue("value");
623
624 themeModel.setSetting(key, value);
625 }
626 }
627
628 themeModel.setWapTheme(GetterUtil.getBoolean(
629 theme.elementText("wap-theme"), themeModel.isWapTheme()));
630
631 Element rolesEl = theme.element("roles");
632
633 if (rolesEl != null) {
634 Iterator<Element> itr2 = rolesEl.elements(
635 "role-name").iterator();
636
637 while (itr2.hasNext()) {
638 Element roleNameEl = itr2.next();
639
640 pluginSetting.addRole(roleNameEl.getText());
641 }
642 }
643
644 _readColorSchemes(
645 theme, themeModel.getColorSchemesMap(), themeContextReplace);
646 _readColorSchemes(
647 theme, themeModel.getColorSchemesMap(), themeContextReplace);
648
649 Element layoutTemplatesEl = theme.element("layout-templates");
650
651 if (layoutTemplatesEl != null) {
652 Element standardEl = layoutTemplatesEl.element("standard");
653
654 if (standardEl != null) {
655 LayoutTemplateLocalUtil.readLayoutTemplate(
656 servletContextName, ctx, null, standardEl, true,
657 themeId, pluginPackage);
658 }
659
660 Element customEl = layoutTemplatesEl.element("custom");
661
662 if (customEl != null) {
663 LayoutTemplateLocalUtil.readLayoutTemplate(
664 servletContextName, ctx, null, customEl, false, themeId,
665 pluginPackage);
666 }
667 }
668 }
669
670 return themeIds;
671 }
672
673 private static Log _log = LogFactory.getLog(ThemeLocalUtil.class);
674
675 private static Map<String, Theme> _themes =
676 new ConcurrentHashMap<String, Theme>();
677 private static Map<Long, Map<String, Theme>> _themesPool =
678 new ConcurrentHashMap<Long, Map<String, Theme>>();
679
680 }