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