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.ListUtil;
30 import com.liferay.portal.kernel.util.ReleaseInfo;
31 import com.liferay.portal.kernel.util.StringUtil;
32 import com.liferay.portal.kernel.util.Validator;
33 import com.liferay.portal.kernel.xml.Document;
34 import com.liferay.portal.kernel.xml.Element;
35 import com.liferay.portal.kernel.xml.SAXReaderUtil;
36 import com.liferay.portal.model.ColorScheme;
37 import com.liferay.portal.model.PluginSetting;
38 import com.liferay.portal.model.PortletConstants;
39 import com.liferay.portal.model.Theme;
40 import com.liferay.portal.model.impl.ColorSchemeImpl;
41 import com.liferay.portal.model.impl.ThemeImpl;
42 import com.liferay.portal.plugin.PluginUtil;
43 import com.liferay.portal.service.LayoutTemplateLocalServiceUtil;
44 import com.liferay.portal.service.PluginSettingLocalServiceUtil;
45 import com.liferay.portal.service.base.ThemeLocalServiceBaseImpl;
46 import com.liferay.portal.theme.ThemeCompanyId;
47 import com.liferay.portal.theme.ThemeCompanyLimit;
48 import com.liferay.portal.theme.ThemeGroupId;
49 import com.liferay.portal.theme.ThemeGroupLimit;
50 import com.liferay.portal.util.PortalUtil;
51 import com.liferay.util.ContextReplace;
52 import com.liferay.util.Version;
53
54 import java.util.ArrayList;
55 import java.util.HashSet;
56 import java.util.Iterator;
57 import java.util.List;
58 import java.util.Map;
59 import java.util.Set;
60 import java.util.concurrent.ConcurrentHashMap;
61
62 import javax.servlet.ServletContext;
63
64 import org.apache.commons.logging.Log;
65 import org.apache.commons.logging.LogFactory;
66
67
74 public class ThemeLocalServiceImpl extends ThemeLocalServiceBaseImpl {
75
76 public ColorScheme getColorScheme(
77 long companyId, String themeId, String colorSchemeId,
78 boolean wapTheme) {
79
80 colorSchemeId = GetterUtil.getString(colorSchemeId);
81
82 Theme theme = getTheme(companyId, themeId, wapTheme);
83
84 Map<String, ColorScheme> colorSchemesMap = theme.getColorSchemesMap();
85
86 ColorScheme colorScheme = colorSchemesMap.get(colorSchemeId);
87
88 if (colorScheme == null) {
89 List<ColorScheme> colorSchemes = theme.getColorSchemes();
90
91 if (colorSchemes.size() > 0) {
92 for (int i = (colorSchemes.size() - 1); i >= 0; i--) {
93 colorScheme = colorSchemes.get(i);
94
95 if (colorScheme.isDefaultCs()) {
96 break;
97 }
98 }
99 }
100 }
101
102 if (colorScheme == null) {
103 if (wapTheme) {
104 colorSchemeId = ColorSchemeImpl.getDefaultWapColorSchemeId();
105 }
106 else {
107 colorSchemeId =
108 ColorSchemeImpl.getDefaultRegularColorSchemeId();
109 }
110 }
111
112 if (colorScheme == null) {
113 colorScheme = ColorSchemeImpl.getNullColorScheme();
114 }
115
116 return colorScheme;
117 }
118
119 public Theme getTheme(long companyId, String themeId, boolean wapTheme) {
120 themeId = GetterUtil.getString(themeId);
121
122 Theme theme = _getThemes(companyId).get(themeId);
123
124 if (theme == null) {
125 if (_log.isWarnEnabled()) {
126 _log.warn(
127 "No theme found for specified theme id " + themeId +
128 ". Returning the default theme.");
129 }
130
131 if (wapTheme) {
132 themeId = ThemeImpl.getDefaultWapThemeId();
133 }
134 else {
135 themeId = ThemeImpl.getDefaultRegularThemeId();
136 }
137
138 theme = _themes.get(themeId);
139 }
140
141 if (theme == null) {
142 if (_themes.isEmpty()) {
143 if (_log.isDebugEnabled()) {
144 _log.debug("No themes are installed");
145 }
146
147 return null;
148 }
149
150 _log.error(
151 "No theme found for default theme id " + themeId +
152 ". Returning a random theme.");
153
154 Iterator<Map.Entry<String, Theme>> itr =
155 _themes.entrySet().iterator();
156
157 while (itr.hasNext()) {
158 Map.Entry<String, Theme> entry = itr.next();
159
160 theme = entry.getValue();
161 }
162 }
163
164 return theme;
165 }
166
167 public List<Theme> getThemes(long companyId) {
168 List<Theme> themes = ListUtil.fromCollection(
169 _getThemes(companyId).values());
170
171 return ListUtil.sort(themes);
172 }
173
174 public List<Theme> getThemes(
175 long companyId, long groupId, long userId, boolean wapTheme)
176 throws PortalException, SystemException {
177
178 List<Theme> themes = getThemes(companyId);
179
180 themes = PluginUtil.restrictPlugins(themes, companyId, userId);
181
182 Iterator<Theme> itr = themes.iterator();
183
184 while (itr.hasNext()) {
185 Theme theme = itr.next();
186
187 if ((!theme.isGroupAvailable(groupId)) ||
188 (theme.isWapTheme() != wapTheme)) {
189
190 itr.remove();
191 }
192 }
193
194 return themes;
195 }
196
197 public List<String> init(
198 ServletContext servletContext, String themesPath,
199 boolean loadFromServletContext, String[] xmls,
200 PluginPackage pluginPackage) {
201
202 return init(
203 null, servletContext, themesPath, loadFromServletContext, xmls,
204 pluginPackage);
205 }
206
207 public List<String> init(
208 String servletContextName, ServletContext servletContext,
209 String themesPath, boolean loadFromServletContext, String[] xmls,
210 PluginPackage pluginPackage) {
211
212 List<String> themeIds = new ArrayList<String>();
213
214 try {
215 for (int i = 0; i < xmls.length; i++) {
216 Set<String> themes = _readThemes(
217 servletContextName, servletContext, themesPath,
218 loadFromServletContext, xmls[i], pluginPackage);
219
220 Iterator<String> itr = themes.iterator();
221
222 while (itr.hasNext()) {
223 String themeId = itr.next();
224
225 if (!themeIds.contains(themeId)) {
226 themeIds.add(themeId);
227 }
228 }
229 }
230 }
231 catch (Exception e) {
232 e.printStackTrace();
233 }
234
235 _themesPool.clear();
236
237 return themeIds;
238 }
239
240 public void uninstallThemes(List<String> themeIds) {
241 for (int i = 0; i < themeIds.size(); i++) {
242 String themeId = themeIds.get(i);
243
244 _themes.remove(themeId);
245
246 LayoutTemplateLocalServiceUtil.uninstallLayoutTemplates(themeId);
247 }
248
249 _themesPool.clear();
250 }
251
252 private List<ThemeCompanyId> _getCompanyLimitExcludes(Element el) {
253 List<ThemeCompanyId> includes = new ArrayList<ThemeCompanyId>();
254
255 if (el != null) {
256 List<Element> companyIds = el.elements("company-id");
257
258 for (int i = 0; i < companyIds.size(); i++) {
259 Element companyIdEl = companyIds.get(i);
260
261 String name = companyIdEl.attributeValue("name");
262 String pattern = companyIdEl.attributeValue("pattern");
263
264 ThemeCompanyId themeCompanyId = null;
265
266 if (Validator.isNotNull(name)) {
267 themeCompanyId = new ThemeCompanyId(name, false);
268 }
269 else if (Validator.isNotNull(pattern)) {
270 themeCompanyId = new ThemeCompanyId(pattern, true);
271 }
272
273 if (themeCompanyId != null) {
274 includes.add(themeCompanyId);
275 }
276 }
277 }
278
279 return includes;
280 }
281
282 private List<ThemeCompanyId> _getCompanyLimitIncludes(Element el) {
283 return _getCompanyLimitExcludes(el);
284 }
285
286 private List<ThemeGroupId> _getGroupLimitExcludes(Element el) {
287 List<ThemeGroupId> includes = new ArrayList<ThemeGroupId>();
288
289 if (el != null) {
290 List<Element> groupIds = el.elements("group-id");
291
292 for (int i = 0; i < groupIds.size(); i++) {
293 Element groupIdEl = groupIds.get(i);
294
295 String name = groupIdEl.attributeValue("name");
296 String pattern = groupIdEl.attributeValue("pattern");
297
298 ThemeGroupId themeGroupId = null;
299
300 if (Validator.isNotNull(name)) {
301 themeGroupId = new ThemeGroupId(name, false);
302 }
303 else if (Validator.isNotNull(pattern)) {
304 themeGroupId = new ThemeGroupId(pattern, true);
305 }
306
307 if (themeGroupId != null) {
308 includes.add(themeGroupId);
309 }
310 }
311 }
312
313 return includes;
314 }
315
316 private List<ThemeGroupId> _getGroupLimitIncludes(Element el) {
317 return _getGroupLimitExcludes(el);
318 }
319
320 private Map<String, Theme> _getThemes(long companyId) {
321 Map<String, Theme> themes = _themesPool.get(companyId);
322
323 if (themes == null) {
324 themes = new ConcurrentHashMap<String, Theme>();
325
326 Iterator<Map.Entry<String, Theme>> itr =
327 _themes.entrySet().iterator();
328
329 while (itr.hasNext()) {
330 Map.Entry<String, Theme> entry = itr.next();
331
332 String themeId = entry.getKey();
333 Theme theme = entry.getValue();
334
335 if (theme.isCompanyAvailable(companyId)) {
336 themes.put(themeId, theme);
337 }
338 }
339
340 _themesPool.put(companyId, themes);
341 }
342
343 return themes;
344 }
345
346 private Version _getVersion(String version) {
347 if (version.equals("${current-version}")) {
348 version = ReleaseInfo.getVersion();
349 }
350
351 return Version.getInstance(version);
352 }
353
354 private void _readColorSchemes(
355 Element theme, Map<String, ColorScheme> colorSchemes,
356 ContextReplace themeContextReplace) {
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 Set<String> _readThemes(
413 String servletContextName, ServletContext servletContext,
414 String themesPath, boolean loadFromServletContext, String xml,
415 PluginPackage pluginPackage)
416 throws Exception {
417
418 Set<String> themeIds = new HashSet<String>();
419
420 if (xml == null) {
421 return themeIds;
422 }
423
424 Document doc = SAXReaderUtil.read(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 + PortletConstants.WAR_SEPARATOR +
518 servletContextName;
519 }
520
521 themeId = PortalUtil.getJsSafePortletId(themeId);
522
523 themeContextReplace.addValue("theme-id", themeId);
524
525 themeIds.add(themeId);
526
527 Theme themeModel = _themes.get(themeId);
528
529 if (themeModel == null) {
530 themeModel = new ThemeImpl(themeId);
531
532 _themes.put(themeId, themeModel);
533 }
534
535 themeModel.setTimestamp(System.currentTimeMillis());
536
537 PluginSetting pluginSetting =
538 PluginSettingLocalServiceUtil.getDefaultPluginSetting();
539
540 themeModel.setPluginPackage(pluginPackage);
541 themeModel.setDefaultPluginSetting(pluginSetting);
542
543 themeModel.setThemeCompanyLimit(companyLimit);
544 themeModel.setThemeGroupLimit(groupLimit);
545
546 if (servletContextName != null) {
547 themeModel.setServletContextName(servletContextName);
548 }
549
550 themeModel.setLoadFromServletContext(loadFromServletContext);
551
552 String name = GetterUtil.getString(
553 theme.attributeValue("name"), themeModel.getName());
554
555 String rootPath = GetterUtil.getString(
556 theme.elementText("root-path"), themeModel.getRootPath());
557
558 rootPath = themeContextReplace.replace(rootPath);
559
560 themeContextReplace.addValue("root-path", rootPath);
561
562 String templatesPath = GetterUtil.getString(
563 theme.elementText("templates-path"),
564 themeModel.getTemplatesPath());
565
566 templatesPath = themeContextReplace.replace(templatesPath);
567 templatesPath = StringUtil.safePath(templatesPath);
568
569 themeContextReplace.addValue("templates-path", templatesPath);
570
571 String cssPath = GetterUtil.getString(
572 theme.elementText("css-path"), themeModel.getCssPath());
573
574 cssPath = themeContextReplace.replace(cssPath);
575 cssPath = StringUtil.safePath(cssPath);
576
577 themeContextReplace.addValue("css-path", cssPath);
578
579 String imagesPath = GetterUtil.getString(
580 theme.elementText("images-path"),
581 themeModel.getImagesPath());
582
583 imagesPath = themeContextReplace.replace(imagesPath);
584 imagesPath = StringUtil.safePath(imagesPath);
585
586 themeContextReplace.addValue("images-path", imagesPath);
587
588 String javaScriptPath = GetterUtil.getString(
589 theme.elementText("javascript-path"),
590 themeModel.getJavaScriptPath());
591
592 javaScriptPath = themeContextReplace.replace(javaScriptPath);
593 javaScriptPath = StringUtil.safePath(javaScriptPath);
594
595 themeContextReplace.addValue("javascript-path", javaScriptPath);
596
597 String virtualPath = GetterUtil.getString(
598 theme.elementText("virtual-path"), themeModel.getVirtualPath());
599
600 String templateExtension = GetterUtil.getString(
601 theme.elementText("template-extension"),
602 themeModel.getTemplateExtension());
603
604 themeModel.setName(name);
605 themeModel.setRootPath(rootPath);
606 themeModel.setTemplatesPath(templatesPath);
607 themeModel.setCssPath(cssPath);
608 themeModel.setImagesPath(imagesPath);
609 themeModel.setJavaScriptPath(javaScriptPath);
610 themeModel.setVirtualPath(virtualPath);
611 themeModel.setTemplateExtension(templateExtension);
612
613 Element settingsEl = theme.element("settings");
614
615 if (settingsEl != null) {
616 Iterator<Element> itr2 = settingsEl.elements(
617 "setting").iterator();
618
619 while (itr2.hasNext()) {
620 Element settingEl = itr2.next();
621
622 String key = settingEl.attributeValue("key");
623 String value = settingEl.attributeValue("value");
624
625 themeModel.setSetting(key, value);
626 }
627 }
628
629 themeModel.setWapTheme(GetterUtil.getBoolean(
630 theme.elementText("wap-theme"), themeModel.isWapTheme()));
631
632 Element rolesEl = theme.element("roles");
633
634 if (rolesEl != null) {
635 Iterator<Element> itr2 = rolesEl.elements(
636 "role-name").iterator();
637
638 while (itr2.hasNext()) {
639 Element roleNameEl = itr2.next();
640
641 pluginSetting.addRole(roleNameEl.getText());
642 }
643 }
644
645 _readColorSchemes(
646 theme, themeModel.getColorSchemesMap(), themeContextReplace);
647 _readColorSchemes(
648 theme, themeModel.getColorSchemesMap(), themeContextReplace);
649
650 Element layoutTemplatesEl = theme.element("layout-templates");
651
652 if (layoutTemplatesEl != null) {
653 Element standardEl = layoutTemplatesEl.element("standard");
654
655 if (standardEl != null) {
656 LayoutTemplateLocalServiceUtil.readLayoutTemplate(
657 servletContextName, servletContext, null,
658 standardEl, true, themeId, pluginPackage);
659 }
660
661 Element customEl = layoutTemplatesEl.element("custom");
662
663 if (customEl != null) {
664 LayoutTemplateLocalServiceUtil.readLayoutTemplate(
665 servletContextName, servletContext, null,
666 customEl, false, themeId, pluginPackage);
667 }
668 }
669 }
670
671 return themeIds;
672 }
673
674 private static Log _log = LogFactory.getLog(ThemeLocalServiceImpl.class);
675
676 private static Map<String, Theme> _themes =
677 new ConcurrentHashMap<String, Theme>();
678 private static Map<Long, Map<String, Theme>> _themesPool =
679 new ConcurrentHashMap<Long, Map<String, Theme>>();
680
681 }