/* DspExtendlet.java
Purpose:
Description:
History:
Wed Jul 4 15:57:24 2007, Created by tomyeh
Copyright (C) 2007 Potix Corporation. All Rights Reserved.
{{IS_RIGHT
This program is distributed under LGPL Version 2.1 in the hope that
it will be useful, but WITHOUT ANY WARRANTY.
}}IS_RIGHT
*/
package org.zkoss.web.util.resource;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.StringWriter;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.zkoss.io.Files;
import org.zkoss.lang.Library;
import org.zkoss.util.media.ContentTypes;
import org.zkoss.util.resource.ResourceCache;
import org.zkoss.web.servlet.Servlets;
import org.zkoss.web.servlet.dsp.ExtendletDspContext;
import org.zkoss.web.servlet.dsp.Interpretation;
import org.zkoss.web.servlet.dsp.Interpreter;
import org.zkoss.web.servlet.http.Encodes;
import org.zkoss.web.servlet.http.Https;
import org.zkoss.xml.XMLs;
/**
* The DSP resource processor ({@link Extendlet}) used to parse
* DSP files loaded from the classpath.
*
* <p>Note: it assumes the file being loaded is UTF-8.
* The encoding of the output stream is default to UTF-8, but
* DSP can change by use of the page directive.
*
* @author tomyeh
* @since 2.4.1 (public since 5.0.5)
*/
public class DspExtendlet implements Extendlet {
private static final Logger log = LoggerFactory.getLogger(DspExtendlet.class);
private ExtendletContext _webctx;
/** DSP Interpretation cache. */
private ResourceCache<String, Interpretation> _cache;
public void init(ExtendletConfig config) {
_webctx = config.getExtendletContext();
final DspLoader loader = new DspLoader();
_cache = new ResourceCache<String, Interpretation>(loader, 131);
_cache.setMaxSize(1024);
_cache.setLifetime(60 * 60 * 1000); //1hr
final int checkPeriod = loader.getCheckPeriod();
_cache.setCheckPeriod(checkPeriod >= 0 ? checkPeriod : 60 * 60 * 1000); //1hr
}
public boolean getFeature(int feature) {
return feature == ALLOW_DIRECT_INCLUDE;
}
public void service(HttpServletRequest request, HttpServletResponse response, String path)
throws ServletException, IOException {
String resourceCache = Library.getProperty("org.zkoss.zk.WCS.cache");
if (resourceCache != null && "false".equalsIgnoreCase(resourceCache))
_cache.clear();
final Interpretation cnt = _cache.get(path);
if (cnt == null) {
if (Servlets.isIncluded(request)) {
log.error("Failed to load the resource: " + Encodes.encodeURI(path));
//It might be eaten, so log the error
throw new java.io.FileNotFoundException("Failed to load the resource: " + path);
//have the includer to handle it
}
response.sendError(HttpServletResponse.SC_NOT_FOUND, XMLs.escapeXML(path));
return;
}
StringWriter sw = _webctx.shallCompress(request, get2ndExtension(path)) ? new StringWriter(4096) : null;
cnt.interpret(new ExtendletDspContext(_webctx, request, response, path, sw));
if (sw != null) {
final String result = sw.toString();
sw = null; //free
try {
final OutputStream os = response.getOutputStream();
//Call it first to ensure getWrite() is not called yet
String charset = response.getCharacterEncoding();
if (charset == null || charset.length() == 0)
charset = "UTF-8";
byte[] data = result.getBytes(charset);
if (data.length > 200) {
byte[] bs = Https.gzip(request, response, null, data);
if (bs != null)
data = bs; //yes, browser support compress
}
response.setContentLength(data.length);
os.write(data);
} catch (IllegalStateException ex) { //getWriter is called
response.getWriter().write(result);
}
response.flushBuffer();
}
}
/** Returns the second extension. For example, js in xx.js.dsp.
*/
private static final String get2ndExtension(String path) {
int j = path.lastIndexOf('.');
if (j < 0 || path.indexOf('/', j + 1) >= 0)
return null;
int k = j > 0 ? path.lastIndexOf('.', j - 1) : -1;
if (k < 0 || path.indexOf('/', k + 1) >= 0)
return null;
return path.substring(k + 1, j).toLowerCase(java.util.Locale.ENGLISH);
}
/** Helper class. */
private class DspLoader extends ExtendletLoader<Interpretation> {
private DspLoader() {
}
//-- super --//
protected Interpretation parse(InputStream is, String path, String orgpath) throws Exception {
final String content = Files.readAll(new InputStreamReader(is, "UTF-8")).toString();
String ctype = Interpreter.getContentType(path);
if (ctype == null)
ctype = ";charset=UTF-8";
else if (ctype.indexOf(';') < 0 && !ContentTypes.isBinary(ctype))
ctype += ";charset=UTF-8";
return new Interpreter().parse(content, ctype, null, _webctx.getLocator());
}
protected ExtendletContext getExtendletContext() {
return _webctx;
}
}
}