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.util.ContextReplace;
048
049 import java.io.File;
050
051 import java.util.ArrayList;
052 import java.util.HashSet;
053 import java.util.Iterator;
054 import java.util.List;
055 import java.util.Map;
056 import java.util.Properties;
057 import java.util.Set;
058 import java.util.concurrent.ConcurrentHashMap;
059
060 import javax.servlet.ServletContext;
061
062
066 public class ThemeLocalServiceImpl extends ThemeLocalServiceBaseImpl {
067
068 public ColorScheme getColorScheme(
069 long companyId, String themeId, String colorSchemeId,
070 boolean wapTheme)
071 throws SystemException {
072
073 colorSchemeId = GetterUtil.getString(colorSchemeId);
074
075 Theme theme = getTheme(companyId, themeId, wapTheme);
076
077 Map<String, ColorScheme> colorSchemesMap = theme.getColorSchemesMap();
078
079 ColorScheme colorScheme = colorSchemesMap.get(colorSchemeId);
080
081 if (colorScheme == null) {
082 List<ColorScheme> colorSchemes = theme.getColorSchemes();
083
084 if (colorSchemes.size() > 0) {
085 for (int i = (colorSchemes.size() - 1); i >= 0; i--) {
086 colorScheme = colorSchemes.get(i);
087
088 if (colorScheme.isDefaultCs()) {
089 break;
090 }
091 }
092 }
093 }
094
095 if (colorScheme == null) {
096 if (wapTheme) {
097 colorSchemeId = ColorSchemeImpl.getDefaultWapColorSchemeId();
098 }
099 else {
100 colorSchemeId =
101 ColorSchemeImpl.getDefaultRegularColorSchemeId();
102 }
103 }
104
105 if (colorScheme == null) {
106 colorScheme = ColorSchemeImpl.getNullColorScheme();
107 }
108
109 return colorScheme;
110 }
111
112 public Theme getTheme(long companyId, String themeId, boolean wapTheme)
113 throws SystemException {
114
115 themeId = GetterUtil.getString(themeId);
116
117 Theme theme = _getThemes(companyId).get(themeId);
118
119 if (theme == null) {
120 if (_log.isWarnEnabled()) {
121 _log.warn(
122 "No theme found for specified theme id " + themeId +
123 ". Returning the default theme.");
124 }
125
126 if (wapTheme) {
127 themeId = ThemeImpl.getDefaultWapThemeId(companyId);
128 }
129 else {
130 themeId = ThemeImpl.getDefaultRegularThemeId(companyId);
131 }
132
133 theme = _themes.get(themeId);
134 }
135
136 if (theme == null) {
137 if (_themes.isEmpty()) {
138 if (_log.isDebugEnabled()) {
139 _log.debug("No themes are installed");
140 }
141
142 return null;
143 }
144
145 _log.error(
146 "No theme found for default theme id " + themeId +
147 ". Returning a random theme.");
148
149 Iterator<Map.Entry<String, Theme>> itr =
150 _themes.entrySet().iterator();
151
152 while (itr.hasNext()) {
153 Map.Entry<String, Theme> entry = itr.next();
154
155 theme = entry.getValue();
156 }
157 }
158
159 return theme;
160 }
161
162 public List<Theme> getThemes(long companyId) {
163 List<Theme> themes = ListUtil.fromCollection(
164 _getThemes(companyId).values());
165
166 return ListUtil.sort(themes);
167 }
168
169 public List<Theme> getThemes(
170 long companyId, long groupId, long userId, boolean wapTheme)
171 throws SystemException {
172
173 List<Theme> themes = getThemes(companyId);
174
175 themes = (List<Theme>)PluginUtil.restrictPlugins(
176 themes, companyId, userId);
177
178 Iterator<Theme> itr = themes.iterator();
179
180 while (itr.hasNext()) {
181 Theme theme = itr.next();
182
183 if ((theme.getThemeId().equals("controlpanel")) ||
184 (!theme.isGroupAvailable(groupId)) ||
185 (theme.isWapTheme() != wapTheme)) {
186
187 itr.remove();
188 }
189 }
190
191 return themes;
192 }
193
194 public List<Theme> getWARThemes() {
195 List<Theme> themes = ListUtil.fromCollection(_themes.values());
196
197 Iterator<Theme> itr = themes.iterator();
198
199 while (itr.hasNext()) {
200 Theme theme = itr.next();
201
202 if (!theme.isWARFile()) {
203 itr.remove();
204 }
205 }
206
207 return themes;
208 }
209
210 public List<String> init(
211 ServletContext servletContext, String themesPath,
212 boolean loadFromServletContext, String[] xmls,
213 PluginPackage pluginPackage) {
214
215 return init(
216 null, servletContext, themesPath, loadFromServletContext, xmls,
217 pluginPackage);
218 }
219
220 public List<String> init(
221 String servletContextName, ServletContext servletContext,
222 String themesPath, boolean loadFromServletContext, String[] xmls,
223 PluginPackage pluginPackage) {
224
225 List<String> themeIds = new ArrayList<String>();
226
227 try {
228 for (int i = 0; i < xmls.length; i++) {
229 Set<String> themes = _readThemes(
230 servletContextName, servletContext, themesPath,
231 loadFromServletContext, xmls[i], pluginPackage);
232
233 Iterator<String> itr = themes.iterator();
234
235 while (itr.hasNext()) {
236 String themeId = itr.next();
237
238 if (!themeIds.contains(themeId)) {
239 themeIds.add(themeId);
240 }
241 }
242 }
243 }
244 catch (Exception e) {
245 e.printStackTrace();
246 }
247
248 _themesPool.clear();
249
250 return themeIds;
251 }
252
253 public void uninstallThemes(List<String> themeIds) {
254 for (int i = 0; i < themeIds.size(); i++) {
255 String themeId = themeIds.get(i);
256
257 _themes.remove(themeId);
258
259 layoutTemplateLocalService.uninstallLayoutTemplates(themeId);
260 }
261
262 _themesPool.clear();
263 }
264
265 private List<ThemeCompanyId> _getCompanyLimitExcludes(Element el) {
266 List<ThemeCompanyId> includes = new ArrayList<ThemeCompanyId>();
267
268 if (el != null) {
269 List<Element> companyIds = el.elements("company-id");
270
271 for (int i = 0; i < companyIds.size(); i++) {
272 Element companyIdEl = companyIds.get(i);
273
274 String name = companyIdEl.attributeValue("name");
275 String pattern = companyIdEl.attributeValue("pattern");
276
277 ThemeCompanyId themeCompanyId = null;
278
279 if (Validator.isNotNull(name)) {
280 themeCompanyId = new ThemeCompanyId(name, false);
281 }
282 else if (Validator.isNotNull(pattern)) {
283 themeCompanyId = new ThemeCompanyId(pattern, true);
284 }
285
286 if (themeCompanyId != null) {
287 includes.add(themeCompanyId);
288 }
289 }
290 }
291
292 return includes;
293 }
294
295 private List<ThemeCompanyId> _getCompanyLimitIncludes(Element el) {
296 return _getCompanyLimitExcludes(el);
297 }
298
299 private List<ThemeGroupId> _getGroupLimitExcludes(Element el) {
300 List<ThemeGroupId> includes = new ArrayList<ThemeGroupId>();
301
302 if (el != null) {
303 List<Element> groupIds = el.elements("group-id");
304
305 for (int i = 0; i < groupIds.size(); i++) {
306 Element groupIdEl = groupIds.get(i);
307
308 String name = groupIdEl.attributeValue("name");
309 String pattern = groupIdEl.attributeValue("pattern");
310
311 ThemeGroupId themeGroupId = null;
312
313 if (Validator.isNotNull(name)) {
314 themeGroupId = new ThemeGroupId(name, false);
315 }
316 else if (Validator.isNotNull(pattern)) {
317 themeGroupId = new ThemeGroupId(pattern, true);
318 }
319
320 if (themeGroupId != null) {
321 includes.add(themeGroupId);
322 }
323 }
324 }
325
326 return includes;
327 }
328
329 private List<ThemeGroupId> _getGroupLimitIncludes(Element el) {
330 return _getGroupLimitExcludes(el);
331 }
332
333 private Map<String, Theme> _getThemes(long companyId) {
334 Map<String, Theme> themes = _themesPool.get(companyId);
335
336 if (themes == null) {
337 themes = new ConcurrentHashMap<String, Theme>();
338
339 Iterator<Map.Entry<String, Theme>> itr =
340 _themes.entrySet().iterator();
341
342 while (itr.hasNext()) {
343 Map.Entry<String, Theme> entry = itr.next();
344
345 String themeId = entry.getKey();
346 Theme theme = entry.getValue();
347
348 if (theme.isCompanyAvailable(companyId)) {
349 themes.put(themeId, theme);
350 }
351 }
352
353 _themesPool.put(companyId, themes);
354 }
355
356 return themes;
357 }
358
359 private Version _getVersion(String version) {
360 if (version.equals("${current-version}")) {
361 version = ReleaseInfo.getVersion();
362 }
363
364 return Version.getInstance(version);
365 }
366
367 private void _readColorSchemes(
368 Element theme, Map<String, ColorScheme> colorSchemes,
369 ContextReplace themeContextReplace) {
370
371 Iterator<Element> itr = theme.elements("color-scheme").iterator();
372
373 while (itr.hasNext()) {
374 Element colorScheme = itr.next();
375
376 ContextReplace colorSchemeContextReplace =
377 (ContextReplace)themeContextReplace.clone();
378
379 String id = colorScheme.attributeValue("id");
380
381 colorSchemeContextReplace.addValue("color-scheme-id", id);
382
383 ColorScheme colorSchemeModel = colorSchemes.get(id);
384
385 if (colorSchemeModel == null) {
386 colorSchemeModel = new ColorSchemeImpl(id);
387 }
388
389 String name = GetterUtil.getString(
390 colorScheme.attributeValue("name"), colorSchemeModel.getName());
391
392 name = colorSchemeContextReplace.replace(name);
393
394 boolean defaultCs = GetterUtil.getBoolean(
395 colorScheme.elementText("default-cs"),
396 colorSchemeModel.isDefaultCs());
397
398 String cssClass = GetterUtil.getString(
399 colorScheme.elementText("css-class"),
400 colorSchemeModel.getCssClass());
401
402 cssClass = colorSchemeContextReplace.replace(cssClass);
403
404 colorSchemeContextReplace.addValue("css-class", cssClass);
405
406 String colorSchemeImagesPath = GetterUtil.getString(
407 colorScheme.elementText("color-scheme-images-path"),
408 colorSchemeModel.getColorSchemeImagesPath());
409
410 colorSchemeImagesPath = colorSchemeContextReplace.replace(
411 colorSchemeImagesPath);
412
413 colorSchemeContextReplace.addValue(
414 "color-scheme-images-path", colorSchemeImagesPath);
415
416 colorSchemeModel.setName(name);
417 colorSchemeModel.setDefaultCs(defaultCs);
418 colorSchemeModel.setCssClass(cssClass);
419 colorSchemeModel.setColorSchemeImagesPath(colorSchemeImagesPath);
420
421 colorSchemes.put(id, colorSchemeModel);
422 }
423 }
424
425 private Set<String> _readThemes(
426 String servletContextName, ServletContext servletContext,
427 String themesPath, boolean loadFromServletContext, String xml,
428 PluginPackage pluginPackage)
429 throws Exception {
430
431 Set<String> themeIds = new HashSet<String>();
432
433 if (xml == null) {
434 return themeIds;
435 }
436
437 Document doc = SAXReaderUtil.read(xml, true);
438
439 Element root = doc.getRootElement();
440
441 Version portalVersion = _getVersion(ReleaseInfo.getVersion());
442
443 boolean compatible = false;
444
445 Element compatibilityEl = root.element("compatibility");
446
447 if (compatibilityEl != null) {
448 Iterator<Element> itr = compatibilityEl.elements(
449 "version").iterator();
450
451 while (itr.hasNext()) {
452 Element versionEl = itr.next();
453
454 Version version = _getVersion(versionEl.getTextTrim());
455
456 if (version.includes(portalVersion)) {
457 compatible = true;
458
459 break;
460 }
461 }
462 }
463
464 if (!compatible) {
465 _log.error(
466 "Themes in this WAR are not compatible with " +
467 ReleaseInfo.getServerInfo());
468
469 return themeIds;
470 }
471
472 ThemeCompanyLimit companyLimit = null;
473
474 Element companyLimitEl = root.element("company-limit");
475
476 if (companyLimitEl != null) {
477 companyLimit = new ThemeCompanyLimit();
478
479 Element companyIncludesEl =
480 companyLimitEl.element("company-includes");
481
482 if (companyIncludesEl != null) {
483 companyLimit.setIncludes(
484 _getCompanyLimitIncludes(companyIncludesEl));
485 }
486
487 Element companyExcludesEl =
488 companyLimitEl.element("company-excludes");
489
490 if (companyExcludesEl != null) {
491 companyLimit.setExcludes(
492 _getCompanyLimitExcludes(companyExcludesEl));
493 }
494 }
495
496 ThemeGroupLimit groupLimit = null;
497
498 Element groupLimitEl = root.element("group-limit");
499
500 if (groupLimitEl != null) {
501 groupLimit = new ThemeGroupLimit();
502
503 Element groupIncludesEl = groupLimitEl.element("group-includes");
504
505 if (groupIncludesEl != null) {
506 groupLimit.setIncludes(_getGroupLimitIncludes(groupIncludesEl));
507 }
508
509 Element groupExcludesEl =
510 groupLimitEl.element("group-excludes");
511
512 if (groupExcludesEl != null) {
513 groupLimit.setExcludes(_getGroupLimitExcludes(groupExcludesEl));
514 }
515 }
516
517 long timestamp = ServletContextUtil.getLastModified(servletContext);
518
519 Iterator<Element> itr1 = root.elements("theme").iterator();
520
521 while (itr1.hasNext()) {
522 Element theme = itr1.next();
523
524 ContextReplace themeContextReplace = new ContextReplace();
525
526 themeContextReplace.addValue("themes-path", themesPath);
527
528 String themeId = theme.attributeValue("id");
529
530 if (servletContextName != null) {
531 themeId =
532 themeId + PortletConstants.WAR_SEPARATOR +
533 servletContextName;
534 }
535
536 themeId = PortalUtil.getJsSafePortletId(themeId);
537
538 themeContextReplace.addValue("theme-id", themeId);
539
540 themeIds.add(themeId);
541
542 Theme themeModel = _themes.get(themeId);
543
544 if (themeModel == null) {
545 themeModel = new ThemeImpl(themeId);
546
547 _themes.put(themeId, themeModel);
548 }
549
550 themeModel.setTimestamp(timestamp);
551
552 PluginSetting pluginSetting =
553 pluginSettingLocalService.getDefaultPluginSetting();
554
555 themeModel.setPluginPackage(pluginPackage);
556 themeModel.setDefaultPluginSetting(pluginSetting);
557
558 themeModel.setThemeCompanyLimit(companyLimit);
559 themeModel.setThemeGroupLimit(groupLimit);
560
561 if (servletContextName != null) {
562 themeModel.setServletContextName(servletContextName);
563 }
564
565 themeModel.setLoadFromServletContext(loadFromServletContext);
566
567 String name = GetterUtil.getString(
568 theme.attributeValue("name"), themeModel.getName());
569
570 String rootPath = GetterUtil.getString(
571 theme.elementText("root-path"), themeModel.getRootPath());
572
573 rootPath = themeContextReplace.replace(rootPath);
574
575 themeContextReplace.addValue("root-path", rootPath);
576
577 String templatesPath = GetterUtil.getString(
578 theme.elementText("templates-path"),
579 themeModel.getTemplatesPath());
580
581 templatesPath = themeContextReplace.replace(templatesPath);
582 templatesPath = StringUtil.safePath(templatesPath);
583
584 themeContextReplace.addValue("templates-path", templatesPath);
585
586 String cssPath = GetterUtil.getString(
587 theme.elementText("css-path"), themeModel.getCssPath());
588
589 cssPath = themeContextReplace.replace(cssPath);
590 cssPath = StringUtil.safePath(cssPath);
591
592 themeContextReplace.addValue("css-path", cssPath);
593
594 String imagesPath = GetterUtil.getString(
595 theme.elementText("images-path"),
596 themeModel.getImagesPath());
597
598 imagesPath = themeContextReplace.replace(imagesPath);
599 imagesPath = StringUtil.safePath(imagesPath);
600
601 themeContextReplace.addValue("images-path", imagesPath);
602
603 String javaScriptPath = GetterUtil.getString(
604 theme.elementText("javascript-path"),
605 themeModel.getJavaScriptPath());
606
607 javaScriptPath = themeContextReplace.replace(javaScriptPath);
608 javaScriptPath = StringUtil.safePath(javaScriptPath);
609
610 themeContextReplace.addValue("javascript-path", javaScriptPath);
611
612 String virtualPath = GetterUtil.getString(
613 theme.elementText("virtual-path"), themeModel.getVirtualPath());
614
615 String templateExtension = GetterUtil.getString(
616 theme.elementText("template-extension"),
617 themeModel.getTemplateExtension());
618
619 themeModel.setName(name);
620 themeModel.setRootPath(rootPath);
621 themeModel.setTemplatesPath(templatesPath);
622 themeModel.setCssPath(cssPath);
623 themeModel.setImagesPath(imagesPath);
624 themeModel.setJavaScriptPath(javaScriptPath);
625 themeModel.setVirtualPath(virtualPath);
626 themeModel.setTemplateExtension(templateExtension);
627
628 Element settingsEl = theme.element("settings");
629
630 if (settingsEl != null) {
631 Iterator<Element> itr2 = settingsEl.elements(
632 "setting").iterator();
633
634 while (itr2.hasNext()) {
635 Element settingEl = itr2.next();
636
637 String key = settingEl.attributeValue("key");
638 String value = settingEl.attributeValue("value");
639
640 themeModel.setSetting(key, value);
641 }
642 }
643
644 themeModel.setWapTheme(GetterUtil.getBoolean(
645 theme.elementText("wap-theme"), themeModel.isWapTheme()));
646
647 Element rolesEl = theme.element("roles");
648
649 if (rolesEl != null) {
650 Iterator<Element> itr2 = rolesEl.elements(
651 "role-name").iterator();
652
653 while (itr2.hasNext()) {
654 Element roleNameEl = itr2.next();
655
656 pluginSetting.addRole(roleNameEl.getText());
657 }
658 }
659
660 _readColorSchemes(
661 theme, themeModel.getColorSchemesMap(), themeContextReplace);
662 _readColorSchemes(
663 theme, themeModel.getColorSchemesMap(), themeContextReplace);
664
665 Element layoutTemplatesEl = theme.element("layout-templates");
666
667 if (layoutTemplatesEl != null) {
668 Element standardEl = layoutTemplatesEl.element("standard");
669
670 if (standardEl != null) {
671 layoutTemplateLocalService.readLayoutTemplate(
672 servletContextName, servletContext, null,
673 standardEl, true, themeId, pluginPackage);
674 }
675
676 Element customEl = layoutTemplatesEl.element("custom");
677
678 if (customEl != null) {
679 layoutTemplateLocalService.readLayoutTemplate(
680 servletContextName, servletContext, null,
681 customEl, false, themeId, pluginPackage);
682 }
683 }
684
685 if (!themeModel.isWapTheme()) {
686 _setSpriteImages(servletContext, themeModel, imagesPath);
687 }
688 }
689
690 return themeIds;
691 }
692
693 private void _setSpriteImages(
694 ServletContext servletContext, Theme theme, String resourcePath)
695 throws Exception {
696
697 Set<String> resourcePaths = servletContext.getResourcePaths(
698 resourcePath);
699
700 if (resourcePaths == null) {
701 return;
702 }
703
704 List<File> images = new ArrayList<File>(resourcePaths.size());
705
706 for (String curResourcePath : resourcePaths) {
707 if (curResourcePath.endsWith(StringPool.SLASH)) {
708 _setSpriteImages(servletContext, theme, curResourcePath);
709 }
710 else if (curResourcePath.endsWith(".png")) {
711 String realPath = ServletContextUtil.getRealPath(
712 servletContext, curResourcePath);
713
714 if (realPath != null) {
715 images.add(new File(realPath));
716 }
717 else {
718 if (ServerDetector.isTomcat()) {
719 if (_log.isInfoEnabled()) {
720 _log.info(ServletContextUtil.LOG_INFO_SPRITES);
721 }
722 }
723 else {
724 _log.error(
725 "Real path for " + curResourcePath + " is null");
726 }
727 }
728 }
729 }
730
731 String spriteFileName = ".sprite.png";
732 String spritePropertiesFileName = ".sprite.properties";
733 String spritePropertiesRootPath = ServletContextUtil.getRealPath(
734 servletContext, theme.getImagesPath());
735
736 Properties spriteProperties = SpriteProcessorUtil.generate(
737 images, spriteFileName, spritePropertiesFileName,
738 spritePropertiesRootPath, 16, 16, 10240);
739
740 if (spriteProperties == null) {
741 return;
742 }
743
744 spriteFileName =
745 resourcePath.substring(
746 theme.getImagesPath().length(), resourcePath.length()) +
747 spriteFileName;
748
749 theme.setSpriteImages(spriteFileName, spriteProperties);
750 }
751
752 private static Log _log = LogFactoryUtil.getLog(
753 ThemeLocalServiceImpl.class);
754
755 private static Map<String, Theme> _themes =
756 new ConcurrentHashMap<String, Theme>();
757 private static Map<Long, Map<String, Theme>> _themesPool =
758 new ConcurrentHashMap<Long, Map<String, Theme>>();
759
760 }