001: /* InterpreterServlet.java
002:
003: {{IS_NOTE
004: Purpose:
005:
006: Description:
007:
008: History:
009: Mon Sep 5 17:06:34 2005, Created by tomyeh
010: }}IS_NOTE
011:
012: Copyright (C) 2005 Potix Corporation. All Rights Reserved.
013:
014: {{IS_RIGHT
015: This program is distributed under GPL Version 2.0 in the hope that
016: it will be useful, but WITHOUT ANY WARRANTY.
017: }}IS_RIGHT
018: */
019: package org.zkoss.web.servlet.dsp;
020:
021: import java.io.File;
022: import java.io.InputStream;
023: import java.io.InputStreamReader;
024: import java.io.FileInputStream;
025: import java.io.OutputStream;
026: import java.io.StringWriter;
027: import java.io.IOException;
028: import java.net.URL;
029:
030: import javax.servlet.ServletConfig;
031: import javax.servlet.ServletContext;
032: import javax.servlet.ServletException;
033: import javax.servlet.http.HttpServletRequest;
034: import javax.servlet.http.HttpServletResponse;
035: import javax.servlet.http.HttpServlet;
036:
037: import org.zkoss.lang.D;
038: import org.zkoss.lang.Exceptions;
039: import org.zkoss.lang.SystemException;
040: import org.zkoss.util.logging.Log;
041: import org.zkoss.util.resource.ResourceCache;
042: import org.zkoss.util.resource.Locator;
043: import org.zkoss.io.Files;
044: import org.zkoss.xel.taglib.Taglibs;
045:
046: import org.zkoss.web.servlet.Charsets;
047: import org.zkoss.web.servlet.Servlets;
048: import org.zkoss.web.servlet.http.Https;
049: import org.zkoss.web.util.resource.ResourceCaches;
050: import org.zkoss.web.util.resource.ResourceLoader;
051: import org.zkoss.web.util.resource.ClassWebResource;
052:
053: /**
054: * The servlet used to interpret the DSP file (Potix Dynamic Script Page).
055: *
056: * <p>Initial parameters:
057: * <dl>
058: * <dt>charset</dt>
059: * <dd>The default character set if not specified in the DSP page.<br/>
060: * Default: UTF-8.</dd>
061: * <dt>class-resource</dt>
062: * <dd>Whether to search the class loader if a resource is not found
063: * in the Web application (i.e., ServletContext).</dd>
064: * Default: false.</dd>
065: * </dl>
066: *
067: * @author tomyeh
068: */
069: public class InterpreterServlet extends HttpServlet {
070: private static final Log log = Log.lookup(InterpreterServlet.class);
071: private ServletContext _ctx;
072: private String _charset = "UTF-8";
073: private Locator _locator;
074: private boolean _compress = true;
075:
076: public void init(ServletConfig config) throws ServletException {
077: //super.init(config);
078: //Note callback super to avoid saving config
079:
080: _ctx = config.getServletContext();
081:
082: String param = config.getInitParameter("compress");
083: if (param != null)
084: _compress = "true".equals(param);
085:
086: param = config.getInitParameter("class-resource");
087: final boolean bClsRes = "true".equals(param);
088: _locator = new Locator() {
089: public String getDirectory() {
090: return null; //FUTURE: support relative path
091: }
092:
093: public URL getResource(String name) {
094: URL url = null;
095: if (name.indexOf("://") < 0) {
096: try {
097: url = _ctx.getResource(name);
098: if (bClsRes && url == null)
099: url = ClassWebResource.getResource(name);
100: } catch (java.net.MalformedURLException ex) { //eat it
101: }
102: }
103: return url != null ? url : Taglibs.getDefaultURL(name);
104: }
105:
106: public InputStream getResourceAsStream(String name) {
107: InputStream is = _ctx.getResourceAsStream(name);
108: return !bClsRes || is != null ? is : ClassWebResource
109: .getResourceAsStream(name);
110: }
111: };
112:
113: param = config.getInitParameter("charset");
114: if (param != null)
115: _charset = param.length() > 0 ? param : null;
116: }
117:
118: public ServletContext getServletContext() {
119: return _ctx;
120: }
121:
122: //-- super --//
123: protected void doGet(HttpServletRequest request,
124: HttpServletResponse response) throws ServletException,
125: IOException {
126: final String path = Https.getThisServletPath(request);
127: if (D.ON && log.debugable())
128: log.debug("Get " + path);
129:
130: final Object old = Charsets.setup(request, response, _charset);
131: try {
132: final Interpretation cnt = (Interpretation) ResourceCaches
133: .get(getCache(), _ctx, path, null);
134: if (cnt == null) {
135: if (Https.isIncluded(request))
136: log.error("Not found: " + path);
137: //It might be eaten, so log the error
138: response.sendError(HttpServletResponse.SC_NOT_FOUND,
139: path);
140: return;
141: }
142:
143: final boolean compress = _compress
144: && !Servlets.isIncluded(request);
145: final StringWriter out = compress ? new StringWriter()
146: : null;
147: cnt.interpret(new ServletDspContext(_ctx, request,
148: response, out, null));
149:
150: if (compress) {
151: final String result = out.toString();
152:
153: try {
154: final OutputStream os = response.getOutputStream();
155: //Call it first to ensure getWrite() is not called yet
156:
157: byte[] data = result.getBytes("UTF-8");
158: if (data.length > 200) {
159: byte[] bs = Https.gzip(request, response, null,
160: data);
161: if (bs != null)
162: data = bs; //yes, browser support compress
163: }
164:
165: response.setContentLength(data.length);
166: os.write(data);
167: response.flushBuffer();
168: } catch (IllegalStateException ex) { //getWriter is called
169: response.getWriter().write(result);
170: }
171: }
172: } finally {
173: Charsets.cleanup(request, old);
174: }
175: }
176:
177: protected void doPost(HttpServletRequest request,
178: HttpServletResponse response) throws ServletException,
179: IOException {
180: doGet(request, response);
181: }
182:
183: private static final String ATTR_PAGE_CACHE = "org.zkoss.web.servlet.dsp.PageCache";
184:
185: private final ResourceCache getCache() {
186: ResourceCache cache = (ResourceCache) _ctx
187: .getAttribute(ATTR_PAGE_CACHE);
188: if (cache == null) {
189: synchronized (InterpreterServlet.class) {
190: cache = (ResourceCache) _ctx
191: .getAttribute(ATTR_PAGE_CACHE);
192: if (cache == null) {
193: cache = new ResourceCache(new MyLoader(), 29);
194: cache.setMaxSize(1024);
195: cache.setLifetime(60 * 60 * 1000); //1hr
196: _ctx.setAttribute(ATTR_PAGE_CACHE, cache);
197: }
198: }
199: }
200: return cache;
201: }
202:
203: private class MyLoader extends ResourceLoader {
204: private MyLoader() {
205: }
206:
207: //-- super --//
208: protected Object parse(String path, File file, Object extra)
209: throws Exception {
210: try {
211: return parse0(new FileInputStream(file), Interpreter
212: .getContentType(file.getName()));
213: } catch (Exception ex) {
214: if (log.debugable())
215: log.realCauseBriefly("Failed to parse " + file, ex);
216: else
217: log.error("Failed to parse " + file + "\nCause: "
218: + Exceptions.getMessage(ex) + "\n"
219: + Exceptions.getBriefStackTrace(ex));
220: return null; //as non-existent
221: }
222: }
223:
224: protected Object parse(String path, URL url, Object extra)
225: throws Exception {
226: try {
227: return parse0(url.openStream(), Interpreter
228: .getContentType(url.getPath()));
229: } catch (Exception ex) {
230: if (log.debugable())
231: log.realCauseBriefly("Failed to parse " + url, ex);
232: else
233: log.error("Failed to parse " + url + "\nCause: "
234: + Exceptions.getMessage(ex));
235: return null; //as non-existent
236: }
237: }
238:
239: private Object parse0(InputStream is, String ctype)
240: throws Exception {
241: if (is == null)
242: return null;
243:
244: final String content = Files.readAll(
245: new InputStreamReader(is, "UTF-8")).toString();
246: return new Interpreter().parse(content, ctype, null,
247: _locator);
248: }
249: }
250: }
|