001: /*******************************************************************************
002: * Licensed to the Apache Software Foundation (ASF) under one
003: * or more contributor license agreements. See the NOTICE file
004: * distributed with this work for additional information
005: * regarding copyright ownership. The ASF licenses this file
006: * to you under the Apache License, Version 2.0 (the
007: * "License"); you may not use this file except in compliance
008: * with the License. You may obtain a copy of the License at
009: *
010: * http://www.apache.org/licenses/LICENSE-2.0
011: *
012: * Unless required by applicable law or agreed to in writing,
013: * software distributed under the License is distributed on an
014: * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015: * KIND, either express or implied. See the License for the
016: * specific language governing permissions and limitations
017: * under the License.
018: *******************************************************************************/package org.ofbiz.base.util;
019:
020: import java.io.IOException;
021: import java.io.InputStreamReader;
022: import java.io.Reader;
023: import java.io.StringReader;
024: import java.net.MalformedURLException;
025: import java.net.URL;
026: import java.util.HashMap;
027: import java.util.Iterator;
028: import java.util.Map;
029: import java.util.Set;
030:
031: import org.ofbiz.base.location.FlexibleLocation;
032: import org.ofbiz.base.util.cache.UtilCache;
033:
034: import bsh.BshClassManager;
035: import bsh.EvalError;
036: import bsh.Interpreter;
037: import bsh.NameSpace;
038: import bsh.ParseException;
039:
040: /**
041: * BshUtil - BeanShell Utilities
042: *
043: */
044: public final class BshUtil {
045:
046: public static final String module = BshUtil.class.getName();
047:
048: protected static Map masterClassManagers = new HashMap();
049: public static UtilCache parsedScripts = new UtilCache(
050: "script.BshLocationParsedCache", 0, 0, false);
051:
052: /**
053: * Evaluate a BSH condition or expression
054: * @param expression The expression to evaluate
055: * @param context The context to use in evaluation (re-written)
056: * @return Object The result of the evaluation
057: * @throws EvalError
058: */
059: public static final Object eval(String expression, Map context)
060: throws EvalError {
061: Object o = null;
062: if (expression == null || expression.equals("")) {
063: Debug.logError("BSH Evaluation error. Empty expression",
064: module);
065: return null;
066: }
067:
068: if (Debug.verboseOn())
069: Debug.logVerbose("Evaluating -- " + expression, module);
070: if (Debug.verboseOn())
071: Debug.logVerbose("Using Context -- " + context, module);
072:
073: try {
074: Interpreter bsh = makeInterpreter(context);
075: // evaluate the expression
076: o = bsh.eval(expression);
077: if (Debug.verboseOn())
078: Debug.logVerbose("Evaluated to -- " + o, module);
079:
080: // read back the context info
081: NameSpace ns = bsh.getNameSpace();
082: String[] varNames = ns.getVariableNames();
083: for (int x = 0; x < varNames.length; x++) {
084: context.put(varNames[x], bsh.get(varNames[x]));
085: }
086: } catch (EvalError e) {
087: Debug.logError(e, "BSH Evaluation error.", module);
088: throw e;
089: }
090: return o;
091: }
092:
093: public static Interpreter makeInterpreter(Map context)
094: throws EvalError {
095: Interpreter bsh = getMasterInterpreter(null);
096: // Set the context for the condition
097: if (context != null) {
098: Set keySet = context.keySet();
099: Iterator i = keySet.iterator();
100: while (i.hasNext()) {
101: Object key = i.next();
102: Object value = context.get(key);
103: bsh.set((String) key, value);
104: }
105:
106: // include the context itself in for easier access in the scripts
107: bsh.set("context", context);
108: }
109:
110: return bsh;
111: }
112:
113: public static Interpreter getMasterInterpreter(
114: ClassLoader classLoader) {
115: if (classLoader == null) {
116: classLoader = Thread.currentThread()
117: .getContextClassLoader();
118: }
119:
120: //find the "master" BshClassManager for this classpath
121: BshClassManager master = (BshClassManager) BshUtil.masterClassManagers
122: .get(classLoader);
123: if (master == null) {
124: synchronized (OfbizBshBsfEngine.class) {
125: master = (BshClassManager) BshUtil.masterClassManagers
126: .get(classLoader);
127: if (master == null) {
128: master = BshClassManager.createClassManager();
129: master.setClassLoader(classLoader);
130: BshUtil.masterClassManagers
131: .put(classLoader, master);
132: }
133: }
134: }
135:
136: if (master != null) {
137: Interpreter interpreter = new Interpreter(new StringReader(
138: ""), System.out, System.err, false, new NameSpace(
139: master, "global"), null, null);
140: return interpreter;
141: } else {
142: Interpreter interpreter = new Interpreter();
143: interpreter.setClassLoader(classLoader);
144: return interpreter;
145: }
146: }
147:
148: public static Object runBshAtLocation(String location, Map context)
149: throws GeneralException {
150: try {
151: Interpreter interpreter = makeInterpreter(context);
152:
153: Interpreter.ParsedScript script = null;
154: script = (Interpreter.ParsedScript) parsedScripts
155: .get(location);
156: if (script == null) {
157: synchronized (OfbizBshBsfEngine.class) {
158: script = (Interpreter.ParsedScript) parsedScripts
159: .get(location);
160: if (script == null) {
161: URL scriptUrl = FlexibleLocation
162: .resolveLocation(location);
163: if (scriptUrl == null) {
164: throw new GeneralException(
165: "Could not find bsh script at ["
166: + location + "]");
167: }
168: Reader scriptReader = new InputStreamReader(
169: scriptUrl.openStream());
170: script = interpreter.parseScript(location,
171: scriptReader);
172: if (Debug.verboseOn())
173: Debug.logVerbose("Caching BSH script at: "
174: + location, module);
175: parsedScripts.put(location, script);
176: }
177: }
178: }
179:
180: return interpreter.evalParsedScript(script);
181: } catch (MalformedURLException e) {
182: String errMsg = "Error loading BSH script at [" + location
183: + "]: " + e.toString();
184: Debug.logError(e, errMsg, module);
185: throw new GeneralException(errMsg, e);
186: } catch (ParseException e) {
187: String errMsg = "Error parsing BSH script at [" + location
188: + "]: " + e.toString();
189: Debug.logError(e, errMsg, module);
190: throw new GeneralException(errMsg, e);
191: } catch (IOException e) {
192: String errMsg = "Error loading BSH script at [" + location
193: + "]: " + e.toString();
194: Debug.logError(e, errMsg, module);
195: throw new GeneralException(errMsg, e);
196: } catch (EvalError ee) {
197: Throwable t = ee.getCause();
198: if (t == null) {
199: Debug.logWarning(ee,
200: "WARNING: no cause (from getCause) found for BSH EvalError: "
201: + ee.toString(), module);
202: t = ee;
203: } else {
204: Debug.logError(t,
205: "ERROR: Got cause (from getCause) for BSH EvalError: "
206: + ee.toString(), module);
207: }
208:
209: String errMsg = "Error running BSH script at [" + location
210: + "], line [" + ee.getErrorLineNumber() + "]: "
211: + t.toString();
212: // don't log the full exception, just the main message; more detail logged later
213: throw new GeneralException(errMsg, t);
214: }
215: }
216: }
|