001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common
008: * Development and Distribution License("CDDL") (collectively, the
009: * "License"). You may not use this file except in compliance with the
010: * License. You can obtain a copy of the License at
011: * http://www.netbeans.org/cddl-gplv2.html
012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013: * specific language governing permissions and limitations under the
014: * License. When distributing the software, include this License Header
015: * Notice in each file and include the License file at
016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
017: * particular file as subject to the "Classpath" exception as provided
018: * by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the
020: * License Header, with the fields enclosed by brackets [] replaced by
021: * your own identifying information:
022: * "Portions Copyrighted [year] [name of copyright owner]"
023: *
024: * Contributor(s):
025: *
026: * The Original Software is NetBeans. The Initial Developer of the Original
027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun
028: * Microsystems, Inc. All Rights Reserved.
029: *
030: * If you wish your version of this file to be governed by only the CDDL
031: * or only the GPL Version 2, indicate your decision by adding
032: * "[Contributor] elects to include this software in this distribution
033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
034: * single choice of license, a recipient has the option to distribute
035: * your version of this file under either the CDDL, the GPL Version 2 or
036: * to extend the choice of license to its licensees as provided above.
037: * However, if you add GPL Version 2 code and therefore, elected the GPL
038: * Version 2 license, then the option applies only if the new code is
039: * made subject to such option by the copyright holder.
040: */
041: package com.sun.rave.web.ui.theme;
042:
043: import java.io.BufferedInputStream;
044: import java.io.BufferedOutputStream;
045: import java.io.InputStream;
046: import java.io.IOException;
047: import java.io.OutputStream;
048: import java.util.Date;
049: import java.util.HashMap;
050: import java.util.HashSet;
051: import java.util.Locale;
052: import java.util.Map;
053: import java.util.Set;
054:
055: import javax.servlet.ServletConfig;
056: import javax.servlet.ServletException;
057: import javax.servlet.http.HttpServlet;
058: import javax.servlet.http.HttpServletRequest;
059: import javax.servlet.http.HttpServletResponse;
060:
061: /**
062: * <p>Use this servlet to retrieve resource file
063: * that control the client-side behaviour and
064: * appearance of a web application that uses the
065: * Sun Web.Components. The resource files must
066: * be in a Jar file that is in the application's
067: * classpath. Configure one instance of this servlet
068: * per web application using themed components:
069: * <pre>
070: <servlet>
071: <servlet-name>ThemeServlet</servlet-name>
072: <servlet-class>com.sun.rave.web.ui.theme.ThemeServlet</servlet-class>
073: </servlet>
074:
075: <servlet-mapping>
076: <servlet-name>ThemeServlet</servlet-name>
077: <url-pattern>/theme/*</url-pattern>
078: </servlet-mapping>
079: </pre>
080: * <p>
081: *
082: * <p>For each theme used in an application, you must ensure that this
083: * servlet is mapped to the identifier specified in the "prefix" property
084: * of the <code>META-INF/swc_theme.properties</code> resource for that
085: * theme. For the standard themes, this is set to <code>/theme</code> so
086: * the mapping illustrated above is sufficient.</p>
087: *
088: * <p>Note that, since the JAR files for all installed themes are loaded
089: * into the same class loader, the actual resource paths for the resources
090: * used by each theme <strong>MUST</strong> be unique. This is true
091: * regardless of whether the themes share a prefix or not.</p>
092: *
093: * @author avk
094: */
095: public class ThemeServlet extends HttpServlet {
096:
097: public static final String localeParameter = "com.sun.rave.web.ui.locales";
098: private final static boolean DEBUG = false;
099: private final static Map respType = new HashMap();
100:
101: // Some mime-types... by extension
102: static {
103: // There is no IANA registered type for JS files. See
104: // http://annevankesteren.nl/archives/2005/02/javascript-mime-type
105: // for a discussion. I picked text/javascript because that's
106: // what we use in the script tag. Apache defaults to
107: // application/x-javascript
108: respType.put("js", "text/javascript");
109: respType.put("css", "text/css");
110: respType.put("htm", "text/html");
111: respType.put("html", "text/html");
112: respType.put("wml", "text/wml");
113: respType.put("txt", "text/plain");
114: respType.put("xml", "text/xml");
115: respType.put("jpeg", "image/jpeg");
116: respType.put("jpe", "image/jpeg");
117: respType.put("jpg", "image/jpeg");
118: respType.put("png", "image/png");
119: respType.put("tif", "image/tiff");
120: respType.put("tiff", "image/tiff");
121: respType.put("bmp", "image/bmp");
122: respType.put("xbm", "image/xbm");
123: respType.put("ico", "image/x-icon");
124: respType.put("gif", "image/gif");
125: respType.put("pdf", "application/pdf");
126: respType.put("ps", "application/postscript");
127: respType.put("mim", "application/mime");
128: respType.put("mime", "application/mime");
129: respType.put("mid", "application/midi");
130: respType.put("midi", "application/midi");
131: respType.put("wav", "audio/wav");
132: respType.put("bwf", "audio/wav");
133: respType.put("cpr", "image/cpr");
134: respType.put("avi", "video/x-msvideo");
135: respType.put("mpeg", "video/mpeg");
136: respType.put("mpg", "video/mpeg");
137: respType.put("mpm", "video/mpeg");
138: respType.put("mpv", "video/mpeg");
139: respType.put("mpa", "video/mpeg");
140: respType.put("au", "audio/basic");
141: respType.put("snd", "audio/basic");
142: respType.put("ulw", "audio/basic");
143: respType.put("aiff", "audio/x-aiff");
144: respType.put("aif", "audio/x-aiff");
145: respType.put("aifc", "audio/x-aiff");
146: respType.put("cdda", "audio/x-aiff");
147: respType.put("pict", "image/x-pict");
148: respType.put("pic", "image/x-pict");
149: respType.put("pct", "image/x-pict");
150: respType.put("mov", "video/quicktime");
151: respType.put("qt", "video/quicktime");
152: respType.put("pdf", "application/pdf");
153: respType.put("pdf", "application/pdf");
154: respType.put("ssm", "application/smil");
155: respType.put("rsml", "application/vnd.rn-rsml");
156: respType.put("ra", "application/vnd.rn-realaudio");
157: respType.put("rm", "application/vnd.rn-realmedia");
158: respType.put("rv", "application/vnd.rn-realvideo");
159: respType.put("rf", "application/vnd.rn-realflash");
160: respType.put("rf", "application/vnd.rn-realflash");
161: respType.put("asf", "application/x-ms-asf");
162: respType.put("asx", "application/x-ms-asf");
163: respType.put("wm", "application/x-ms-wm");
164: respType.put("wma", "application/x-ms-wma");
165: respType.put("wax", "application/x-ms-wax");
166: respType.put("wmw", "application/x-ms-wmw");
167: respType.put("wvx", "application/x-ms-wvx");
168: respType.put("swf", "application/x-shockwave-flash");
169: respType.put("spl", "application/futuresplash");
170: respType.put("avi", "video/msvideo");
171: respType.put("flc", "video/flc");
172: respType.put("mp4", "video/mpeg4");
173: }
174:
175: /**
176: * This method handles the requests for the Theme files.
177: * @param request The Servlet Request for the theme file
178: * @param response The Servlet Response
179: * @throws ServletException If the Servlet fails to serve the resource file
180: * @throws IOException If the Servlet cannot locate and read a requested ThemeFile
181: */
182: protected void doGet(HttpServletRequest request,
183: HttpServletResponse response) throws ServletException,
184: IOException {
185:
186: if (DEBUG)
187: log("doGet()");
188: String resourceName = request.getPathInfo();
189: InputStream inStream = null;
190: OutputStream outStream = null;
191: try {
192: // Get InputStream
193: inStream = this .getClass()
194: .getResourceAsStream(resourceName);
195: if (inStream == null) {
196: response.sendError(404, request.getRequestURI());
197: return;
198: }
199: inStream = new BufferedInputStream(inStream, 4096);
200:
201: // Ask the container to resolve the MIME type if possible
202: String type = getServletContext().getMimeType(resourceName);
203: if (type == null) {
204: // Otherwise, use our own hard coded list
205: int lastDot = resourceName.lastIndexOf('.');
206: if (lastDot != -1) {
207: String suffix = resourceName.substring(lastDot + 1);
208: type = (String) respType.get(suffix.toLowerCase());
209: }
210: }
211: // Set the content type of this response
212: if (type != null) {
213: response.setContentType(type);
214: }
215:
216: // Set the timestamp of the response to enable caching
217: response.setDateHeader("Last-Modified",
218: getLastModified(request));
219:
220: // Get the OutputStream
221: outStream = response.getOutputStream();
222: outStream = new BufferedOutputStream(outStream, 4096);
223:
224: int character;
225: while ((character = inStream.read()) != -1) {
226: outStream.write(character);
227: }
228: } catch (IOException ioex) {
229: //Log an error
230: } finally {
231: try {
232: inStream.close();
233: } catch (Throwable t) {
234: }
235: try {
236: outStream.close();
237: } catch (Throwable t) {
238: }
239: }
240: return;
241: }
242:
243: /**
244: * Returns a short description of the servlet.
245: * @return A String that names the Servlet
246: */
247: public String getServletInfo() {
248: return "Theme Servlet for Sun Web Components";
249: }
250:
251: public void init(ServletConfig config) throws ServletException {
252: super .init(config);
253: ThemeFactory.initializeThemeManager(config.getServletContext(),
254: getLocales(config));
255: }
256:
257: /**
258: * Determines the set of supported locales.
259: * @return set containing the support locales.
260: * @throws JspException Thrown if there is any exception encountered.
261: */
262: private Set getLocales(ServletConfig config) {
263:
264: if (DEBUG)
265: log("getLocales()");
266:
267: String localesString = config.getInitParameter(localeParameter);
268: if (localesString == null) {
269: return null;
270: }
271: String[] localeArray = localesString.split(",");
272: Set locales = new HashSet();
273: String language = null;
274: String country = null;
275: String variant = null;
276: String[] strings = null;
277: Locale locale = null;
278: String localeString = null;
279:
280: for (int counter = 0; counter < localeArray.length; ++counter) {
281: localeString = localeArray[counter].trim();
282: if (DEBUG)
283: log(localeString);
284:
285: if (localeString.length() == 0) {
286: continue;
287: }
288: strings = localeString.split("_");
289: if (strings.length > 2) {
290: locale = new Locale(strings[0], strings[1], strings[2]);
291: } else if (strings.length > 1) {
292: locale = new Locale(strings[0], strings[1]);
293: } else if (strings.length > 0) {
294: if (DEBUG)
295: log("language only " + strings[0]);
296: locale = new Locale(strings[0]);
297: }
298: if (DEBUG)
299: log("\tNew locale is " + locale.toString());
300: locales.add(locale);
301: }
302: return locales;
303: }
304:
305: /**
306: * <p>The "last modified" timestamp we should broadcast for all resources
307: * provided by this servlet. This will enable browsers that cache static
308: * resources to send an "If-Modified-Since" header, which will allow us to
309: * return a "Not Modified" response.</p>
310: */
311: private long lastModified = (new Date()).getTime();
312:
313: /**
314: * <p>Return the timestamp for when resources provided by this servlet
315: * were last modified. By default, this will be the timestamp when this
316: * servlet was first loaded at the deployment of the containing webapp,
317: * so that any changes in the resources will be automatically sent to
318: * the clients who might have cached earlier versions.</p>
319: */
320: public long getLastModified(HttpServletRequest request) {
321: return this.lastModified;
322: }
323:
324: }
|