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.ServletContextPool;
020    import com.liferay.portal.kernel.template.TemplateConstants;
021    import com.liferay.portal.kernel.util.ContextPathUtil;
022    import com.liferay.portal.kernel.util.ListUtil;
023    import com.liferay.portal.kernel.util.StringPool;
024    import com.liferay.portal.kernel.util.StringUtil;
025    import com.liferay.portal.kernel.util.ThemeHelper;
026    import com.liferay.portal.kernel.util.Validator;
027    import com.liferay.portal.model.ColorScheme;
028    import com.liferay.portal.model.Plugin;
029    import com.liferay.portal.model.SpriteImage;
030    import com.liferay.portal.model.Theme;
031    import com.liferay.portal.model.ThemeSetting;
032    import com.liferay.portal.theme.ThemeCompanyId;
033    import com.liferay.portal.theme.ThemeCompanyLimit;
034    import com.liferay.portal.theme.ThemeGroupLimit;
035    import com.liferay.portal.util.PortalUtil;
036    import com.liferay.portal.util.PropsValues;
037    
038    import java.util.HashMap;
039    import java.util.LinkedHashMap;
040    import java.util.List;
041    import java.util.Map;
042    import java.util.Properties;
043    import java.util.concurrent.ConcurrentHashMap;
044    
045    import javax.servlet.ServletContext;
046    
047    /**
048     * @author Brian Wing Shun Chan
049     * @author Julio Camarero
050     * @author Raymond Aug??
051     */
052    public class ThemeImpl extends PluginBaseImpl implements Theme {
053    
054            public ThemeImpl() {
055                    this(null);
056            }
057    
058            public ThemeImpl(String themeId) {
059                    this(themeId, null);
060            }
061    
062            public ThemeImpl(String themeId, String name) {
063                    _themeId = themeId;
064                    _name = name;
065            }
066    
067            @Override
068            public void addSetting(
069                    String key, String value, boolean configurable, String type,
070                    String[] options, String script) {
071    
072                    ThemeSetting themeSetting = new ThemeSettingImpl(
073                            configurable, options, script, type, value);
074    
075                    _themeSettingsMap.put(key, themeSetting);
076            }
077    
078            @Override
079            public int compareTo(Theme theme) {
080                    return getName().compareTo(theme.getName());
081            }
082    
083            @Override
084            public boolean equals(Object obj) {
085                    if (this == obj) {
086                            return true;
087                    }
088    
089                    if (!(obj instanceof Theme)) {
090                            return false;
091                    }
092    
093                    Theme theme = (Theme)obj;
094    
095                    String themeId = theme.getThemeId();
096    
097                    if (getThemeId().equals(themeId)) {
098                            return true;
099                    }
100                    else {
101                            return false;
102                    }
103            }
104    
105            @Override
106            public List<ColorScheme> getColorSchemes() {
107                    List<ColorScheme> colorSchemes = ListUtil.fromMapValues(
108                            _colorSchemesMap);
109    
110                    return ListUtil.sort(colorSchemes);
111            }
112    
113            @Override
114            public Map<String, ColorScheme> getColorSchemesMap() {
115                    return _colorSchemesMap;
116            }
117    
118            @Override
119            public Map<String, ThemeSetting> getConfigurableSettings() {
120                    Map<String, ThemeSetting> configurableSettings =
121                            new LinkedHashMap<String, ThemeSetting>();
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 ContextPathUtil.getContextPath(servletContext);
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 = getContextPath();
310    
311                    if (!isWARFile()) {
312                            return contextPath;
313                    }
314    
315                    return proxyPath.concat(contextPath);
316            }
317    
318            @Override
319            public String getTemplateExtension() {
320                    return _templateExtension;
321            }
322    
323            @Override
324            public String getTemplatesPath() {
325                    return _templatesPath;
326            }
327    
328            @Override
329            public ThemeCompanyLimit getThemeCompanyLimit() {
330                    return _themeCompanyLimit;
331            }
332    
333            @Override
334            public ThemeGroupLimit getThemeGroupLimit() {
335                    return _themeGroupLimit;
336            }
337    
338            @Override
339            public String getThemeId() {
340                    return _themeId;
341            }
342    
343            @Override
344            public long getTimestamp() {
345                    return _timestamp;
346            }
347    
348            @Override
349            public String getVelocityResourceListener() {
350                    if (_loadFromServletContext) {
351                            return TemplateConstants.SERVLET_SEPARATOR;
352                    }
353                    else {
354                            return TemplateConstants.THEME_LOADER_SEPARATOR;
355                    }
356            }
357    
358            @Override
359            public String getVirtualPath() {
360                    return _virtualPath;
361            }
362    
363            @Override
364            public boolean getWapTheme() {
365                    return _wapTheme;
366            }
367    
368            @Override
369            public boolean getWARFile() {
370                    return _warFile;
371            }
372    
373            @Override
374            public boolean hasColorSchemes() {
375                    if (!_colorSchemesMap.isEmpty()) {
376                            return true;
377                    }
378                    else {
379                            return false;
380                    }
381            }
382    
383            @Override
384            public int hashCode() {
385                    return _themeId.hashCode();
386            }
387    
388            @Override
389            public boolean isCompanyAvailable(long companyId) {
390                    return isAvailable(getThemeCompanyLimit(), companyId);
391            }
392    
393            @Override
394            public boolean isControlPanelTheme() {
395                    return _controlPanelTheme;
396            }
397    
398            @Override
399            public boolean isGroupAvailable(long groupId) {
400                    return isAvailable(getThemeGroupLimit(), groupId);
401            }
402    
403            @Override
404            public boolean isLoadFromServletContext() {
405                    return _loadFromServletContext;
406            }
407    
408            @Override
409            public boolean isPageTheme() {
410                    return _pageTheme;
411            }
412    
413            @Override
414            public boolean isWapTheme() {
415                    return _wapTheme;
416            }
417    
418            @Override
419            public boolean isWARFile() {
420                    return _warFile;
421            }
422    
423            @Override
424            public boolean resourceExists(
425                            ServletContext servletContext, String portletId, String path)
426                    throws Exception {
427    
428                    if (!PropsValues.LAYOUT_TEMPLATE_CACHE_ENABLED) {
429                            return ThemeHelper.resourceExists(
430                                    servletContext, this, portletId, path);
431                    }
432    
433                    if (Validator.isNull(path)) {
434                            return false;
435                    }
436    
437                    String key = path;
438    
439                    if (Validator.isNotNull(portletId)) {
440                            key = path.concat(StringPool.POUND).concat(portletId);
441                    }
442    
443                    Boolean resourceExists = _resourceExistsMap.get(key);
444    
445                    if (resourceExists != null) {
446                            return resourceExists;
447                    }
448    
449                    resourceExists = ThemeHelper.resourceExists(
450                            servletContext, this, portletId, path);
451    
452                    _resourceExistsMap.put(key, resourceExists);
453    
454                    return resourceExists;
455            }
456    
457            @Override
458            public void setControlPanelTheme(boolean controlPanelTheme) {
459                    _controlPanelTheme = controlPanelTheme;
460            }
461    
462            @Override
463            public void setCssPath(String cssPath) {
464                    _cssPath = cssPath;
465            }
466    
467            @Override
468            public void setImagesPath(String imagesPath) {
469                    _imagesPath = imagesPath;
470            }
471    
472            @Override
473            public void setJavaScriptPath(String javaScriptPath) {
474                    _javaScriptPath = javaScriptPath;
475            }
476    
477            @Override
478            public void setLoadFromServletContext(boolean loadFromServletContext) {
479                    _loadFromServletContext = loadFromServletContext;
480            }
481    
482            @Override
483            public void setName(String name) {
484                    _name = name;
485            }
486    
487            @Override
488            public void setPageTheme(boolean pageTheme) {
489                    _pageTheme = pageTheme;
490            }
491    
492            @Override
493            public void setRootPath(String rootPath) {
494                    _rootPath = rootPath;
495            }
496    
497            @Override
498            public void setServletContextName(String servletContextName) {
499                    _servletContextName = servletContextName;
500    
501                    if (Validator.isNotNull(_servletContextName)) {
502                            _warFile = true;
503                    }
504                    else {
505                            _warFile = false;
506                    }
507            }
508    
509            @Override
510            public void setSetting(String key, String value) {
511                    ThemeSetting themeSetting = _themeSettingsMap.get(key);
512    
513                    if (themeSetting != null) {
514                            themeSetting.setValue(value);
515                    }
516                    else {
517                            addSetting(key, value, false, null, null, null);
518                    }
519            }
520    
521            @Override
522            public void setSpriteImages(
523                    String spriteFileName, Properties spriteProperties) {
524    
525                    for (Map.Entry<Object, Object> entry : spriteProperties.entrySet()) {
526                            String key = (String)entry.getKey();
527                            String value = (String)entry.getValue();
528    
529                            int[] values = StringUtil.split(value, 0);
530    
531                            int offset = values[0];
532                            int height = values[1];
533                            int width = values[2];
534    
535                            SpriteImage spriteImage = new SpriteImage(
536                                    spriteFileName, key, offset, height, width);
537    
538                            _spriteImagesMap.put(key, spriteImage);
539                    }
540            }
541    
542            @Override
543            public void setTemplateExtension(String templateExtension) {
544                    _templateExtension = templateExtension;
545            }
546    
547            @Override
548            public void setTemplatesPath(String templatesPath) {
549                    _templatesPath = templatesPath;
550            }
551    
552            @Override
553            public void setThemeCompanyLimit(ThemeCompanyLimit themeCompanyLimit) {
554                    _themeCompanyLimit = themeCompanyLimit;
555            }
556    
557            @Override
558            public void setThemeGroupLimit(ThemeGroupLimit themeGroupLimit) {
559                    _themeGroupLimit = themeGroupLimit;
560            }
561    
562            @Override
563            public void setTimestamp(long timestamp) {
564                    _timestamp = timestamp;
565            }
566    
567            @Override
568            public void setVirtualPath(String virtualPath) {
569                    if (_warFile && Validator.isNull(virtualPath)) {
570                            virtualPath = PropsValues.THEME_VIRTUAL_PATH;
571                    }
572    
573                    _virtualPath = virtualPath;
574            }
575    
576            @Override
577            public void setWapTheme(boolean wapTheme) {
578                    _wapTheme = wapTheme;
579            }
580    
581            protected boolean isAvailable(ThemeCompanyLimit limit, long id) {
582                    boolean available = true;
583    
584                    if (_log.isDebugEnabled()) {
585                            _log.debug(
586                                    "Check if theme " + getThemeId() + " is available for " + id);
587                    }
588    
589                    if (limit != null) {
590                            List<ThemeCompanyId> includes = limit.getIncludes();
591                            List<ThemeCompanyId> excludes = limit.getExcludes();
592    
593                            if (!includes.isEmpty() && !excludes.isEmpty()) {
594    
595                                    // Since includes and excludes are specified, check to make sure
596                                    // the current company id is included and also not excluded
597    
598                                    if (_log.isDebugEnabled()) {
599                                            _log.debug("Check includes and excludes");
600                                    }
601    
602                                    available = limit.isIncluded(id);
603    
604                                    if (available) {
605                                            available = !limit.isExcluded(id);
606                                    }
607                            }
608                            else if (includes.isEmpty() && !excludes.isEmpty()) {
609    
610                                    // Since no includes are specified, check to make sure the
611                                    // current company id is not excluded
612    
613                                    if (_log.isDebugEnabled()) {
614                                            _log.debug("Check excludes");
615                                    }
616    
617                                    available = !limit.isExcluded(id);
618                            }
619                            else if (!includes.isEmpty() && excludes.isEmpty()) {
620    
621                                    // Since no excludes are specified, check to make sure the
622                                    // current company id is included
623    
624                                    if (_log.isDebugEnabled()) {
625                                            _log.debug("Check includes");
626                                    }
627    
628                                    available = limit.isIncluded(id);
629                            }
630                            else {
631    
632                                    // Since no includes or excludes are specified, this theme is
633                                    // available for every company
634    
635                                    if (_log.isDebugEnabled()) {
636                                            _log.debug("No includes or excludes set");
637                                    }
638    
639                                    available = true;
640                            }
641                    }
642    
643                    if (_log.isDebugEnabled()) {
644                            _log.debug(
645                                    "Theme " + getThemeId() + " is " +
646                                            (!available ? "NOT " : "") + "available for " + id);
647                    }
648    
649                    return available;
650            }
651    
652            private static final Log _log = LogFactoryUtil.getLog(ThemeImpl.class);
653    
654            private final Map<String, ColorScheme> _colorSchemesMap =
655                    new HashMap<String, ColorScheme>();
656            private boolean _controlPanelTheme;
657            private String _cssPath = "${root-path}/css";
658            private String _imagesPath = "${root-path}/images";
659            private String _javaScriptPath = "${root-path}/js";
660            private boolean _loadFromServletContext;
661            private String _name;
662            private boolean _pageTheme;
663            private final Map<String, Boolean> _resourceExistsMap =
664                    new ConcurrentHashMap<String, Boolean>();
665            private final Map<String, String> _resourcePathsMap =
666                    new ConcurrentHashMap<String, String>();
667            private String _rootPath = "/";
668            private String _servletContextName = StringPool.BLANK;
669            private final Map<String, SpriteImage> _spriteImagesMap =
670                    new HashMap<String, SpriteImage>();
671            private String _templateExtension = "vm";
672            private String _templatesPath = "${root-path}/templates";
673            private ThemeCompanyLimit _themeCompanyLimit;
674            private ThemeGroupLimit _themeGroupLimit;
675            private final String _themeId;
676            private final Map<String, ThemeSetting> _themeSettingsMap =
677                    new LinkedHashMap<String, ThemeSetting>();
678            private long _timestamp;
679            private String _virtualPath = StringPool.BLANK;
680            private boolean _wapTheme;
681            private boolean _warFile;
682    
683    }