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