001: /*
002: * @(#)CachedPnutsImpl.java 1.4 05/05/25
003: *
004: * Copyright (c) 1997-2005 Sun Microsystems, Inc. All Rights Reserved.
005: *
006: * See the file "LICENSE.txt" for information on usage and redistribution
007: * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
008: */
009: package pnuts.ext;
010:
011: import java.io.File;
012: import java.io.FileInputStream;
013: import java.io.IOException;
014: import java.io.InputStream;
015: import java.io.Reader;
016: import java.net.URL;
017: import java.net.URLConnection;
018:
019: import org.pnuts.util.Cache;
020: import org.pnuts.util.MemoryCache;
021:
022: import pnuts.compiler.Compiler;
023: import pnuts.lang.Context;
024: import pnuts.lang.Pnuts;
025: import pnuts.lang.PnutsImpl;
026: import pnuts.lang.Runtime;
027:
028: /**
029: * PnutsImpl which caches parsed (compiled) scripts and reuse them. This class
030: * is useful when same scripts are executed over and over, e.g. servlet scripts.
031: *
032: * @see pnuts.lang.PnutsImpl
033: */
034: public class CachedPnutsImpl extends PnutsImpl {
035: private final static boolean DEBUG = false;
036: private final static boolean java2 = Pnuts.isJava2();
037:
038: private boolean useCompiler;
039: private boolean useDynamicProxy;
040: private boolean includeLineNo;
041: private Cache file_cache;
042:
043: public CachedPnutsImpl() {
044: this (true);
045: }
046:
047: /**
048: * @param useCompiler
049: * true if compiler is used (default)
050: */
051: public CachedPnutsImpl(boolean useCompiler) {
052: this (useCompiler, true, false);
053: }
054:
055: /**
056: * @param useCompiler
057: * true if the compiler is used (default)
058: * @param useDynamicProxy
059: * true if the compiler generates dynamic proxy.
060: * @param includeLineNo
061: * true if the compiler generates line number information.
062: */
063: public CachedPnutsImpl(boolean useCompiler,
064: boolean useDynamicProxy, boolean includeLineNo) {
065: this (useCompiler, useDynamicProxy, includeLineNo, createCache());
066: }
067:
068: /**
069: * @param useCompiler
070: * true if the compiler is used (default)
071: * @param useDynamicProxy
072: * true if the compiler generates dynamic proxy.
073: * @param includeLineNo
074: * true if the compiler generates line number information.
075: * @param cache
076: * a cache object to reuse compiled code
077: */
078: public CachedPnutsImpl(boolean useCompiler,
079: boolean useDynamicProxy, boolean includeLineNo, Cache cache) {
080: this .useCompiler = useCompiler;
081: this .useDynamicProxy = useDynamicProxy;
082: this .includeLineNo = includeLineNo;
083: this .file_cache = cache;
084: }
085:
086: public void includeLineNo(boolean flag) {
087: this .includeLineNo = flag;
088: }
089:
090: /**
091: * Reset the cache entries
092: */
093: public void reset() {
094: this .file_cache.reset();
095: }
096:
097: protected ScriptCacheEntry getCachedCode(Object key) {
098: return (ScriptCacheEntry) file_cache.get(key);
099: }
100:
101: protected void putCachedCode(Object key, ScriptCacheEntry entry) {
102: file_cache.put(key, entry);
103: }
104:
105: /**
106: * Load a script file from a URL
107: *
108: * @param scriptURL
109: * the URL of the script
110: * @param context
111: * the context in which the script is executed
112: */
113: public Object load(URL scriptURL, Context context) {
114: String protocol = scriptURL.getProtocol();
115: Pnuts parsed = null;
116: ScriptCacheEntry entry = null;
117: InputStream in = null;
118: Reader reader = null;
119:
120: Context old = getThreadContext();
121: setThreadContext(context);
122: try {
123: if ("file".equals(protocol)) {
124: String fileName = scriptURL.getFile();
125: File file = new File(fileName);
126: String canon = file.getCanonicalPath();
127: long lastModified = file.lastModified();
128: entry = getCachedCode(scriptURL);
129: if (entry == null || lastModified == 0 || // coundn't get the
130: // timestamp
131: entry.lastModified < lastModified) {
132: in = new FileInputStream(file);
133: parsed = Pnuts.parse(Runtime.getScriptReader(in,
134: context), scriptURL, context);
135:
136: if (useCompiler) {
137: Compiler compiler = new Compiler(null, false,
138: useDynamicProxy);
139: compiler.includeLineNo(includeLineNo);
140: compiler.setConstantFolding(true);
141: if (DEBUG) {
142: System.out.println("compiling " + file);
143: }
144: try {
145: parsed = compiler.compile(parsed, context);
146: } catch (ClassFormatError cfe) {
147: /* ignore */
148: }
149: }
150: if (lastModified != 0) {
151: entry = new ScriptCacheEntry();
152: entry.lastModified = lastModified;
153: entry.parsedExpression = parsed;
154: putCachedCode(scriptURL, entry);
155: }
156: } else {
157: parsed = entry.parsedExpression;
158: }
159: } else {
160: URLConnection conn = scriptURL.openConnection();
161: long lastModified = conn.getLastModified();
162: entry = getCachedCode(scriptURL);
163: if (entry == null || lastModified == 0 || // unknown
164: entry.lastModified < lastModified) {
165: in = conn.getInputStream();
166: parsed = Pnuts.parse(Runtime.getScriptReader(in,
167: context), scriptURL, context);
168: if (useCompiler) {
169: Compiler compiler = new Compiler(null, false,
170: useDynamicProxy);
171: compiler.includeLineNo(includeLineNo);
172: compiler.setConstantFolding(true);
173: if (DEBUG) {
174: System.out
175: .println("compiling " + scriptURL);
176: }
177: try {
178: parsed = compiler.compile(parsed, context);
179: } catch (ClassFormatError cfe) {
180: /* ignore */
181: }
182: }
183: if (lastModified != 0) {
184: entry = new ScriptCacheEntry();
185: entry.lastModified = lastModified;
186: entry.parsedExpression = parsed;
187: putCachedCode(scriptURL, entry);
188: }
189: } else {
190: parsed = entry.parsedExpression;
191: }
192: }
193: return parsed.run(context);
194: } catch (Throwable t) {
195: checkException(context, t);
196: return null;
197: } finally {
198: setThreadContext(old);
199: if (in != null) {
200: try {
201: in.close();
202: } catch (IOException io) {
203: }
204: }
205: }
206: }
207:
208: public Object eval(String script, Context context) {
209: Context old = getThreadContext();
210: setThreadContext(context);
211: try {
212: ScriptCacheEntry entry = getCachedCode(script);
213: if (entry == null) {
214: Pnuts parsed = Pnuts.parse(script);
215: try {
216: Compiler compiler = new Compiler(null, false,
217: useDynamicProxy);
218: compiler.includeLineNo(includeLineNo);
219: compiler.setConstantFolding(true);
220: parsed = compiler.compile(parsed, context);
221: } catch (ClassFormatError e) {
222: // skip
223: }
224: entry = new ScriptCacheEntry();
225: entry.parsedExpression = parsed;
226: putCachedCode(script, entry);
227: }
228: return entry.parsedExpression.run(context);
229: } catch (Exception e) {
230: checkException(context, e);
231: return null;
232: } finally {
233: setThreadContext(old);
234: }
235: }
236:
237: public static class ScriptCacheEntry {
238: public long lastModified;
239:
240: public Pnuts parsedExpression;
241: }
242: }
|