001    /**
002     * Copyright (c) 2000-present Liferay, Inc. All rights reserved.
003     *
004     * This library is free software; you can redistribute it and/or modify it under
005     * the terms of the GNU Lesser General Public License as published by the Free
006     * Software Foundation; either version 2.1 of the License, or (at your option)
007     * any later version.
008     *
009     * This library is distributed in the hope that it will be useful, but WITHOUT
010     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
011     * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
012     * details.
013     */
014    
015    package com.liferay.portal.model.impl;
016    
017    import com.liferay.portal.kernel.log.Log;
018    import com.liferay.portal.kernel.log.LogFactoryUtil;
019    import com.liferay.portal.kernel.servlet.PortalWebResourceConstants;
020    import com.liferay.portal.kernel.servlet.PortalWebResourcesUtil;
021    import com.liferay.portal.kernel.servlet.ServletContextPool;
022    import com.liferay.portal.kernel.template.TemplateConstants;
023    import com.liferay.portal.kernel.util.ListUtil;
024    import com.liferay.portal.kernel.util.StringPool;
025    import com.liferay.portal.kernel.util.StringUtil;
026    import com.liferay.portal.kernel.util.ThemeHelper;
027    import com.liferay.portal.kernel.util.Validator;
028    import com.liferay.portal.model.ColorScheme;
029    import com.liferay.portal.model.Plugin;
030    import com.liferay.portal.model.PortletDecorator;
031    import com.liferay.portal.model.SpriteImage;
032    import com.liferay.portal.model.Theme;
033    import com.liferay.portal.model.ThemeSetting;
034    import com.liferay.portal.theme.ThemeCompanyId;
035    import com.liferay.portal.theme.ThemeCompanyLimit;
036    import com.liferay.portal.theme.ThemeGroupLimit;
037    import com.liferay.portal.util.PortalUtil;
038    import com.liferay.portal.util.PropsValues;
039    
040    import java.util.HashMap;
041    import java.util.LinkedHashMap;
042    import java.util.List;
043    import java.util.Map;
044    import java.util.Properties;
045    import java.util.concurrent.ConcurrentHashMap;
046    
047    import javax.servlet.ServletContext;
048    
049    /**
050     * @author Brian Wing Shun Chan
051     * @author Julio Camarero
052     * @author Raymond Aug??
053     */
054    public class ThemeImpl extends PluginBaseImpl implements Theme {
055    
056            public ThemeImpl() {
057                    this(null);
058            }
059    
060            public ThemeImpl(String themeId) {
061                    this(themeId, null);
062            }
063    
064            public ThemeImpl(String themeId, String name) {
065                    _themeId = themeId;
066                    _name = name;
067            }
068    
069            @Override
070            public void addSetting(
071                    String key, String value, boolean configurable, String type,
072                    String[] options, String script) {
073    
074                    ThemeSetting themeSetting = new ThemeSettingImpl(
075                            configurable, options, script, type, value);
076    
077                    _themeSettingsMap.put(key, themeSetting);
078            }
079    
080            @Override
081            public int compareTo(Theme theme) {
082                    return getName().compareTo(theme.getName());
083            }
084    
085            @Override
086            public boolean equals(Object obj) {
087                    if (this == obj) {
088                            return true;
089                    }
090    
091                    if (!(obj instanceof Theme)) {
092                            return false;
093                    }
094    
095                    Theme theme = (Theme)obj;
096    
097                    String themeId = theme.getThemeId();
098    
099                    if (getThemeId().equals(themeId)) {
100                            return true;
101                    }
102                    else {
103                            return false;
104                    }
105            }
106    
107            @Override
108            public List<ColorScheme> getColorSchemes() {
109                    List<ColorScheme> colorSchemes = ListUtil.fromMapValues(
110                            _colorSchemesMap);
111    
112                    return ListUtil.sort(colorSchemes);
113            }
114    
115            @Override
116            public Map<String, ColorScheme> getColorSchemesMap() {
117                    return _colorSchemesMap;
118            }
119    
120            @Override
121            public Map<String, ThemeSetting> getConfigurableSettings() {
122                    Map<String, ThemeSetting> configurableSettings = new LinkedHashMap<>();
123    
124                    for (Map.Entry<String, ThemeSetting> entry :
125                                    _themeSettingsMap.entrySet()) {
126    
127                            ThemeSetting themeSetting = entry.getValue();
128    
129                            if (themeSetting.isConfigurable()) {
130                                    configurableSettings.put(entry.getKey(), entry.getValue());
131                            }
132                    }
133    
134                    return configurableSettings;
135            }
136    
137            @Override
138            public String getContextPath() {
139                    if (!isWARFile()) {
140                            return PortalUtil.getPathContext();
141                    }
142    
143                    String servletContextName = getServletContextName();
144    
145                    if (ServletContextPool.containsKey(servletContextName)) {
146                            ServletContext servletContext = ServletContextPool.get(
147                                    servletContextName);
148    
149                            return servletContext.getContextPath();
150                    }
151    
152                    return StringPool.SLASH.concat(servletContextName);
153            }
154    
155            @Override
156            public String getCssPath() {
157                    return _cssPath;
158            }
159    
160            @Override
161            public String getDevice() {
162                    if (isWapTheme()) {
163                            return "wap";
164                    }
165                    else {
166                            return "regular";
167                    }
168            }
169    
170            @Override
171            public String getFreeMarkerTemplateLoader() {
172                    if (_loadFromServletContext) {
173                            return TemplateConstants.SERVLET_SEPARATOR;
174                    }
175                    else {
176                            return TemplateConstants.THEME_LOADER_SEPARATOR;
177                    }
178            }
179    
180            @Override
181            public String getImagesPath() {
182                    return _imagesPath;
183            }
184    
185            @Override
186            public String getJavaScriptPath() {
187                    return _javaScriptPath;
188            }
189    
190            @Override
191            public boolean getLoadFromServletContext() {
192                    return _loadFromServletContext;
193            }
194    
195            @Override
196            public String getName() {
197                    return _name;
198            }
199    
200            @Override
201            public String getPluginId() {
202                    return getThemeId();
203            }
204    
205            @Override
206            public String getPluginType() {
207                    return Plugin.TYPE_THEME;
208            }
209    
210            @Override
211            public List<PortletDecorator> getPortletDecorators() {
212                    List<PortletDecorator> portletDecorators = ListUtil.fromMapValues(
213                            _portletDecoratorsMap);
214    
215                    return ListUtil.sort(portletDecorators);
216            }
217    
218            @Override
219            public Map<String, PortletDecorator> getPortletDecoratorsMap() {
220                    return _portletDecoratorsMap;
221            }
222    
223            @Override
224            public String getResourcePath(
225                    ServletContext servletContext, String portletId, String path) {
226    
227                    if (!PropsValues.LAYOUT_TEMPLATE_CACHE_ENABLED) {
228                            return ThemeHelper.getResourcePath(
229                                    servletContext, this, portletId, path);
230                    }
231    
232                    String key = path;
233    
234                    if (Validator.isNotNull(portletId)) {
235                            key = path.concat(StringPool.POUND).concat(portletId);
236                    }
237    
238                    String resourcePath = _resourcePathsMap.get(key);
239    
240                    if (resourcePath != null) {
241                            return resourcePath;
242                    }
243    
244                    resourcePath = ThemeHelper.getResourcePath(
245                            servletContext, this, portletId, path);
246    
247                    _resourcePathsMap.put(key, resourcePath);
248    
249                    return resourcePath;
250            }
251    
252            @Override
253            public String getRootPath() {
254                    return _rootPath;
255            }
256    
257            @Override
258            public String getServletContextName() {
259                    return _servletContextName;
260            }
261    
262            @Override
263            public String getSetting(String key) {
264                    String value = null;
265    
266                    ThemeSetting themeSetting = _themeSettingsMap.get(key);
267    
268                    if (themeSetting != null) {
269                            value = themeSetting.getValue();
270                    }
271    
272                    return value;
273            }
274    
275            @Override
276            public String[] getSettingOptions(String key) {
277                    String[] options = null;
278    
279                    ThemeSetting themeSetting = _themeSettingsMap.get(key);
280    
281                    if (themeSetting != null) {
282                            options = themeSetting.getOptions();
283                    }
284    
285                    return options;
286            }
287    
288            @Override
289            public Map<String, ThemeSetting> getSettings() {
290                    return _themeSettingsMap;
291            }
292    
293            @Override
294            public Properties getSettingsProperties() {
295                    Properties properties = new Properties();
296    
297                    for (String key : _themeSettingsMap.keySet()) {
298                            ThemeSetting setting = _themeSettingsMap.get(key);
299    
300                            if (setting != null) {
301                                    properties.setProperty(key, setting.getValue());
302                            }
303                    }
304    
305                    return properties;
306            }
307    
308            @Override
309            public SpriteImage getSpriteImage(String fileName) {
310                    return _spriteImagesMap.get(fileName);
311            }
312    
313            @Override
314            public String getStaticResourcePath() {
315                    String proxyPath = PortalUtil.getPathProxy();
316    
317                    String virtualPath = getVirtualPath();
318    
319                    if (Validator.isNotNull(virtualPath)) {
320                            return proxyPath.concat(virtualPath);
321                    }
322    
323                    if (isWARFile()) {
324                            return getContextPath();
325                    }
326    
327                    String contextPath = null;
328    
329                    if (_themeId.equals("admin")) {
330                            contextPath = PortalWebResourcesUtil.getContextPath(
331                                    PortalWebResourceConstants.RESOURCE_TYPE_THEME_ADMIN);
332                    }
333                    else if (_themeId.equals("classic")) {
334                            contextPath = PortalWebResourcesUtil.getContextPath(
335                                    PortalWebResourceConstants.RESOURCE_TYPE_THEME_CLASSIC);
336                    }
337    
338                    if (Validator.isNull(contextPath)) {
339                            return proxyPath;
340                    }
341    
342                    return proxyPath.concat(contextPath);
343            }
344    
345            @Override
346            public String getTemplateExtension() {
347                    return _templateExtension;
348            }
349    
350            @Override
351            public String getTemplatesPath() {
352                    return _templatesPath;
353            }
354    
355            @Override
356            public ThemeCompanyLimit getThemeCompanyLimit() {
357                    return _themeCompanyLimit;
358            }
359    
360            @Override
361            public ThemeGroupLimit getThemeGroupLimit() {
362                    return _themeGroupLimit;
363            }
364    
365            @Override
366            public String getThemeId() {
367                    return _themeId;
368            }
369    
370            @Override
371            public long getTimestamp() {
372                    return _timestamp;
373            }
374    
375            @Override
376            public String getVelocityResourceListener() {
377                    if (_loadFromServletContext) {
378                            return TemplateConstants.SERVLET_SEPARATOR;
379                    }
380                    else {
381                            return TemplateConstants.THEME_LOADER_SEPARATOR;
382                    }
383            }
384    
385            @Override
386            public String getVirtualPath() {
387                    return _virtualPath;
388            }
389    
390            @Override
391            public boolean getWapTheme() {
392                    return _wapTheme;
393            }
394    
395            @Override
396            public boolean getWARFile() {
397                    return _warFile;
398            }
399    
400            @Override
401            public boolean hasColorSchemes() {
402                    if (!_colorSchemesMap.isEmpty()) {
403                            return true;
404                    }
405                    else {
406                            return false;
407                    }
408            }
409    
410            @Override
411            public int hashCode() {
412                    return _themeId.hashCode();
413            }
414    
415            @Override
416            public boolean isCompanyAvailable(long companyId) {
417                    return isAvailable(getThemeCompanyLimit(), companyId);
418            }
419    
420            @Override
421            public boolean isControlPanelTheme() {
422                    return _controlPanelTheme;
423            }
424    
425            @Override
426            public boolean isGroupAvailable(long groupId) {
427                    return isAvailable(getThemeGroupLimit(), groupId);
428            }
429    
430            @Override
431            public boolean isLoadFromServletContext() {
432                    return _loadFromServletContext;
433            }
434    
435            @Override
436            public boolean isPageTheme() {
437                    return _pageTheme;
438            }
439    
440            @Override
441            public boolean isWapTheme() {
442                    return _wapTheme;
443            }
444    
445            @Override
446            public boolean isWARFile() {
447                    return _warFile;
448            }
449    
450            @Override
451            public boolean resourceExists(
452                            ServletContext servletContext, String portletId, String path)
453                    throws Exception {
454    
455                    if (!PropsValues.LAYOUT_TEMPLATE_CACHE_ENABLED) {
456                            return ThemeHelper.resourceExists(
457                                    servletContext, this, portletId, path);
458                    }
459    
460                    if (Validator.isNull(path)) {
461                            return false;
462                    }
463    
464                    String key = path;
465    
466                    if (Validator.isNotNull(portletId)) {
467                            key = path.concat(StringPool.POUND).concat(portletId);
468                    }
469    
470                    Boolean resourceExists = _resourceExistsMap.get(key);
471    
472                    if (resourceExists != null) {
473                            return resourceExists;
474                    }
475    
476                    resourceExists = ThemeHelper.resourceExists(
477                            servletContext, this, portletId, path);
478    
479                    _resourceExistsMap.put(key, resourceExists);
480    
481                    return resourceExists;
482            }
483    
484            @Override
485            public void setControlPanelTheme(boolean controlPanelTheme) {
486                    _controlPanelTheme = controlPanelTheme;
487            }
488    
489            @Override
490            public void setCssPath(String cssPath) {
491                    _cssPath = cssPath;
492            }
493    
494            @Override
495            public void setImagesPath(String imagesPath) {
496                    _imagesPath = imagesPath;
497            }
498    
499            @Override
500            public void setJavaScriptPath(String javaScriptPath) {
501                    _javaScriptPath = javaScriptPath;
502            }
503    
504            @Override
505            public void setLoadFromServletContext(boolean loadFromServletContext) {
506                    _loadFromServletContext = loadFromServletContext;
507            }
508    
509            @Override
510            public void setName(String name) {
511                    _name = name;
512            }
513    
514            @Override
515            public void setPageTheme(boolean pageTheme) {
516                    _pageTheme = pageTheme;
517            }
518    
519            @Override
520            public void setRootPath(String rootPath) {
521                    _rootPath = rootPath;
522            }
523    
524            @Override
525            public void setServletContextName(String servletContextName) {
526                    _servletContextName = servletContextName;
527    
528                    if (Validator.isNotNull(_servletContextName)) {
529                            _warFile = true;
530                    }
531                    else {
532                            _warFile = false;
533                    }
534            }
535    
536            @Override
537            public void setSetting(String key, String value) {
538                    ThemeSetting themeSetting = _themeSettingsMap.get(key);
539    
540                    if (themeSetting != null) {
541                            themeSetting.setValue(value);
542                    }
543                    else {
544                            addSetting(key, value, false, null, null, null);
545                    }
546            }
547    
548            @Override
549            public void setSpriteImages(
550                    String spriteFileName, Properties spriteProperties) {
551    
552                    for (Map.Entry<Object, Object> entry : spriteProperties.entrySet()) {
553                            String key = (String)entry.getKey();
554                            String value = (String)entry.getValue();
555    
556                            int[] values = StringUtil.split(value, 0);
557    
558                            int offset = values[0];
559                            int height = values[1];
560                            int width = values[2];
561    
562                            SpriteImage spriteImage = new SpriteImage(
563                                    spriteFileName, key, offset, height, width);
564    
565                            _spriteImagesMap.put(key, spriteImage);
566                    }
567            }
568    
569            @Override
570            public void setTemplateExtension(String templateExtension) {
571                    _templateExtension = templateExtension;
572            }
573    
574            @Override
575            public void setTemplatesPath(String templatesPath) {
576                    _templatesPath = templatesPath;
577            }
578    
579            @Override
580            public void setThemeCompanyLimit(ThemeCompanyLimit themeCompanyLimit) {
581                    _themeCompanyLimit = themeCompanyLimit;
582            }
583    
584            @Override
585            public void setThemeGroupLimit(ThemeGroupLimit themeGroupLimit) {
586                    _themeGroupLimit = themeGroupLimit;
587            }
588    
589            @Override
590            public void setTimestamp(long timestamp) {
591                    _timestamp = timestamp;
592            }
593    
594            @Override
595            public void setVirtualPath(String virtualPath) {
596                    if (_warFile && Validator.isNull(virtualPath)) {
597                            virtualPath = PropsValues.THEME_VIRTUAL_PATH;
598                    }
599    
600                    _virtualPath = virtualPath;
601            }
602    
603            @Override
604            public void setWapTheme(boolean wapTheme) {
605                    _wapTheme = wapTheme;
606            }
607    
608            protected boolean isAvailable(ThemeCompanyLimit limit, long id) {
609                    boolean available = true;
610    
611                    if (_log.isDebugEnabled()) {
612                            _log.debug(
613                                    "Check if theme " + getThemeId() + " is available for " + id);
614                    }
615    
616                    if (limit != null) {
617                            List<ThemeCompanyId> includes = limit.getIncludes();
618                            List<ThemeCompanyId> excludes = limit.getExcludes();
619    
620                            if (!includes.isEmpty() && !excludes.isEmpty()) {
621    
622                                    // Since includes and excludes are specified, check to make sure
623                                    // the current company id is included and also not excluded
624    
625                                    if (_log.isDebugEnabled()) {
626                                            _log.debug("Check includes and excludes");
627                                    }
628    
629                                    available = limit.isIncluded(id);
630    
631                                    if (available) {
632                                            available = !limit.isExcluded(id);
633                                    }
634                            }
635                            else if (includes.isEmpty() && !excludes.isEmpty()) {
636    
637                                    // Since no includes are specified, check to make sure the
638                                    // current company id is not excluded
639    
640                                    if (_log.isDebugEnabled()) {
641                                            _log.debug("Check excludes");
642                                    }
643    
644                                    available = !limit.isExcluded(id);
645                            }
646                            else if (!includes.isEmpty() && excludes.isEmpty()) {
647    
648                                    // Since no excludes are specified, check to make sure the
649                                    // current company id is included
650    
651                                    if (_log.isDebugEnabled()) {
652                                            _log.debug("Check includes");
653                                    }
654    
655                                    available = limit.isIncluded(id);
656                            }
657                            else {
658    
659                                    // Since no includes or excludes are specified, this theme is
660                                    // available for every company
661    
662                                    if (_log.isDebugEnabled()) {
663                                            _log.debug("No includes or excludes set");
664                                    }
665    
666                                    available = true;
667                            }
668                    }
669    
670                    if (_log.isDebugEnabled()) {
671                            _log.debug(
672                                    "Theme " + getThemeId() + " is " +
673                                            (!available ? "NOT " : "") + "available for " + id);
674                    }
675    
676                    return available;
677            }
678    
679            private static final Log _log = LogFactoryUtil.getLog(ThemeImpl.class);
680    
681            private final Map<String, ColorScheme> _colorSchemesMap = new HashMap<>();
682            private boolean _controlPanelTheme;
683            private String _cssPath = "${root-path}/css";
684            private String _imagesPath = "${root-path}/images";
685            private String _javaScriptPath = "${root-path}/js";
686            private boolean _loadFromServletContext;
687            private String _name;
688            private boolean _pageTheme;
689            private final Map<String, PortletDecorator> _portletDecoratorsMap =
690                    new HashMap<>();
691            private final Map<String, Boolean> _resourceExistsMap =
692                    new ConcurrentHashMap<>();
693            private final Map<String, String> _resourcePathsMap =
694                    new ConcurrentHashMap<>();
695            private String _rootPath = "/";
696            private String _servletContextName = StringPool.BLANK;
697            private final Map<String, SpriteImage> _spriteImagesMap = new HashMap<>();
698            private String _templateExtension = "ftl";
699            private String _templatesPath = "${root-path}/templates";
700            private ThemeCompanyLimit _themeCompanyLimit;
701            private ThemeGroupLimit _themeGroupLimit;
702            private final String _themeId;
703            private final Map<String, ThemeSetting> _themeSettingsMap =
704                    new LinkedHashMap<>();
705            private long _timestamp;
706            private String _virtualPath = StringPool.BLANK;
707            private boolean _wapTheme;
708            private boolean _warFile;
709    
710    }