001: /* DspExtendlet.java
002:
003: {{IS_NOTE
004: Purpose:
005:
006: Description:
007:
008: History:
009: Wed Jul 4 15:57:24 2007, Created by tomyeh
010: }}IS_NOTE
011:
012: Copyright (C) 2007 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.util.resource;
020:
021: import java.io.InputStream;
022: import java.io.InputStreamReader;
023: import java.io.Writer;
024: import java.io.StringWriter;
025: import java.io.OutputStream;
026: import java.io.IOException;
027:
028: import javax.servlet.ServletRequest;
029: import javax.servlet.ServletException;
030: import javax.servlet.http.HttpServletRequest;
031: import javax.servlet.http.HttpServletResponse;
032:
033: import org.zkoss.lang.D;
034: import org.zkoss.lang.Exceptions;
035: import org.zkoss.io.Files;
036: import org.zkoss.util.logging.Log;
037: import org.zkoss.util.resource.ResourceCache;
038: import org.zkoss.util.resource.Loader;
039:
040: import org.zkoss.web.servlet.Servlets;
041: import org.zkoss.web.servlet.http.Https;
042: import org.zkoss.web.servlet.dsp.Interpreter;
043: import org.zkoss.web.servlet.dsp.Interpretation;
044: import org.zkoss.web.servlet.dsp.ServletDspContext;
045:
046: /**
047: * The DSP resource processor ({@link Extendlet}) used to parse
048: * DSP files loaded from the classpath.
049: *
050: * @author tomyeh
051: * @since 2.4.1
052: */
053: /*package*/class DspExtendlet implements Extendlet {
054: private static final Log log = Log.lookup(DspExtendlet.class);
055:
056: private ExtendletContext _webctx;
057: /** DSP Interpretation cache. */
058: private ResourceCache _cache;
059:
060: public void init(ExtendletConfig config) {
061: _webctx = config.getExtendletContext();
062: _cache = new ResourceCache(new DSPLoader(), 131);
063: _cache.setMaxSize(1024);
064: _cache.setLifetime(60 * 60 * 1000); //1hr
065: _cache.setCheckPeriod(60 * 60 * 1000); //1hr
066: }
067:
068: public void service(HttpServletRequest request,
069: HttpServletResponse response, String path, String extra)
070: throws ServletException, IOException {
071: final Interpretation cnt = (Interpretation) _cache.get(path);
072: if (cnt == null) {
073: if (Servlets.isIncluded(request))
074: log.error("Failed to load the resource: " + path);
075: //It might be eaten, so log the error
076: response.sendError(response.SC_NOT_FOUND, path);
077: return;
078: }
079:
080: StringWriter sw = _webctx.shallCompress(request,
081: get2ndExtension(path)) ? new StringWriter(4096) : null;
082: cnt.interpret(new ServletDspContext(
083: _webctx.getServletContext(), request, response, sw,
084: _webctx.getLocator()));
085: if (extra != null)
086: (sw != null ? (Writer) sw : response.getWriter())
087: .write(extra);
088:
089: if (sw != null) {
090: final String result = sw.toString();
091: sw = null; //free
092:
093: try {
094: final OutputStream os = response.getOutputStream();
095: //Call it first to ensure getWrite() is not called yet
096:
097: byte[] data = result.getBytes("UTF-8");
098: if (data.length > 200) {
099: byte[] bs = Https.gzip(request, response, null,
100: data);
101: if (bs != null)
102: data = bs; //yes, browser support compress
103: }
104:
105: response.setContentLength(data.length);
106: os.write(data);
107: } catch (IllegalStateException ex) { //getWriter is called
108: response.getWriter().write(result);
109: }
110:
111: response.flushBuffer();
112: }
113: return; //done
114: }
115:
116: /** Returns the second extension. For example, js in xx.js.dsp.
117: */
118: private static final String get2ndExtension(String path) {
119: int j = path.lastIndexOf('.');
120: if (j < 0 || path.indexOf('/', j + 1) >= 0)
121: return null;
122:
123: int k = j > 0 ? path.lastIndexOf('.', j - 1) : -1;
124: if (k < 0 || path.indexOf('/', k + 1) >= 0)
125: return null;
126: return path.substring(k + 1, j).toLowerCase();
127: }
128:
129: /** Helper class. */
130: private class DSPLoader implements Loader {
131: private DSPLoader() {
132: }
133:
134: //-- super --//
135: public boolean shallCheck(Object src, long expiredMillis) {
136: return expiredMillis > 0;
137: }
138:
139: /** Returns the last modified time.
140: */
141: public long getLastModified(Object src) {
142: return 1; //any value (because it is packed in jar)
143: }
144:
145: public Object load(Object src) throws Exception {
146: // if (D.ON && log.debugable()) log.debug("Parse "+src);
147: final String path = (String) src;
148: final InputStream is = _webctx.getResourceAsStream(path);
149: if (is == null)
150: return null;
151:
152: try {
153: return parse0(is, Interpreter.getContentType(path));
154: } catch (Exception ex) {
155: if (log.debugable())
156: log.realCauseBriefly("Failed to parse " + path, ex);
157: else
158: log.error("Failed to parse " + path + "\nCause: "
159: + ex.getClass().getName() + " "
160: + Exceptions.getMessage(ex) + "\n"
161: + Exceptions.getBriefStackTrace(ex));
162: return null; //as non-existent
163: }
164: }
165:
166: private Object parse0(InputStream is, String ctype)
167: throws Exception {
168: final String content = Files.readAll(
169: new InputStreamReader(is, "UTF-8")).toString();
170: return new Interpreter().parse(content, ctype, null,
171: _webctx.getLocator());
172: }
173: }
174: }
|