001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: *
017: */
018:
019: package org.apache.jmeter.util;
020:
021: import java.io.File;
022: import java.io.FileNotFoundException;
023: import java.io.IOException;
024: import java.lang.reflect.InvocationTargetException;
025: import java.lang.reflect.Method;
026: import org.apache.jorphan.logging.LoggingManager;
027: import org.apache.jorphan.util.JMeterError;
028: import org.apache.jorphan.util.JMeterException;
029: import org.apache.log.Logger;
030:
031: /**
032: * BeanShell setup function - encapsulates all the access to the BeanShell
033: * Interpreter in a single class.
034: *
035: * The class uses dynamic class loading to access BeanShell, which means that
036: * all the source files can be built without needing access to the bsh jar.
037: *
038: * If the beanshell jar is not present at run-time, an error will be logged
039: *
040: */
041:
042: public class BeanShellInterpreter {
043: private static final Logger log = LoggingManager
044: .getLoggerForClass();
045:
046: private static final Method bshGet;
047:
048: private static final Method bshSet;
049:
050: private static final Method bshEval;
051:
052: private static final Method bshSource;
053:
054: private static final Class bshClass;
055:
056: private static final String BSH_INTERPRETER = "bsh.Interpreter"; //$NON-NLS-1$
057:
058: static {
059: // Temporary copies, so can set the final ones
060: Method get = null, eval = null, set = null, source = null;
061: Class clazz = null;
062: ClassLoader loader = Thread.currentThread()
063: .getContextClassLoader();
064: try {
065: clazz = loader.loadClass(BSH_INTERPRETER);
066: Class string = String.class;
067: Class object = Object.class;
068:
069: get = clazz.getMethod("get", //$NON-NLS-1$
070: new Class[] { string });
071: eval = clazz.getMethod("eval", //$NON-NLS-1$
072: new Class[] { string });
073: set = clazz.getMethod("set", //$NON-NLS-1$
074: new Class[] { string, object });
075: source = clazz.getMethod("source", //$NON-NLS-1$
076: new Class[] { string });
077: } catch (ClassNotFoundException e) {
078: log.error("Beanshell Interpreter not found");
079: } catch (SecurityException e) {
080: log.error("Beanshell Interpreter not found", e);
081: } catch (NoSuchMethodException e) {
082: log.error("Beanshell Interpreter not found", e);
083: } finally {
084: bshEval = eval;
085: bshGet = get;
086: bshSet = set;
087: bshSource = source;
088: bshClass = clazz;
089: }
090: }
091:
092: // This class is not serialised
093: private Object bshInstance = null; // The interpreter instance for this class
094:
095: public BeanShellInterpreter() throws ClassNotFoundException {
096: if (bshClass == null) {
097: throw new ClassNotFoundException(BSH_INTERPRETER);
098: }
099: try {
100: bshInstance = bshClass.newInstance();
101: } catch (InstantiationException e) {
102: log.error("Can't instantiate BeanShell", e);
103: throw new ClassNotFoundException(
104: "Can't instantiate BeanShell", e);
105: } catch (IllegalAccessException e) {
106: log.error("Can't instantiate BeanShell", e);
107: throw new ClassNotFoundException(
108: "Can't instantiate BeanShell", e);
109: }
110: }
111:
112: public void init(final String initFile, final Object logger)
113: throws IOException, JMeterException {
114: if (logger != null) {// Do this before starting the script
115: try {
116: set("log", logger);//$NON-NLS-1$
117: } catch (JMeterException e) {
118: log.error("Can't set logger variable", e);
119: throw e;
120: }
121: }
122: if (initFile != null && initFile.length() > 0) {
123: String fileToUse = initFile;
124: // Check file so we can distinguish file error from script error
125: File in = new File(fileToUse);
126: if (!in.exists()) {// Cannot find the file locally, so try the bin directory
127: fileToUse = JMeterUtils.getJMeterHome()
128: + File.separator + "bin" // $NON-NLS-1$
129: + File.separator + initFile;
130: in = new File(fileToUse);
131: if (!in.exists()) {
132: throw new FileNotFoundException(initFile); // use the original name here
133: }
134: }
135: if (!in.canRead()) {
136: throw new IOException("Cannot read" + fileToUse);
137: }
138: source(fileToUse);
139: }
140: }
141:
142: /**
143: *
144: * @param init initialisation file
145: * @param _log logger to pass to interpreter; also used to log errors in this method
146: */
147: public BeanShellInterpreter(String init, Logger _log)
148: throws ClassNotFoundException {
149: this ();
150: try {
151: this .init(init, _log);
152: } catch (IOException e) {
153: _log.warn("Could not initialise interpreter: "
154: + e.toString()); // no need for stack trace
155: } catch (JMeterException e) {
156: _log.warn("Could not initialise interpreter: "
157: + e.toString()); // no need for stack trace
158: }
159: }
160:
161: private Object bshInvoke(Method m, Object[] o, boolean shouldLog)
162: throws JMeterException {
163: Object r = null;
164: final String errorString = "Error invoking bsh method: ";
165: try {
166: r = m.invoke(bshInstance, o);
167: } catch (IllegalArgumentException e) { // Programming error
168: final String message = errorString + m.getName();
169: log.error(message);
170: throw new JMeterError(message, e);
171: } catch (IllegalAccessException e) { // Also programming error
172: final String message = errorString + m.getName();
173: log.error(message);
174: throw new JMeterError(message, e);
175: } catch (InvocationTargetException e) { // Can occur at run-time
176: // could be caused by the bsh Exceptions:
177: // EvalError, ParseException or TargetError
178: String message = errorString + m.getName();
179: Throwable cause = e.getCause();
180: if (cause != null) {
181: message += "\t" + cause.getLocalizedMessage();
182: }
183:
184: if (shouldLog) {
185: log.error(message);
186: }
187: throw new JMeterException(message, e);
188: }
189: return r;
190: }
191:
192: public Object eval(String s) throws JMeterException {
193: return bshInvoke(bshEval, new Object[] { s }, true);
194: }
195:
196: public Object evalNoLog(String s) throws JMeterException {
197: return bshInvoke(bshEval, new Object[] { s }, false);
198: }
199:
200: public Object set(String s, Object o) throws JMeterException {
201: return bshInvoke(bshSet, new Object[] { s, o }, true);
202: }
203:
204: public Object set(String s, boolean b) throws JMeterException {
205: return bshInvoke(bshSet,
206: new Object[] { s, Boolean.valueOf(b) }, true);
207: }
208:
209: public Object source(String s) throws JMeterException {
210: return bshInvoke(bshSource, new Object[] { s }, true);
211: }
212:
213: public Object get(String s) throws JMeterException {
214: return bshInvoke(bshGet, new Object[] { s }, true);
215: }
216: }
|