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.model.ColorScheme;
020    import com.liferay.portal.kernel.model.Plugin;
021    import com.liferay.portal.kernel.model.PortletDecorator;
022    import com.liferay.portal.kernel.model.SpriteImage;
023    import com.liferay.portal.kernel.model.Theme;
024    import com.liferay.portal.kernel.model.ThemeSetting;
025    import com.liferay.portal.kernel.servlet.PortalWebResourceConstants;
026    import com.liferay.portal.kernel.servlet.PortalWebResourcesUtil;
027    import com.liferay.portal.kernel.servlet.ServletContextPool;
028    import com.liferay.portal.kernel.template.TemplateConstants;
029    import com.liferay.portal.kernel.theme.ThemeCompanyId;
030    import com.liferay.portal.kernel.theme.ThemeCompanyLimit;
031    import com.liferay.portal.kernel.theme.ThemeGroupLimit;
032    import com.liferay.portal.kernel.util.ListUtil;
033    import com.liferay.portal.kernel.util.PortalUtil;
034    import com.liferay.portal.kernel.util.StringPool;
035    import com.liferay.portal.kernel.util.StringUtil;
036    import com.liferay.portal.kernel.util.ThemeHelper;
037    import com.liferay.portal.kernel.util.Validator;
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                    String portalPathContext = PortalUtil.getPathContext();
146    
147                    if (ServletContextPool.containsKey(servletContextName)) {
148                            ServletContext servletContext = ServletContextPool.get(
149                                    servletContextName);
150    
151                            return portalPathContext.concat(servletContext.getContextPath());
152                    }
153    
154                    return portalPathContext.concat(
155                            StringPool.SLASH.concat(servletContextName));
156            }
157    
158            @Override
159            public String getCssPath() {
160                    return _cssPath;
161            }
162    
163            @Override
164            public String getDevice() {
165                    return "regular";
166            }
167    
168            @Override
169            public String getFreeMarkerTemplateLoader() {
170                    if (_loadFromServletContext) {
171                            return TemplateConstants.SERVLET_SEPARATOR;
172                    }
173                    else {
174                            return TemplateConstants.THEME_LOADER_SEPARATOR;
175                    }
176            }
177    
178            @Override
179            public String getImagesPath() {
180                    return _imagesPath;
181            }
182    
183            @Override
184            public String getJavaScriptPath() {
185                    return _javaScriptPath;
186            }
187    
188            @Override
189            public boolean getLoadFromServletContext() {
190                    return _loadFromServletContext;
191            }
192    
193            @Override
194            public String getName() {
195                    return _name;
196            }
197    
198            @Override
199            public String getPluginId() {
200                    return getThemeId();
201            }
202    
203            @Override
204            public String getPluginType() {
205                    return Plugin.TYPE_THEME;
206            }
207    
208            @Override
209            public List<PortletDecorator> getPortletDecorators() {
210                    List<PortletDecorator> portletDecorators = ListUtil.fromMapValues(
211                            _portletDecoratorsMap);
212    
213                    return ListUtil.sort(portletDecorators);
214            }
215    
216            @Override
217            public Map<String, PortletDecorator> getPortletDecoratorsMap() {
218                    return _portletDecoratorsMap;
219            }
220    
221            @Override
222            public String getResourcePath(
223                    ServletContext servletContext, String portletId, String path) {
224    
225                    if (!PropsValues.LAYOUT_TEMPLATE_CACHE_ENABLED) {
226                            return ThemeHelper.getResourcePath(
227                                    servletContext, this, portletId, path);
228                    }
229    
230                    String key = path;
231    
232                    if (Validator.isNotNull(portletId)) {
233                            key = path.concat(StringPool.POUND).concat(portletId);
234                    }
235    
236                    String resourcePath = _resourcePathsMap.get(key);
237    
238                    if (resourcePath != null) {
239                            return resourcePath;
240                    }
241    
242                    resourcePath = ThemeHelper.getResourcePath(
243                            servletContext, this, portletId, path);
244    
245                    _resourcePathsMap.put(key, resourcePath);
246    
247                    return resourcePath;
248            }
249    
250            @Override
251            public String getRootPath() {
252                    return _rootPath;
253            }
254    
255            @Override
256            public String getServletContextName() {
257                    return _servletContextName;
258            }
259    
260            @Override
261            public String getSetting(String key) {
262                    String value = null;
263    
264                    ThemeSetting themeSetting = _themeSettingsMap.get(key);
265    
266                    if (themeSetting != null) {
267                            value = themeSetting.getValue();
268                    }
269    
270                    return value;
271            }
272    
273            @Override
274            public String[] getSettingOptions(String key) {
275                    String[] options = null;
276    
277                    ThemeSetting themeSetting = _themeSettingsMap.get(key);
278    
279                    if (themeSetting != null) {
280                            options = themeSetting.getOptions();
281                    }
282    
283                    return options;
284            }
285    
286            @Override
287            public Map<String, ThemeSetting> getSettings() {
288                    return _themeSettingsMap;
289            }
290    
291            @Override
292            public Properties getSettingsProperties() {
293                    Properties properties = new Properties();
294    
295                    for (Map.Entry<String, ThemeSetting> entry :
296                                    _themeSettingsMap.entrySet()) {
297    
298                            ThemeSetting setting = entry.getValue();
299    
300                            if (setting != null) {
301                                    properties.setProperty(entry.getKey(), 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.getModuleContextPath(
331                                    PortalWebResourceConstants.RESOURCE_TYPE_THEME_ADMIN);
332                    }
333                    else if (_themeId.equals("classic")) {
334                            contextPath = PortalWebResourcesUtil.getModuleContextPath(
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 getWARFile() {
392                    return _warFile;
393            }
394    
395            @Override
396            public boolean hasColorSchemes() {
397                    if (!_colorSchemesMap.isEmpty()) {
398                            return true;
399                    }
400                    else {
401                            return false;
402                    }
403            }
404    
405            @Override
406            public int hashCode() {
407                    return _themeId.hashCode();
408            }
409    
410            @Override
411            public boolean isCompanyAvailable(long companyId) {
412                    return isAvailable(getThemeCompanyLimit(), companyId);
413            }
414    
415            @Override
416            public boolean isControlPanelTheme() {
417                    return _controlPanelTheme;
418            }
419    
420            @Override
421            public boolean isGroupAvailable(long groupId) {
422                    return isAvailable(getThemeGroupLimit(), groupId);
423            }
424    
425            @Override
426            public boolean isLoadFromServletContext() {
427                    return _loadFromServletContext;
428            }
429    
430            @Override
431            public boolean isPageTheme() {
432                    return _pageTheme;
433            }
434    
435            @Override
436            public boolean isWARFile() {
437                    return _warFile;
438            }
439    
440            @Override
441            public boolean resourceExists(
442                            ServletContext servletContext, String portletId, String path)
443                    throws Exception {
444    
445                    if (!PropsValues.LAYOUT_TEMPLATE_CACHE_ENABLED) {
446                            return ThemeHelper.resourceExists(
447                                    servletContext, this, portletId, path);
448                    }
449    
450                    if (Validator.isNull(path)) {
451                            return false;
452                    }
453    
454                    String key = path;
455    
456                    if (Validator.isNotNull(portletId)) {
457                            key = path.concat(StringPool.POUND).concat(portletId);
458                    }
459    
460                    Boolean resourceExists = _resourceExistsMap.get(key);
461    
462                    if (resourceExists != null) {
463                            return resourceExists;
464                    }
465    
466                    resourceExists = ThemeHelper.resourceExists(
467                            servletContext, this, portletId, path);
468    
469                    _resourceExistsMap.put(key, resourceExists);
470    
471                    return resourceExists;
472            }
473    
474            @Override
475            public void setControlPanelTheme(boolean controlPanelTheme) {
476                    _controlPanelTheme = controlPanelTheme;
477            }
478    
479            @Override
480            public void setCssPath(String cssPath) {
481                    _cssPath = cssPath;
482            }
483    
484            @Override
485            public void setImagesPath(String imagesPath) {
486                    _imagesPath = imagesPath;
487            }
488    
489            @Override
490            public void setJavaScriptPath(String javaScriptPath) {
491                    _javaScriptPath = javaScriptPath;
492            }
493    
494            @Override
495            public void setLoadFromServletContext(boolean loadFromServletContext) {
496                    _loadFromServletContext = loadFromServletContext;
497            }
498    
499            @Override
500            public void setName(String name) {
501                    _name = name;
502            }
503    
504            @Override
505            public void setPageTheme(boolean pageTheme) {
506                    _pageTheme = pageTheme;
507            }
508    
509            @Override
510            public void setRootPath(String rootPath) {
511                    _rootPath = rootPath;
512            }
513    
514            @Override
515            public void setServletContextName(String servletContextName) {
516                    _servletContextName = servletContextName;
517    
518                    if (Validator.isNotNull(_servletContextName)) {
519                            _warFile = true;
520                    }
521                    else {
522                            _warFile = false;
523                    }
524            }
525    
526            @Override
527            public void setSetting(String key, String value) {
528                    ThemeSetting themeSetting = _themeSettingsMap.get(key);
529    
530                    if (themeSetting != null) {
531                            themeSetting.setValue(value);
532                    }
533                    else {
534                            addSetting(key, value, false, null, null, null);
535                    }
536            }
537    
538            @Override
539            public void setSpriteImages(
540                    String spriteFileName, Properties spriteProperties) {
541    
542                    for (Map.Entry<Object, Object> entry : spriteProperties.entrySet()) {
543                            String key = (String)entry.getKey();
544                            String value = (String)entry.getValue();
545    
546                            int[] values = StringUtil.split(value, 0);
547    
548                            int offset = values[0];
549                            int height = values[1];
550                            int width = values[2];
551    
552                            SpriteImage spriteImage = new SpriteImage(
553                                    spriteFileName, key, offset, height, width);
554    
555                            _spriteImagesMap.put(key, spriteImage);
556                    }
557            }
558    
559            @Override
560            public void setTemplateExtension(String templateExtension) {
561                    _templateExtension = templateExtension;
562            }
563    
564            @Override
565            public void setTemplatesPath(String templatesPath) {
566                    _templatesPath = templatesPath;
567            }
568    
569            @Override
570            public void setThemeCompanyLimit(ThemeCompanyLimit themeCompanyLimit) {
571                    _themeCompanyLimit = themeCompanyLimit;
572            }
573    
574            @Override
575            public void setThemeGroupLimit(ThemeGroupLimit themeGroupLimit) {
576                    _themeGroupLimit = themeGroupLimit;
577            }
578    
579            @Override
580            public void setTimestamp(long timestamp) {
581                    _timestamp = timestamp;
582            }
583    
584            @Override
585            public void setVirtualPath(String virtualPath) {
586                    if (_warFile && Validator.isNull(virtualPath)) {
587                            virtualPath = PropsValues.THEME_VIRTUAL_PATH;
588                    }
589    
590                    _virtualPath = virtualPath;
591            }
592    
593            protected boolean isAvailable(ThemeCompanyLimit limit, long id) {
594                    boolean available = true;
595    
596                    if (_log.isDebugEnabled()) {
597                            _log.debug(
598                                    "Check if theme " + getThemeId() + " is available for " + id);
599                    }
600    
601                    if (limit != null) {
602                            List<ThemeCompanyId> includes = limit.getIncludes();
603                            List<ThemeCompanyId> excludes = limit.getExcludes();
604    
605                            if (!includes.isEmpty() && !excludes.isEmpty()) {
606    
607                                    // Since includes and excludes are specified, check to make sure
608                                    // the current company id is included and also not excluded
609    
610                                    if (_log.isDebugEnabled()) {
611                                            _log.debug("Check includes and excludes");
612                                    }
613    
614                                    available = limit.isIncluded(id);
615    
616                                    if (available) {
617                                            available = !limit.isExcluded(id);
618                                    }
619                            }
620                            else if (includes.isEmpty() && !excludes.isEmpty()) {
621    
622                                    // Since no includes are specified, check to make sure the
623                                    // current company id is not excluded
624    
625                                    if (_log.isDebugEnabled()) {
626                                            _log.debug("Check excludes");
627                                    }
628    
629                                    available = !limit.isExcluded(id);
630                            }
631                            else if (!includes.isEmpty() && excludes.isEmpty()) {
632    
633                                    // Since no excludes are specified, check to make sure the
634                                    // current company id is included
635    
636                                    if (_log.isDebugEnabled()) {
637                                            _log.debug("Check includes");
638                                    }
639    
640                                    available = limit.isIncluded(id);
641                            }
642                            else {
643    
644                                    // Since no includes or excludes are specified, this theme is
645                                    // available for every company
646    
647                                    if (_log.isDebugEnabled()) {
648                                            _log.debug("No includes or excludes set");
649                                    }
650    
651                                    available = true;
652                            }
653                    }
654    
655                    if (_log.isDebugEnabled()) {
656                            _log.debug(
657                                    "Theme " + getThemeId() + " is " + (!available ? "NOT " : "") +
658                                            "available for " + id);
659                    }
660    
661                    return available;
662            }
663    
664            private static final Log _log = LogFactoryUtil.getLog(ThemeImpl.class);
665    
666            private final Map<String, ColorScheme> _colorSchemesMap = new HashMap<>();
667            private boolean _controlPanelTheme;
668            private String _cssPath = "${root-path}/css";
669            private String _imagesPath = "${root-path}/images";
670            private String _javaScriptPath = "${root-path}/js";
671            private boolean _loadFromServletContext;
672            private String _name;
673            private boolean _pageTheme;
674            private final Map<String, PortletDecorator> _portletDecoratorsMap =
675                    new HashMap<>();
676            private final Map<String, Boolean> _resourceExistsMap =
677                    new ConcurrentHashMap<>();
678            private final Map<String, String> _resourcePathsMap =
679                    new ConcurrentHashMap<>();
680            private String _rootPath = "/";
681            private String _servletContextName = StringPool.BLANK;
682            private final Map<String, SpriteImage> _spriteImagesMap = new HashMap<>();
683            private String _templateExtension = "ftl";
684            private String _templatesPath = "${root-path}/templates";
685            private ThemeCompanyLimit _themeCompanyLimit;
686            private ThemeGroupLimit _themeGroupLimit;
687            private final String _themeId;
688            private final Map<String, ThemeSetting> _themeSettingsMap =
689                    new LinkedHashMap<>();
690            private long _timestamp;
691            private String _virtualPath = StringPool.BLANK;
692            private boolean _warFile;
693    
694    }