001: /*
002: * (C) Copyright 2006 Nabh Information Systems, Inc.
003: *
004: * This program is free software; you can redistribute it and/or
005: * modify it under the terms of the GNU General Public License
006: * as published by the Free Software Foundation; either version 2
007: * of the License, or (at your option) any later version.
008: *
009: * This program is distributed in the hope that it will be useful,
010: * but WITHOUT ANY WARRANTY; without even the implied warranty of
011: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
012: * GNU General Public License for more details.
013: *
014: * You should have received a copy of the GNU General Public License
015: * along with this program; if not, write to the Free Software
016: * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
017: *
018: */
019: package com.nabhinc.portal.core;
020:
021: import java.io.InputStream;
022: import java.util.Hashtable;
023: import java.util.Iterator;
024: import java.util.Properties;
025: import java.util.StringTokenizer;
026: import java.util.Vector;
027:
028: import javax.servlet.ServletConfig;
029: import javax.servlet.ServletContext;
030: import javax.servlet.ServletException;
031:
032: import org.apache.commons.logging.Log;
033: import org.apache.commons.logging.LogFactory;
034:
035: import com.nabhinc.portal.model.PortalConfiguration;
036: import com.nabhinc.portlet.mvcportlet.core.ValueAndLabel;
037: import com.nabhinc.util.IOUtil;
038:
039: /**
040: *
041: *
042: * @author Padmanabh Dabke
043: * (c) 2006 Nabh Information Systems, Inc. All Rights Reserved.
044: */
045: public class ThemeManager {
046: public static final String DEFAULT_PORTAL_STYLE_FILENAME = "portal.css";
047: public static final String THEME_INFO_FILE_NAME = "theme.properties";
048: public static final String THEME_LABEL_PROPERTY = "theme.label";
049: private static Log tmLogger = LogFactory.getLog(ThemeManager.class);
050: /**
051: * Theme metadata needed in personalization.
052: */
053: private static ThemeInfo[] tmThemeInfo = null;
054: private static ValueAndLabel[] tmThemeOptions = null;
055:
056: public static class ThemeInfo {
057: public String id = null;
058: public String name = null;
059:
060: public ThemeInfo() {
061: super ();
062: }
063:
064: public ThemeInfo(String i, String nm) {
065: id = i;
066: name = nm;
067: }
068: }
069:
070: public static ThemeInfo[] getThemeInfos() {
071: return tmThemeInfo;
072: }
073:
074: public static ValueAndLabel[] getThemeOptions() {
075: return tmThemeOptions;
076: }
077:
078: @SuppressWarnings("unchecked")
079: protected static void init(ServletConfig config)
080: throws ServletException {
081:
082: try {
083: String themesDir = PortalConfiguration.getInstance()
084: .getThemesDir();
085: ServletContext sContext = config.getServletContext();
086: Iterator themeDirs = sContext.getResourcePaths(themesDir)
087: .iterator(); // cssDir.list();
088: Vector themeVec = new Vector();
089: while (themeDirs.hasNext()) {
090: String themeDirResource = (String) themeDirs.next();
091: String themeName = themeDirResource.substring(themesDir
092: .length() + 1, themeDirResource.length() - 1);
093: InputStream is = sContext
094: .getResourceAsStream(themeDirResource
095: + ThemeManager.THEME_INFO_FILE_NAME);
096: if (is != null) {
097: Properties themeProps = new Properties();
098: themeProps.load(is);
099: String themeLabel = themeProps
100: .getProperty(THEME_LABEL_PROPERTY);
101: if (themeLabel == null) {
102: throw new ServletException(
103: "Property file for theme " + themeName
104: + " does not define "
105: + THEME_LABEL_PROPERTY + ".");
106: }
107: ThemeInfo themeInfo = new ThemeInfo(themeName,
108: themeLabel);
109: themeVec.add(themeInfo);
110: continue;
111: }
112: sContext.getResourceAsStream(themeDirResource
113: + ThemeManager.DEFAULT_PORTAL_STYLE_FILENAME);
114: if (is == null)
115: continue;
116: Hashtable themeTable = new Hashtable();
117: String cssStr = IOUtil.getInputStreamContentAsString(
118: is, "UTF-8");
119: is.close();
120: StringTokenizer st = new StringTokenizer(cssStr, "{}");
121:
122: while (st.hasMoreElements()) {
123: try {
124: String currentToken = st.nextToken();
125: if (currentToken != null) {
126: currentToken = currentToken.trim();
127: if (!currentToken.equals("")) {
128: String styleName = filterStyleName(currentToken);
129: if ("".equals(styleName))
130: continue; // only found comments
131:
132: if (styleName.charAt(0) == '.')
133: styleName = styleName.substring(1);
134: String styleSpec = st.nextToken();
135: if (styleSpec == null
136: || styleSpec.trim().equals("")) {
137: continue;
138: //styleSpec = st.nextToken();
139: }
140:
141: StringTokenizer st2 = new StringTokenizer(
142: styleSpec, ";");
143: Hashtable styleTable = new Hashtable();
144: while (st2.hasMoreTokens()) {
145: String attrSpec = st2.nextToken();
146: if (attrSpec == null
147: || attrSpec.trim().equals(
148: ""))
149: continue;
150: attrSpec = attrSpec.trim();
151: // filtering the multiple lines comment
152: if (attrSpec.startsWith("/*")) {
153: int index = attrSpec
154: .indexOf("*/");
155: if (index < 0) {
156: throw new Exception(
157: "Malformed stylesheet spec: "
158: + "theme = "
159: + themeName
160: + ": Missing comment close tag */.");
161: }
162: if (index == attrSpec.length() - 2)
163: continue;
164: attrSpec = attrSpec
165: .substring(index + 2);
166: }
167: int colonIndex = attrSpec
168: .indexOf(':');
169: if (colonIndex < 0) {
170: throw new Exception(
171: "Malformed stylesheet spec: "
172: + "theme = "
173: + themeName
174: + " style = "
175: + styleName);
176: }
177: String attrValue = attrSpec
178: .substring(colonIndex + 1)
179: .trim();
180: if (attrValue.endsWith("px"))
181: attrValue = attrValue
182: .substring(
183: 0,
184: attrValue
185: .length() - 2)
186: .trim();
187: styleTable.put(attrSpec.substring(
188: 0, colonIndex).trim()
189: .toUpperCase(), attrValue);
190: }
191: themeTable.put(styleName.trim()
192: .toUpperCase(), styleTable);
193: }
194: }
195: } catch (Exception ex) {
196: // Ignoring CSS files malformed since they do not affect the portal functionality
197: // at this time. Just log as warning.
198: tmLogger.warn(ex.getMessage());
199: }
200: }
201:
202: // psThemes.put(themeName, themeTable);
203:
204: String themeLabel = null;
205: Hashtable themeInfoTable = (Hashtable) themeTable
206: .get("THEMEINFO");
207: if (themeInfoTable != null)
208: themeLabel = (String) themeInfoTable.get("NAME");
209: if (themeLabel == null)
210: themeLabel = themeName;
211: // psThemeInfo[i] = new ThemeInfo(themeName, themeLabel);
212: themeVec.add(new ThemeInfo(themeName, themeLabel));
213: tmLogger.info("Created theme: " + themeName);
214:
215: }
216: tmThemeInfo = new ThemeInfo[themeVec.size()];
217: themeVec.copyInto(tmThemeInfo);
218: computeThemeOptions();
219: } catch (Exception ex) {
220: ex.printStackTrace();
221: throw new ServletException(
222: "Encountered exception while constructing portal themes: "
223: + ex.getMessage(), ex);
224: }
225: }
226:
227: private static String filterStyleName(String styleName) {
228: // multiple lines slash-star comments
229: if (styleName.startsWith("/*")) {
230: int endOfComment = styleName.indexOf("*/");
231: styleName = styleName.substring(endOfComment + 2).trim();
232:
233: }
234:
235: // # is not a valid css comment
236: /*
237: if (styleName.startsWith("#")) {
238: // verify if multiple rows comment
239: int lastIndex = styleName.lastIndexOf("\n#");
240: if (lastIndex != -1)
241: styleName = styleName.substring(styleName.indexOf ("\n", lastIndex + 1) + 1).trim();
242: else
243: styleName = styleName.substring(styleName.indexOf("\n") + 1).trim();
244: }
245: */
246:
247: // one line slash-slash comments
248: if (styleName.startsWith("//")) {
249: int lastIndex = styleName.lastIndexOf("\n//");
250: if (lastIndex != -1)
251: styleName = styleName.substring(
252: styleName.indexOf("\n", lastIndex + 1) + 1)
253: .trim();
254: else
255: styleName = styleName.substring(
256: styleName.indexOf("\n") + 1).trim();
257: }
258:
259: return styleName;
260: }
261:
262: private static void computeThemeOptions() {
263: tmThemeOptions = new ValueAndLabel[tmThemeInfo.length];
264: for (int i = 0; i < tmThemeOptions.length; i++) {
265: tmThemeOptions[i] = new ValueAndLabel(tmThemeInfo[i].id,
266: tmThemeInfo[i].name);
267: }
268:
269: }
270:
271: }
|