001: /*
002: * This file is part of PFIXCORE.
003: *
004: * PFIXCORE is free software; you can redistribute it and/or modify
005: * it under the terms of the GNU Lesser General Public License as published by
006: * the Free Software Foundation; either version 2 of the License, or
007: * (at your option) any later version.
008: *
009: * PFIXCORE is distributed in the hope that it will be useful,
010: * but WITHOUT ANY WARRANTY; without even the implied warranty of
011: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
012: * GNU Lesser General Public License for more details.
013: *
014: * You should have received a copy of the GNU Lesser General Public License
015: * along with PFIXCORE; if not, write to the Free Software
016: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
017: *
018: */
019:
020: package de.schlund.pfixcore.scripting;
021:
022: import java.io.IOException;
023: import java.io.InputStream;
024: import java.io.InputStreamReader;
025: import java.io.StringWriter;
026: import java.util.Hashtable;
027: import java.util.Map;
028:
029: import org.apache.bsf.BSFEngine;
030: import org.apache.bsf.BSFException;
031: import org.apache.log4j.Logger;
032:
033: import de.schlund.pfixxml.resources.FileResource;
034: import de.schlund.pfixxml.resources.ResourceUtil;
035:
036: /**
037: *
038: * @author Benjamin Reitzammer <benjamin@schlund.de>
039: */
040: public class ScriptingUtil {
041:
042: private final static Logger LOG = Logger
043: .getLogger(ScriptingUtil.class);
044:
045: /**
046: * keyed by the path as String, if it's a resource (starts with '/')
047: * value is a String, if it's a source (script stored in file), value is
048: * an Object array, consisting of two elements, with the first being the lastMod
049: * (as Long object) time of the file, when it was stored in the cache and the
050: * second the script as a String object.
051: */
052: private static final Map<String, Tupel<Long, String>> fileCache = new Hashtable<String, Tupel<Long, String>>();
053: private static final Map<String, String> classpathCache = new Hashtable<String, String>();
054:
055: /**
056: * @return never null
057: */
058: public static boolean isCachedCurrent(String path)
059: throws IOException {
060: return path.startsWith("/") ? isCachedResourceCurrent(path)
061: : isCachedFileCurrent(path);
062: }
063:
064: /**
065: * @return never null
066: */
067: public static String getScript(String path) throws IOException {
068: return path.startsWith("/") ? getClasspathResource(path)
069: : getFileSource(path);
070: }
071:
072: /**
073: *
074: */
075: protected static boolean exec(BSFEngine engine, String methodName,
076: Object[] args) throws Exception {
077: Boolean bool = (Boolean) engine.call(null, methodName, args);
078:
079: if (bool == null)
080: throw new BSFException(BSFException.REASON_EXECUTION_ERROR,
081: methodName + "() returned null Boolean value!");
082:
083: return bool.booleanValue();
084: }
085:
086: /**
087: */
088: protected static String scriptName(String path) {
089: int indexBegin = path.lastIndexOf("/") != -1 ? path
090: .lastIndexOf("/") : "script:".length();
091: return path.substring(indexBegin, path.lastIndexOf("."));
092: }
093:
094: // ============ private Helper methods ============
095:
096: /**
097: * @return never null
098: */
099: private static String getClasspathResource(String path)
100: throws IOException {
101:
102: String script = null;
103:
104: if (isCachedResourceCurrent(path)) {
105:
106: LOG.debug("Returning Script from cache for path '" + path);
107: script = classpathCache.get(path);
108:
109: } else {
110:
111: LOG.debug("Fetching Script from classpath for path '"
112: + path);
113:
114: InputStream stream = path.getClass().getResourceAsStream(
115: path);
116: if (stream == null)
117: throw new IOException("No Resource found for '" + path
118: + "'");
119:
120: script = copy(stream);
121: classpathCache.put(path, script);
122: }
123:
124: return script;
125: }
126:
127: /**
128: */
129: private static String getFileSource(String relativePath)
130: throws IOException {
131: String script = null;
132:
133: if (isCachedFileCurrent(relativePath)) {
134:
135: LOG.debug("Returning Script from cache for path '"
136: + relativePath);
137: script = fileCache.get(relativePath).obj2;
138:
139: } else {
140:
141: LOG.debug("Fetching Script for path '" + relativePath
142: + "' from file");
143:
144: FileResource file = ResourceUtil
145: .getFileResourceFromDocroot(relativePath);
146: script = copy(file.getInputStream());
147:
148: fileCache.put(relativePath, new Tupel<Long, String>(
149: new Long(file.lastModified()), script));
150:
151: }
152:
153: return script;
154: }
155:
156: /**
157: *
158: */
159: private static boolean isCachedFileCurrent(String path) {
160: boolean isCurrent = false;
161:
162: if (fileCache.containsKey(path)) {
163:
164: Tupel<Long, String> cacheEntry = fileCache.get(path);
165: long lastMod = cacheEntry.obj1.longValue();
166:
167: FileResource file = ResourceUtil
168: .getFileResourceFromDocroot(path);
169: if (file.lastModified() <= lastMod)
170: isCurrent = true;
171: }
172:
173: return isCurrent;
174: }
175:
176: /**
177: */
178: private static boolean isCachedResourceCurrent(String path) {
179: return classpathCache.containsKey(path);
180: }
181:
182: /**
183: */
184: private static String copy(InputStream input) throws IOException {
185:
186: InputStreamReader reader = new InputStreamReader(input);
187: StringWriter output = new StringWriter();
188:
189: char[] buffer = new char[4096];
190: int n = 0;
191: while (-1 != (n = reader.read(buffer))) {
192: output.write(buffer, 0, n);
193: }
194:
195: return output.toString();
196: }
197:
198: private static class Tupel<A, B> {
199: private A obj1;
200: private B obj2;
201:
202: public Tupel(A v1, B v2) {
203: obj1 = v1;
204: obj2 = v2;
205: }
206: }
207: }
|