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