diff --git a/build.gradle b/build.gradle
index 0cc7bd840..b421f0183 100644
--- a/build.gradle
+++ b/build.gradle
@@ -137,8 +137,8 @@ dependencies {
implementation "net.kyori:adventure-text-minimessage:4.1.0-SNAPSHOT"
implementation "net.kyori:adventure-platform-bukkit:4.0.0-SNAPSHOT"
implementation 'net.kyori:adventure-api:4.8.1'
-\
-// Dynamically Loaded
+
+ // Dynamically Loaded
implementation 'it.unimi.dsi:fastutil:8.5.4'
implementation 'com.googlecode.concurrentlinkedhashmap:concurrentlinkedhashmap-lru:1.4.2'
implementation 'org.zeroturnaround:zt-zip:1.14'
@@ -146,4 +146,5 @@ dependencies {
implementation 'org.ow2.asm:asm:9.2'
implementation 'com.google.guava:guava:30.1.1-jre'
+
}
\ No newline at end of file
diff --git a/src/main/java/com/volmit/iris/engine/IrisExecutionEnvironment.java b/src/main/java/com/volmit/iris/engine/IrisExecutionEnvironment.java
new file mode 100644
index 000000000..e8896350d
--- /dev/null
+++ b/src/main/java/com/volmit/iris/engine/IrisExecutionEnvironment.java
@@ -0,0 +1,33 @@
+/*
+ * Iris is a World Generator for Minecraft Bukkit Servers
+ * Copyright (c) 2021 Arcane Arts (Volmit Software)
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see
+ * When a scripting engine is first fired up, the initialize() + * method is called right after construction. + *
+ * A scripting engine must provide two access points for applications + * to call into them: via function calls and via expression evaluation. + * It must also support loading scripts. + *
+ * A scripting engine is a property change listener and will be notified
+ * when any of the relevant properties of the manager change. (See
+ * BSFManager to see which of its properties are bound.)
+ *
+ * @author Sanjiva Weerawarana
+ * @author Matthew J. Duftler
+ */
+public interface BSFEngine extends PropertyChangeListener {
+
+ /**
+ * This is used by an application to invoke an anonymous function. An
+ * anonymous function is a multi-line script which when evaluated will
+ * produce a value. These are separated from expressions and scripts
+ * because the prior are spsed to be good 'ol expressions and scripts
+ * are not value returning. We allow anonymous functions to have parameters
+ * as well for completeness.
+ *
+ * @param source (context info) the source of this expression
+ * (e.g., filename)
+ * @param lineNo (context info) the line number in source for expr
+ * @param columnNo (context info) the column number in source for expr
+ * @param funcBody the multi-line, value returning script to evaluate
+ * @param paramNames the names of the parameters above assumes
+ * @param arguments values of the above parameters
+ *
+ * @exception BSFException if anything goes wrong while doin' it.
+ */
+ public Object apply(
+ String source,
+ int lineNo,
+ int columnNo,
+ Object funcBody,
+ Vector paramNames,
+ Vector arguments)
+ throws BSFException;
+ /**
+ * This is used by an application to call into the scripting engine
+ * to make a function/method call. The "object" argument is the object
+ * whose method is to be called, if that applies. For non-OO languages,
+ * this is typically ignored and should be given as null. For pretend-OO
+ * languages such as VB, this would be the (String) name of the object.
+ * The arguments are given in the args array.
+ *
+ * @param object object on which to make the call
+ * @param name name of the method / procedure to call
+ * @param args the arguments to be given to the procedure
+ *
+ * @exception BSFException if anything goes wrong while eval'ing a
+ * BSFException is thrown. The reason indicates the problem.
+ */
+ public Object call(Object object, String name, Object[] args)
+ throws BSFException;
+ /**
+ * This is used by an application to compile an anonymous function. See
+ * comments in apply for more hdetails.
+ *
+ * @param source (context info) the source of this expression
+ * (e.g., filename)
+ * @param lineNo (context info) the line number in source for expr
+ * @param columnNo (context info) the column number in source for expr
+ * @param funcBody the multi-line, value returning script to evaluate
+ * @param paramNames the names of the parameters above assumes
+ * @param arguments values of the above parameters
+ * @param cb the CodeBuffer to compile into
+ *
+ * @exception BSFException if anything goes wrong while doin' it.
+ */
+ public void compileApply(
+ String source,
+ int lineNo,
+ int columnNo,
+ Object funcBody,
+ Vector paramNames,
+ Vector arguments,
+ CodeBuffer cb)
+ throws BSFException;
+ /**
+ * This is used by an application to compile a value-returning expression.
+ * The expr may be string or some other type, depending on the language.
+ * The generated code is dumped into the CodeBuffer.
+ *
+ * @param source (context info) the source of this expression
+ * (e.g., filename)
+ * @param lineNo (context info) the line number in source for expr
+ * @param columnNo (context info) the column number in source for expr
+ * @param expr the expression to compile
+ * @param cb the CodeBuffer to compile into
+ *
+ * @exception BSFException if anything goes wrong while compiling a
+ * BSFException is thrown. The reason indicates the problem.
+ */
+ public void compileExpr(
+ String source,
+ int lineNo,
+ int columnNo,
+ Object expr,
+ CodeBuffer cb)
+ throws BSFException;
+ /**
+ * This is used by an application to compile some script. The
+ * script may be string or some other type, depending on the
+ * language. The generated code is dumped into the CodeBuffer.
+ *
+ * @param source (context info) the source of this script
+ * (e.g., filename)
+ * @param lineNo (context info) the line number in source for script
+ * @param columnNo (context info) the column number in source for script
+ * @param script the script to compile
+ * @param cb the CodeBuffer to compile into
+ *
+ * @exception BSFException if anything goes wrong while compiling a
+ * BSFException is thrown. The reason indicates the problem.
+ */
+ public void compileScript(
+ String source,
+ int lineNo,
+ int columnNo,
+ Object script,
+ CodeBuffer cb)
+ throws BSFException;
+ /**
+ * Declare a bean after the engine has been started. Declared beans
+ * are beans that are named and which the engine must make available
+ * to the scripts it runs in the most first class way possible.
+ *
+ * @param bean the bean to declare
+ *
+ * @exception BSFException if the engine cannot do this operation
+ */
+ public void declareBean(BSFDeclaredBean bean) throws BSFException;
+ /**
+ * This is used by an application to evaluate an expression. The
+ * expression may be string or some other type, depending on the
+ * language. (For example, for BML it'll be an org.w3c.dom.Element
+ * object.)
+ *
+ * @param source (context info) the source of this expression
+ * (e.g., filename)
+ * @param lineNo (context info) the line number in source for expr
+ * @param columnNo (context info) the column number in source for expr
+ * @param expr the expression to evaluate
+ *
+ * @exception BSFException if anything goes wrong while eval'ing a
+ * BSFException is thrown. The reason indicates the problem.
+ */
+ public Object eval(String source, int lineNo, int columnNo, Object expr)
+ throws BSFException;
+ /**
+ * This is used by an application to execute some script. The
+ * expression may be string or some other type, depending on the
+ * language. Returns nothing but if something goes wrong it excepts
+ * (of course).
+ *
+ * @param source (context info) the source of this expression
+ * (e.g., filename)
+ * @param lineNo (context info) the line number in source for expr
+ * @param columnNo (context info) the column number in source for expr
+ * @param script the script to execute
+ *
+ * @exception BSFException if anything goes wrong while exec'ing a
+ * BSFException is thrown. The reason indicates the problem.
+ */
+ public void exec(String source, int lineNo, int columnNo, Object script)
+ throws BSFException;
+ /**
+ * This is used by an application to execute some script, as though
+ * one were interacting with the language in an interactive session.
+ * The expression may be string or some other type, depending on the
+ * language. Returns nothing but if something goes wrong it excepts (of
+ * course).
+ *
+ * @param source (context info) the source of this expression
+ * (e.g., filename)
+ * @param lineNo (context info) the line number in source for expr
+ * @param columnNo (context info) the column number in source for expr
+ * @param script the script to execute
+ *
+ * @exception BSFException if anything goes wrong while exec'ing a
+ * BSFException is thrown. The reason indicates the problem.
+ */
+ public void iexec(String source, int lineNo, int columnNo, Object script)
+ throws BSFException;
+
+ /**
+ * This method is used to initialize the engine right after construction.
+ * This method will be called before any calls to eval or call. At this
+ * time the engine should capture the current values of interesting
+ * properties from the manager. In the future, any changes to those
+ * will be mirrored to me by the manager via a property change event.
+ *
+ * @param mgr The BSFManager that's hosting this engine.
+ * @param lang Language string which this engine is handling.
+ * @param declaredBeans Vector of BSFDeclaredObject containing beans
+ * that should be declared into the language runtime at init
+ * time as best as possible.
+ *
+ * @exception BSFException if anything goes wrong while init'ing a
+ * BSFException is thrown. The reason indicates the problem.
+ */
+ public void initialize(BSFManager mgr, String lang, Vector declaredBeans)
+ throws BSFException;
+ /**
+ * Graceful termination
+ */
+ public void terminate();
+ /**
+ * Undeclare a previously declared bean.
+ *
+ * @param bean the bean to undeclare
+ *
+ * @exception BSFException if the engine cannot do this operation
+ */
+ public void undeclareBean(BSFDeclaredBean bean) throws BSFException;
+}
diff --git a/src/main/java/com/volmit/iris/util/bsf/BSFException.java b/src/main/java/com/volmit/iris/util/bsf/BSFException.java
new file mode 100644
index 000000000..2ab480d05
--- /dev/null
+++ b/src/main/java/com/volmit/iris/util/bsf/BSFException.java
@@ -0,0 +1,71 @@
+/*
+ * Iris is a World Generator for Minecraft Bukkit Servers
+ * Copyright (c) 2021 Arcane Arts (Volmit Software)
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see
+ * BSFManager serves as the registry of available scripting engines
+ * as well. Loading and unloading of scripting engines is
+ * supported as well. Each BSFManager loads one engine per language.
+ * Several BSFManagers can be created per JVM.
+ *
+ * @author Sanjiva Weerawarana
+ * @author Matthew J. Duftler
+ * @author Sam Ruby
+ * @author Olivier Gruber (added original debugging support)
+ * @author Don Schwarz (added support for registering languages dynamically)
+ */
+public class BSFManager {
+ // version string is in the form "abc.yyyymmdd" where
+ // "abc" represents a dewey decimal number (three levels, each between 0 and 9),
+ // and "yyyy" a four digit year, "mm" a two digit month, "dd" a two digit day.
+ //
+ // Example: "240.20060925" stands for: BSF version "2.4.0" as of "2006-09-25"
+ protected static String version="240.20061006";
+
+ // table of registered scripting engines
+ protected static Hashtable registeredEngines = new Hashtable();
+
+ // mapping of file extensions to languages
+ protected static Hashtable extn2Lang = new Hashtable();
+
+ // table of scripting engine instances created by this manager.
+ // only one instance of a given language engine is created by a single
+ // manager instance.
+ protected Hashtable loadedEngines = new Hashtable();
+
+ // table of registered beans for use by scripting engines.
+ protected ObjectRegistry objectRegistry = new ObjectRegistry();
+
+ // prop change support containing loaded engines to inform when any
+ // of my interesting properties change
+ protected PropertyChangeSupport pcs;
+
+ // the class loader to use if a class loader is needed. Default is
+ // he who loaded me (which may be null in which case its Class.forName).
+ // protected ClassLoader classLoader = getClass().getClassLoader();
+ protected ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); // rgf, 2006-01-05
+
+ // temporary directory to use to dump temporary files into. Note that
+ // if class files are dropped here then unless this dir is in the
+ // classpath or unless the classloader knows to look here, the classes
+ // will not be found.
+ protected String tempDir = ".";
+
+ // classpath used by those that need a classpath
+ protected String classPath;
+
+ // stores BSFDeclaredBeans representing objects
+ // introduced by a client of BSFManager
+ protected Vector declaredBeans = new Vector();
+
+ private Log logger = LogFactory.getLog(this.getClass().getName());
+
+ //////////////////////////////////////////////////////////////////////
+ //
+ // pre-register engines that BSF supports off the shelf
+ //
+ //////////////////////////////////////////////////////////////////////
+
+ static {
+ try {
+ Enumeration e = BSFManager.class.getClassLoader().getResources("org/apache/bsf/Languages.properties");
+ while (e.hasMoreElements()) {
+ URL url = (URL)e.nextElement();
+ InputStream is = url.openStream();
+
+ Properties p = new Properties();
+ p.load(is);
+
+ for (Enumeration keys = p.propertyNames(); keys.hasMoreElements();) {
+
+ String key = (String) keys.nextElement();
+ String value = p.getProperty(key);
+ String className = value.substring(0, value.indexOf(","));
+
+
+
+
+ // get the extensions for this language
+ String exts = value.substring(value.indexOf(",")+1, value.length());
+ StringTokenizer st = new StringTokenizer(exts, "|");
+ String[] extensions = new String[st.countTokens()];
+ for (int i = 0; st.hasMoreTokens(); i++) {
+ extensions[i] = ((String) st.nextToken()).trim();
+ }
+
+ registerScriptingEngine(key, className, extensions);
+ }
+ }
+ } catch (IOException ex) {
+
+ ex.printStackTrace();
+ System.err.println("Error reading Languages file " + ex);
+ } catch (NoSuchElementException nsee) {
+
+ nsee.printStackTrace();
+ System.err.println("Syntax error in Languages resource bundle");
+ } catch (MissingResourceException mre) {
+
+ mre.printStackTrace();
+ System.err.println("Initialization error: " + mre.toString());
+ }
+ }
+
+ public BSFManager() {
+ pcs = new PropertyChangeSupport(this);
+ }
+
+
+ /** Returns the version string of BSF.
+ *
+ * @return version string in the form "abc.yyyymmdd" where
+ "abc" represents a dewey decimal number (three levels, each between 0 and 9), and
+ "yyyy" a four digit year, "mm" a two digit month,
+ "dd" a two digit day.
+ *
+
Example: "240.20061006
"
+ stands for: BSF version 2.4.0
as of 2006-10-06
.
+ *
+ *
+ * @since 2006-01-17
+ */
+ public static String getVersion() {
+
+ return version;
+ }
+
+ /**
+ * Apply the given anonymous function of the given language to the given
+ * parameters and return the resulting value.
+ *
+ * @param lang language identifier
+ * @param source (context info) the source of this expression
+ (e.g., filename)
+ * @param lineNo (context info) the line number in source for expr
+ * @param columnNo (context info) the column number in source for expr
+ * @param funcBody the multi-line, value returning script to evaluate
+ * @param paramNames the names of the parameters above assumes
+ * @param arguments values of the above parameters
+ *
+ * @exception BSFException if anything goes wrong while running the script
+ */
+ public Object apply(String lang,
+ String source,
+ int lineNo,
+ int columnNo,
+ Object funcBody,
+ Vector paramNames,
+ Vector arguments)
+ throws BSFException {
+ logger.debug("BSFManager:apply");
+
+ final BSFEngine e = loadScriptingEngine(lang);
+ final String sourcef = source;
+ final int lineNof = lineNo, columnNof = columnNo;
+ final Object funcBodyf = funcBody;
+ final Vector paramNamesf = paramNames;
+ final Vector argumentsf = arguments;
+ Object result = null;
+
+ try {
+ final Object resultf =
+ AccessController.doPrivileged(new PrivilegedExceptionAction() {
+ public Object run() throws Exception {
+ return e.apply(sourcef, lineNof, columnNof,
+ funcBodyf, paramNamesf, argumentsf);
+ }
+ });
+ result = resultf;
+ } catch (PrivilegedActionException prive) {
+
+ logger.error("Exception: ", prive);
+ throw (BSFException) prive.getException();
+ }
+
+ return result;
+ }
+
+ /**
+ * Compile the application of the given anonymous function of the given
+ * language to the given parameters into the given CodeBuffer.
+ *
+ * @param lang language identifier
+ * @param source (context info) the source of this expression
+ (e.g., filename)
+ * @param lineNo (context info) the line number in source for expr
+ * @param columnNo (context info) the column number in source for expr
+ * @param funcBody the multi-line, value returning script to evaluate
+ * @param paramNames the names of the parameters above assumes
+ * @param arguments values of the above parameters
+ * @param cb code buffer to compile into
+ *
+ * @exception BSFException if anything goes wrong while running the script
+ */
+ public void compileApply(String lang,
+ String source,
+ int lineNo,
+ int columnNo,
+ Object funcBody,
+ Vector paramNames,
+ Vector arguments,
+ CodeBuffer cb)
+ throws BSFException {
+ logger.debug("BSFManager:compileApply");
+
+ final BSFEngine e = loadScriptingEngine(lang);
+ final String sourcef = source;
+ final int lineNof = lineNo, columnNof = columnNo;
+ final Object funcBodyf = funcBody;
+ final Vector paramNamesf = paramNames;
+ final Vector argumentsf = arguments;
+ final CodeBuffer cbf = cb;
+
+ try {
+ AccessController.doPrivileged(new PrivilegedExceptionAction() {
+ public Object run() throws Exception {
+ e.compileApply(sourcef, lineNof, columnNof,
+ funcBodyf, paramNamesf,
+ argumentsf, cbf);
+ return null;
+ }
+ });
+ } catch (PrivilegedActionException prive) {
+
+ logger.error("Exception :", prive);
+ throw (BSFException) prive.getException();
+ }
+ }
+
+ /**
+ * Compile the given expression of the given language into the given
+ * CodeBuffer.
+ *
+ * @param lang language identifier
+ * @param source (context info) the source of this expression
+ (e.g., filename)
+ * @param lineNo (context info) the line number in source for expr
+ * @param columnNo (context info) the column number in source for expr
+ * @param expr the expression to compile
+ * @param cb code buffer to compile into
+ *
+ * @exception BSFException if any error while compiling the expression
+ */
+ public void compileExpr(String lang,
+ String source,
+ int lineNo,
+ int columnNo,
+ Object expr,
+ CodeBuffer cb)
+ throws BSFException {
+ logger.debug("BSFManager:compileExpr");
+
+ final BSFEngine e = loadScriptingEngine(lang);
+ final String sourcef = source;
+ final int lineNof = lineNo, columnNof = columnNo;
+ final Object exprf = expr;
+ final CodeBuffer cbf = cb;
+
+ try {
+ AccessController.doPrivileged(new PrivilegedExceptionAction() {
+ public Object run() throws Exception {
+ e.compileExpr(sourcef, lineNof, columnNof, exprf, cbf);
+ return null;
+ }
+ });
+ } catch (PrivilegedActionException prive) {
+
+ logger.error("Exception :", prive);
+ throw (BSFException) prive.getException();
+ }
+ }
+
+ /**
+ * Compile the given script of the given language into the given
+ * CodeBuffer.
+ *
+ * @param lang language identifier
+ * @param source (context info) the source of this script
+ (e.g., filename)
+ * @param lineNo (context info) the line number in source for script
+ * @param columnNo (context info) the column number in source for script
+ * @param script the script to compile
+ * @param cb code buffer to compile into
+ *
+ * @exception BSFException if any error while compiling the script
+ */
+ public void compileScript(String lang,
+ String source,
+ int lineNo,
+ int columnNo,
+ Object script,
+ CodeBuffer cb)
+ throws BSFException {
+ logger.debug("BSFManager:compileScript");
+
+ final BSFEngine e = loadScriptingEngine(lang);
+ final String sourcef = source;
+ final int lineNof = lineNo, columnNof = columnNo;
+ final Object scriptf = script;
+ final CodeBuffer cbf = cb;
+
+ try {
+ AccessController.doPrivileged(new PrivilegedExceptionAction() {
+ public Object run() throws Exception {
+ e.compileScript(sourcef, lineNof, columnNof,
+ scriptf, cbf);
+ return null;
+ }
+ });
+ } catch (PrivilegedActionException prive) {
+
+ logger.error("Exception :", prive);
+ throw (BSFException) prive.getException();
+ }
+ }
+
+ /**
+ * Declare a bean. The difference between declaring and registering
+ * is that engines are spsed to make declared beans "pre-available"
+ * in the scripts as far as possible. That is, if a script author
+ * needs a registered bean, he needs to look it up in some way. However
+ * if he needs a declared bean, the language has the responsibility to
+ * make those beans avaialable "automatically."
+ *
+ * When a bean is declared it is automatically registered as well + * so that any declared bean can be gotton to by looking it up as well. + *
+ * If any of the languages that are already running in this manager + * says they don't like this (by throwing an exception) then this + * method will simply quit with that exception. That is, any engines + * that come after than in the engine enumeration will not even be + * told about this new bean. + *
+ * So, in general its best to declare beans before the manager has
+ * been asked to load any engines because then the user can be informed
+ * when an engine rejects it. Also, its much more likely that an engine
+ * can declare a bean at start time than it can at any time.
+ *
+ * @param beanName name to declare bean as
+ * @param bean the bean that's being declared
+ * @param type the type to represent the bean as
+ *
+ * @exception BSFException if any of the languages that are already
+ * running decides to throw an exception when asked to
+ * declare this bean.
+ */
+ public void declareBean(String beanName, Object bean, Class type)
+ throws BSFException {
+ logger.debug("BSFManager:declareBean");
+
+ registerBean(beanName, bean);
+
+ BSFDeclaredBean tempBean = new BSFDeclaredBean(beanName, bean, type);
+ declaredBeans.addElement(tempBean);
+
+ Enumeration enginesEnum = loadedEngines.elements();
+ BSFEngine engine;
+ while (enginesEnum.hasMoreElements()) {
+ engine = (BSFEngine) enginesEnum.nextElement();
+ engine.declareBean(tempBean);
+ }
+ }
+
+ /**
+ * Evaluate the given expression of the given language and return the
+ * resulting value.
+ *
+ * @param lang language identifier
+ * @param source (context info) the source of this expression
+ (e.g., filename)
+ * @param lineNo (context info) the line number in source for expr
+ * @param columnNo (context info) the column number in source for expr
+ * @param expr the expression to evaluate
+ *
+ * @exception BSFException if anything goes wrong while running the script
+ */
+ public Object eval(String lang,
+ String source,
+ int lineNo,
+ int columnNo,
+ Object expr)
+ throws BSFException {
+ logger.debug("BSFManager:eval");
+
+ final BSFEngine e = loadScriptingEngine(lang);
+ final String sourcef = source;
+ final int lineNof = lineNo, columnNof = columnNo;
+ final Object exprf = expr;
+ Object result = null;
+
+ try {
+ final Object resultf =
+ AccessController.doPrivileged(new PrivilegedExceptionAction() {
+ public Object run() throws Exception {
+ return e.eval(sourcef, lineNof, columnNof, exprf);
+ }
+ });
+ result = resultf;
+ } catch (PrivilegedActionException prive) {
+
+ logger.error("Exception: ", prive);
+ throw (BSFException) prive.getException();
+ }
+
+ return result;
+ }
+
+ //////////////////////////////////////////////////////////////////////
+ //
+ // Convenience functions for exec'ing and eval'ing scripts directly
+ // without loading and dealing with engines etc..
+ //
+ //////////////////////////////////////////////////////////////////////
+
+ /**
+ * Execute the given script of the given language.
+ *
+ * @param lang language identifier
+ * @param source (context info) the source of this expression
+ (e.g., filename)
+ * @param lineNo (context info) the line number in source for expr
+ * @param columnNo (context info) the column number in source for expr
+ * @param script the script to execute
+ *
+ * @exception BSFException if anything goes wrong while running the script
+ */
+ public void exec(String lang,
+ String source,
+ int lineNo,
+ int columnNo,
+ Object script)
+ throws BSFException {
+ logger.debug("BSFManager:exec");
+
+ final BSFEngine e = loadScriptingEngine(lang);
+ final String sourcef = source;
+ final int lineNof = lineNo, columnNof = columnNo;
+ final Object scriptf = script;
+
+ try {
+ AccessController.doPrivileged(new PrivilegedExceptionAction() {
+ public Object run() throws Exception {
+ e.exec(sourcef, lineNof, columnNof, scriptf);
+ return null;
+ }
+ });
+ } catch (PrivilegedActionException prive) {
+
+ logger.error("Exception :", prive);
+ throw (BSFException) prive.getException();
+ }
+ }
+
+ /**
+ * Execute the given script of the given language, attempting to
+ * emulate an interactive session w/ the language.
+ *
+ * @param lang language identifier
+ * @param source (context info) the source of this expression
+ * (e.g., filename)
+ * @param lineNo (context info) the line number in source for expr
+ * @param columnNo (context info) the column number in source for expr
+ * @param script the script to execute
+ *
+ * @exception BSFException if anything goes wrong while running the script
+ */
+ public void iexec(String lang,
+ String source,
+ int lineNo,
+ int columnNo,
+ Object script)
+ throws BSFException {
+ logger.debug("BSFManager:iexec");
+
+ final BSFEngine e = loadScriptingEngine(lang);
+ final String sourcef = source;
+ final int lineNof = lineNo, columnNof = columnNo;
+ final Object scriptf = script;
+
+ try {
+ AccessController.doPrivileged(new PrivilegedExceptionAction() {
+ public Object run() throws Exception {
+ e.iexec(sourcef, lineNof, columnNof, scriptf);
+ return null;
+ }
+ });
+ } catch (PrivilegedActionException prive) {
+
+ logger.error("Exception :", prive);
+ throw (BSFException) prive.getException();
+ }
+ }
+
+ /**
+ * Get classLoader
+ */
+ public ClassLoader getClassLoader() {
+ logger.debug("BSFManager:getClassLoader");
+ return classLoader;
+ }
+
+ /**
+ * Get classPath
+ */
+ public String getClassPath() {
+ logger.debug("BSFManager:getClassPath");
+ if (classPath == null) {
+ try {
+ classPath = System.getProperty("java.class.path");
+ } catch (Throwable t) {
+
+ logger.debug("Exception :", t);
+ // prolly a security exception .. so no can do
+ }
+ }
+ return classPath;
+ }
+
+ /**
+ * Determine the language of a script file by looking at the file
+ * extension.
+ *
+ * @param fileName the name of the file
+ *
+ * @return the scripting language the file is in if the file extension
+ * is known to me (must have been registered via
+ * registerScriptingEngine).
+ *
+ * @exception BSFException if file's extension is unknown.
+ */
+ public static String getLangFromFilename(String fileName)
+ throws BSFException {
+ int dotIndex = fileName.lastIndexOf(".");
+
+ if (dotIndex != -1) {
+ String extn = fileName.substring(dotIndex + 1);
+ String langval = (String) extn2Lang.get(extn);
+ String lang = null;
+ int index, loops = 0;
+
+ if (langval != null) {
+ while ((index = langval.indexOf(":", 0)) != -1) {
+ // Great. Multiple language engines registered
+ // for this extension.
+ // Try to find first one that is in our classpath.
+ lang = langval.substring(0, index);
+ langval = langval.substring(index + 1);
+ loops++;
+
+ // Test to see if in classpath
+ try {
+ String engineName =
+ (String) registeredEngines.get(lang);
+ Class.forName(engineName);
+ } catch (ClassNotFoundException cnfe) {
+
+ // Bummer.
+ lang = langval;
+ continue;
+ }
+
+ // Got past that? Good.
+ break;
+ }
+ if (loops == 0) { lang = langval; }
+ }
+
+ if (lang != null && lang != "") {
+ return lang;
+ }
+ }
+ throw new BSFException(BSFException.REASON_OTHER_ERROR,
+ "file extension missing or unknown: "
+ + "unable to determine language for '"
+ + fileName
+ + "'");
+ }
+
+ /**
+ * Return the current object registry of the manager.
+ *
+ * @return the current registry.
+ */
+ public ObjectRegistry getObjectRegistry() {
+ return objectRegistry;
+ }
+
+ /**
+ * Get tempDir
+ */
+ public String getTempDir() {
+ return tempDir;
+ }
+
+ /**
+ * Determine whether a language is registered.
+ *
+ * @param lang string identifying a language
+ *
+ * @return true iff it is
+ */
+ public static boolean isLanguageRegistered(String lang) {
+ return (registeredEngines.get(lang) != null);
+ }
+
+ //////////////////////////////////////////////////////////////////////
+ //
+ // Bean scripting framework services
+ //
+ //////////////////////////////////////////////////////////////////////
+
+ /**
+ * Load a scripting engine based on the lang string identifying it.
+ *
+ * @param lang string identifying language
+ * @exception BSFException if the language is unknown (i.e., if it
+ * has not been registered) with a reason of
+ * REASON_UNKNOWN_LANGUAGE. If the language is known but
+ * if the interface can't be created for some reason, then
+ * the reason is set to REASON_OTHER_ERROR and the actual
+ * exception is passed on as well.
+ */
+ public BSFEngine loadScriptingEngine(String lang) throws BSFException {
+ logger.debug("BSFManager:loadScriptingEngine");
+
+ // if its already loaded return that
+ BSFEngine eng = (BSFEngine) loadedEngines.get(lang);
+ if (eng != null) {
+ return eng;
+ }
+
+ // is it a registered language?
+ String engineClassName = (String) registeredEngines.get(lang);
+ if (engineClassName == null) {
+ logger.error("unsupported language: " + lang);
+ throw new BSFException(BSFException.REASON_UNKNOWN_LANGUAGE,
+ "unsupported language: " + lang);
+ }
+
+ // create the engine and initialize it. if anything goes wrong
+ // except.
+ try {
+ Class engineClass =
+ (classLoader == null)
+ ? Class.forName(engineClassName)
+ : classLoader.loadClass(engineClassName);
+ final BSFEngine engf = (BSFEngine) engineClass.newInstance();
+ final BSFManager thisf = this;
+ final String langf = lang;
+ final Vector dbf = declaredBeans;
+ AccessController.doPrivileged(new PrivilegedExceptionAction() {
+ public Object run() throws Exception {
+ engf.initialize(thisf, langf, dbf);
+ return null;
+ }
+ });
+ eng = engf;
+ loadedEngines.put(lang, eng);
+ pcs.addPropertyChangeListener(eng);
+ return eng;
+ } catch (PrivilegedActionException prive) {
+
+ logger.error("Exception :", prive);
+ throw (BSFException) prive.getException();
+ } catch (Throwable t) {
+
+ logger.error("Exception :", t);
+ throw new BSFException(BSFException.REASON_OTHER_ERROR,
+ "unable to load language: " + lang,
+ t);
+ }
+ }
+
+ /**
+ * return a handle to a bean registered in the bean registry by the
+ * application or a scripting engine. Returns null if bean is not found.
+ *
+ * @param beanName name of bean to look up
+ *
+ * @return the bean if its found or null
+ */
+ public Object lookupBean(String beanName) {
+ logger.debug("BSFManager:lookupBean");
+
+ try {
+ return ((BSFDeclaredBean)objectRegistry.lookup(beanName)).bean;
+ } catch (IllegalArgumentException e) {
+
+ logger.debug("Exception :", e);
+ return null;
+ }
+ }
+
+ /**
+ * Registering a bean allows a scripting engine or the application to
+ * access that bean by name and to manipulate it.
+ *
+ * @param beanName name to register under
+ * @param bean the bean to register
+ */
+ public void registerBean(String beanName, Object bean) {
+ logger.debug("BSFManager:registerBean");
+
+ BSFDeclaredBean tempBean;
+
+ if(bean == null) {
+ tempBean = new BSFDeclaredBean(beanName, null, null);
+ } else {
+
+ tempBean = new BSFDeclaredBean(beanName, bean, bean.getClass());
+ }
+ objectRegistry.register(beanName, tempBean);
+ }
+
+ /**
+ * Register a scripting engine in the static registry of the
+ * BSFManager.
+ *
+ * @param lang string identifying language
+ * @param engineClassName fully qualified name of the class interfacing
+ * the language to BSF.
+ * @param extensions array of file extensions that should be mapped to
+ * this language type. may be null.
+ */
+ public static void registerScriptingEngine(String lang,
+ String engineClassName,
+ String[] extensions) {
+ registeredEngines.put(lang, engineClassName);
+ if (extensions != null) {
+ for (int i = 0; i < extensions.length; i++) {
+ String langstr = (String) extn2Lang.get(extensions[i]);
+ langstr = (langstr == null) ? lang : lang + ":" + langstr;
+ extn2Lang.put(extensions[i], langstr);
+ }
+ }
+ }
+
+ /**
+ * Set the class loader for those that need to use it. Default is he
+ * who loaded me or null (i.e., its Class.forName).
+ *
+ * @param classLoader the class loader to use.
+ */
+ public void setClassLoader(ClassLoader classLoader) {
+ logger.debug("BSFManager:setClassLoader");
+
+ pcs.firePropertyChange("classLoader", this.classLoader, classLoader);
+ this.classLoader = classLoader;
+ }
+
+ /**
+ * Set the classpath for those that need to use it. Default is the value
+ * of the java.class.path property.
+ *
+ * @param classPath the classpath to use
+ */
+ public void setClassPath(String classPath) {
+ logger.debug("BSFManager:setClassPath");
+
+ pcs.firePropertyChange("classPath", this.classPath, classPath);
+ this.classPath = classPath;
+ }
+
+ /**
+ * Set the object registry used by this manager. By default a new
+ * one is created when the manager is new'ed and this overwrites
+ * that one.
+ *
+ * @param objectRegistry the registry to use
+ */
+ public void setObjectRegistry(ObjectRegistry objectRegistry) {
+ logger.debug("BSFManager:setObjectRegistry");
+
+ this.objectRegistry = objectRegistry;
+ }
+
+ /**
+ * Temporary directory to put stuff into (for those who need to). Note
+ * that unless this directory is in the classpath or unless the
+ * classloader knows to look in here, any classes here will not
+ * be found! BSFManager provides a service method to load a class
+ * which uses either the classLoader provided by the class loader
+ * property or, if that fails, a class loader which knows to load from
+ * the tempdir to try to load the class. Default value of tempDir
+ * is "." (current working dir).
+ *
+ * @param tempDir the temporary directory
+ */
+ public void setTempDir(String tempDir) {
+ logger.debug("BSFManager:setTempDir");
+
+ pcs.firePropertyChange("tempDir", this.tempDir, tempDir);
+ this.tempDir = tempDir;
+ }
+
+ /**
+ * Gracefully terminate all engines
+ */
+ public void terminate() {
+ logger.debug("BSFManager:terminate");
+
+ Enumeration enginesEnum = loadedEngines.elements();
+ BSFEngine engine;
+ while (enginesEnum.hasMoreElements()) {
+ engine = (BSFEngine) enginesEnum.nextElement();
+ engine.terminate();
+ }
+
+ loadedEngines = new Hashtable();
+ }
+
+ /**
+ * Undeclare a previously declared bean. This removes the bean from
+ * the list of declared beans in the manager as well as asks every
+ * running engine to undeclared the bean. As with above, if any
+ * of the engines except when asked to undeclare, this method does
+ * not catch that exception. Quietly returns if the bean is unknown.
+ *
+ * @param beanName name of bean to undeclare
+ *
+ * @exception BSFException if any of the languages that are already
+ * running decides to throw an exception when asked to
+ * undeclare this bean.
+ */
+ public void undeclareBean(String beanName) throws BSFException {
+ logger.debug("BSFManager:undeclareBean");
+
+ unregisterBean(beanName);
+
+ BSFDeclaredBean tempBean = null;
+ boolean found = false;
+ for (Iterator i = declaredBeans.iterator(); i.hasNext();) {
+ tempBean = (BSFDeclaredBean) i.next();
+ if (tempBean.name.equals(beanName)) {
+ found = true;
+ break;
+ }
+ }
+
+ if (found) {
+ declaredBeans.removeElement(tempBean);
+
+ Enumeration enginesEnum = loadedEngines.elements();
+ while (enginesEnum.hasMoreElements()) {
+ BSFEngine engine = (BSFEngine) enginesEnum.nextElement();
+ engine.undeclareBean(tempBean);
+ }
+ }
+ }
+
+ /**
+ * Unregister a previously registered bean. Silent if name is not found.
+ *
+ * @param beanName name of bean to unregister
+ */
+ public void unregisterBean(String beanName) {
+ logger.debug("BSFManager:unregisterBean");
+
+ objectRegistry.unregister(beanName);
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/volmit/iris/util/bsf/Languages.properties b/src/main/java/com/volmit/iris/util/bsf/Languages.properties
new file mode 100644
index 000000000..6c5e83281
--- /dev/null
+++ b/src/main/java/com/volmit/iris/util/bsf/Languages.properties
@@ -0,0 +1,50 @@
+#
+# Iris is a World Generator for Minecraft Bukkit Servers
+# Copyright (c) 2021 Arcane Arts (Volmit Software)
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see
+ *
+ * @author Sanjiva Weerawarana
+ */
+
+public class JaclEngine extends BSFEngineImpl {
+ /* the Jacl interpretor object */
+ private Interp interp;
+
+ /**
+ *
+ * @param method The name of the method to call.
+ * @param args an array of arguments to be
+ * passed to the extension, which may be either
+ * Vectors of Nodes, or Strings.
+ */
+ public Object call (Object obj, String method, Object[] args)
+ throws BSFException {
+ StringBuffer tclScript = new StringBuffer (method);
+ if (args != null) {
+ for( int i = 0 ; i < args.length ; i++ ) {
+ tclScript.append (" ");
+ tclScript.append (args[i].toString ());
+ }
+ }
+ return eval ("
+ * The Java code must be written script-style -- that is, just the body of
+ * the function, without class or method headers or footers.
+ * The JavaEngine will generate those via a "boilerplate" wrapper:
+ *
+ * If you use the placeholder string $$CLASSNAME$$ elsewhere
+ * in your script -- including within text strings -- BSFJavaEngine will
+ * replace it with the generated name of the class before the Java code
+ * is compiled.
+ *
+ *
+ * NOTE that it is your responsibility to convert the code into an acceptable
+ * Java string. If you're invoking the JavaEngine directly (as in the
+ * JSPLikeInJava example) that means \"quoting\" characters that would
+ * otherwise cause trouble.
+ *
+ * ALSO NOTE that it is your responsibility to return an object, or null in
+ * lieu thereof!
+ *
+ * Since the code has to be compiled to a Java classfile, invoking it involves
+ * a fair amount of computation to load and execute the compiler. We are
+ * currently making an attempt to manage that by caching the class
+ * after it has been loaded, but the indexing is fairly primitive. It has
+ * been suggested that the Bean Scripting Framework may want to support
+ * preload-and-name-script and execute-preloaded-script-by-name options to
+ * provide better control over when and how much overhead occurs.
+ *
+ * @author Joe Kesselman
+ */
+public class JavaEngine extends BSFEngineImpl {
+ Class javaclass = null;
+ static Hashtable codeToClass = new Hashtable();
+ static String serializeCompilation = "";
+ static String placeholder = "$$CLASSNAME$$";
+ String minorPrefix;
+
+ private Log logger = LogFactory.getLog(this.getClass().getName());
+
+ /**
+ * Create a scratchfile, open it for writing, return its name.
+ * Relies on the filesystem to provide us with uniqueness testing.
+ * NOTE THAT uniqueFileOffset continues to count; we don't want to
+ * risk reusing a classname we have previously loaded in this session
+ * even if the classfile has been deleted.
+ */
+ private int uniqueFileOffset = -1;
+
+ private class GeneratedFile {
+ File file = null;
+ FileOutputStream fos = null;
+ String className = null;
+ GeneratedFile(File file, FileOutputStream fos, String className) {
+ this.file = file;
+ this.fos = fos;
+ this.className = className;
+ }
+ }
+
+ /**
+ * Constructor.
+ */
+ public JavaEngine () {
+ // Do compilation-possible check here??????????????
+ }
+
+ public Object call (Object object, String method, Object[] args)
+ throws BSFException
+ {
+ throw new BSFException (BSFException.REASON_UNSUPPORTED_FEATURE,
+ "call() is not currently supported by JavaEngine");
+ }
+
+ public void compileScript (String source, int lineNo, int columnNo,
+ Object script, CodeBuffer cb) throws BSFException {
+ ObjInfo oldRet = cb.getFinalServiceMethodStatement ();
+
+ if (oldRet != null && oldRet.isExecutable ()) {
+ cb.addServiceMethodStatement (oldRet.objName + ";");
+ }
+
+ cb.addServiceMethodStatement (script.toString ());
+ cb.setFinalServiceMethodStatement (null);
+ }
+
+ /**
+ * This is used by an application to evaluate a string containing
+ * some expression. It should store the "bsf" handle where the
+ * script can get to it, for callback purposes.
+ *
+ * Note that Java compilation imposes serious overhead,
+ * but in exchange you get full Java performance
+ * once the classes have been created (minus the cache lookup cost).
+ *
+ * Nobody knows whether javac is threadsafe.
+ * I'm going to serialize access to protect it.
+ *
+ * There is no published API for invoking javac as a class. There's a trick
+ * that seems to work for Java 1.1.x, but it stopped working in Java 1.2.
+ * We will attempt to use it, then if necessary fall back on invoking
+ * javac via the command line.
+ */
+ public Object eval (String source, int lineNo, int columnNo,
+ Object oscript) throws BSFException
+ {
+ Object retval = null;
+ String classname = null;
+ GeneratedFile gf = null;
+
+ String basescript = oscript.toString();
+ String script = basescript; // May be altered by $$CLASSNAME$$ expansion
+
+ try {
+ // Do we already have a class exactly matching this code?
+ javaclass = (Class)codeToClass.get(basescript);
+
+ if(javaclass != null) {
+ classname=javaclass.getName();
+ } else {
+ gf = openUniqueFile(tempDir, "BSFJava",".java");
+ if( gf == null) {
+ throw new BSFException("couldn't create JavaEngine scratchfile");
+ }
+ // Obtain classname
+ classname = gf.className;
+
+ // Write the kluge header to the file.
+ gf.fos.write(("import java.lang.*;"+
+ "import java.util.*;"+
+ "public class "+classname+" {\n" +
+ " static public Object BSFJavaEngineEntry(com.volmit.iris.util.bsf.BSFManager bsf) {\n")
+ .getBytes());
+
+ // Edit the script to replace placeholder with the generated
+ // classname. Note that this occurs _after_ the cache was checked!
+ int startpoint = script.indexOf(placeholder);
+ int endpoint;
+ if(startpoint >= 0) {
+ StringBuffer changed = new StringBuffer();
+ for(; startpoint >=0; startpoint = script.indexOf(placeholder,startpoint)) {
+ changed.setLength(0); // Reset for 2nd pass or later
+ if(startpoint > 0) {
+ changed.append(script.substring(0,startpoint));
+ }
+ changed.append(classname);
+ endpoint = startpoint+placeholder.length();
+ if(endpoint < script.length()) {
+ changed.append(script.substring(endpoint));
+ }
+ script = changed.toString();
+ }
+ }
+
+ // MJD - debug
+// BSFDeclaredBean tempBean;
+// String className;
+//
+// for (int i = 0; i < declaredBeans.size (); i++) {
+// tempBean = (BSFDeclaredBean) declaredBeans.elementAt (i);
+// className = StringUtils.getClassName (tempBean.bean.getClass ());
+//
+// gf.fos.write ((className + " " +
+// tempBean.name + " = (" + className +
+// ")bsf.lookupBean(\"" +
+// tempBean.name + "\");").getBytes ());
+// }
+ // MJD - debug
+
+ // Copy the input to the file.
+ // Assumes all available -- probably mistake, but same as other engines.
+ gf.fos.write(script.getBytes());
+ // Close the method and class
+ gf.fos.write(("\n }\n}\n").getBytes());
+ gf.fos.close();
+
+ // Compile through Java to .class file
+ // May not be threadsafe. Serialize access on static object:
+ synchronized(serializeCompilation) {
+ JavaUtils.JDKcompile(gf.file.getPath(), classPath);
+ }
+
+ // Load class.
+ javaclass = EngineUtils.loadClass(mgr, classname);
+
+ // Stash class for reuse
+ codeToClass.put(basescript, javaclass);
+ }
+
+ Object[] callArgs = {mgr};
+ retval = internalCall(this,"BSFJavaEngineEntry",callArgs);
+ }
+
+
+ catch(Exception e) {
+ e.printStackTrace ();
+ throw new BSFException (BSFException.REASON_IO_ERROR, e.getMessage ());
+ } finally {
+ // Cleanup: delete the .java and .class files
+
+// if(gf!=null && gf.file!=null && gf.file.exists())
+// gf.file.delete(); // .java file
+
+
+ if(classname!=null) {
+ // Generated class
+ File file = new File(tempDir+File.separatorChar+classname+".class");
+// if(file.exists())
+// file.delete();
+
+ // Search for and clean up minor classes, classname$xxx.class
+ file = new File(tempDir); // ***** Is this required?
+ minorPrefix = classname+"$"; // Indirect arg to filter
+ String[] minorClassfiles = file.list(new FilenameFilter()
+ {
+ // Starts with classname$ and ends with .class
+ public boolean accept(File dir,String name) {
+ return
+ (0 == name.indexOf(minorPrefix))
+ &&
+ (name.lastIndexOf(".class") == name.length()-6);
+ }
+ });
+ for(int i = 0; i < minorClassfiles.length; ++i) {
+ file = new File(minorClassfiles[i]);
+// file.delete();
+ }
+ }
+ }
+ return retval;
+ }
+
+ public void initialize (BSFManager mgr, String lang,
+ Vector declaredBeans) throws BSFException {
+ super.initialize (mgr, lang, declaredBeans);
+ }
+ /**
+ * Return an object from an extension.
+ * @param object Object on which to make the internal_call (ignored).
+ * @param method The name of the method to internal_call.
+ * @param args an array of arguments to be
+ * passed to the extension, which may be either
+ * Vectors of Nodes, or Strings.
+ */
+ Object internalCall (Object object, String method, Object[] args)
+ throws BSFException
+ {
+ //***** ISSUE: Only static methods are currently supported
+ Object retval = null;
+ try {
+ if(javaclass != null) {
+ //***** This should call the lookup used in BML, for typesafety
+ Class[] argtypes = new Class[args.length];
+ for(int i=0; i
+ * The original version of this code was first written by Adam Peller
+ * for use in LotusXSL. Sanjiva took his code and adapted it for BSF.
+ *
+ * @author Adam Peller
+ * The NetRexx code must be written script-style, without a "class" or
+ * "properties" section preceeding the executable code. The NetRexxEngine will
+ * generate a prefix for this code:
+ *
+ * If you use the placeholder string $$CLASSNAME$$ elsewhere
+ * in your script -- including within text strings -- BSFNetRexxEngine will
+ * replace it with the generated name of the class before the NetRexx code
+ * is compiled.
+ *
+ * If you need to use full NetRexx functionality, we recommend that your
+ * NetRexx script define and invoke a "minor class", with or without the
+ * "dependent" keyword as suits your needs. You'll have to use $$CLASSNAME$$
+ * in naming the minor class, since the name of the main class is synthesized;
+ * for example, to create the minor class "bar" you'd write
+ * "class $$CLASSNAME$$.Bar".
+ *
+ *
+ * Since NetRexx has to be _compiled_ to a Java classfile, invoking it involves
+ * a fair amount of computation to load and execute the compiler. We are
+ * currently making an attempt to manage that by caching the class
+ * after it has been loaded, but the indexing is fairly primitive; we
+ * hash against the script string to find the class for it.
+ *
+ * Minor-class .class files are now being deleted after the major class loads.
+ * This coould potentially cause problems.
+ *
+ * @author Joe Kesselman
+ * @author Sanjiva Weerawarana
+ */
+public class NetRexxEngine extends BSFEngineImpl
+{
+ BSFFunctions mgrfuncs;
+ static Hashtable codeToClass=new Hashtable();
+ static String serializeCompilation="";
+ static String placeholder="$$CLASSNAME$$";
+ String minorPrefix;
+
+ private Log logger = LogFactory.getLog(this.getClass().getName());
+
+ /**
+ * Create a scratchfile, open it for writing, return its name.
+ * Relies on the filesystem to provide us with uniqueness testing.
+ * NOTE THAT uniqueFileOffset continues to count; we don't want to
+ * risk reusing a classname we have previously loaded in this session
+ * even if the classfile has been deleted.
+ *
+ * I've made the offset static, due to concerns about reuse/reentrancy
+ * of the NetRexx engine.
+ */
+ private static int uniqueFileOffset=0;
+ private class GeneratedFile
+ {
+ File file=null;
+ FileOutputStream fos=null;
+ String className=null;
+ GeneratedFile(File file,FileOutputStream fos,String className)
+ {
+ this.file=file;
+ this.fos=fos;
+ this.className=className;
+ }
+ }
+
+ // rexxclass used to be an instance variable, on the theory that
+ // each NetRexxEngine was an instance of a specific script.
+ // BSF is currently reusing Engines, so caching the class
+ // no longer makes sense.
+ // Class rexxclass;
+
+ /**
+ * Constructor.
+ */
+ public NetRexxEngine ()
+ {
+ /*
+ The following line is intended to cause the constructor to
+ throw a NoClassDefFoundError if the NetRexxC.zip dependency
+ is not resolved.
+
+ If this line was not here, the problem would not surface until
+ the actual processing of a script. We want to know all is well
+ at the time the engine is instantiated, not when we attempt to
+ process a script.
+ */
+
+ new netrexx.lang.BadArgumentException();
+ }
+ /**
+ * Return an object from an extension.
+ * @param object object from which to call our static method
+ * @param method The name of the method to call.
+ * @param args an array of arguments to be
+ * passed to the extension, which may be either
+ * Vectors of Nodes, or Strings.
+ */
+ public Object call (Object object, String method, Object[] args)
+ throws BSFException
+ {
+ throw new BSFException(BSFException.REASON_UNSUPPORTED_FEATURE,
+ "NetRexx doesn't currently support call()",
+ null);
+ }
+ /**
+ * Invoke a static method.
+ * @param rexxclass Class to invoke the method against
+ * @param method The name of the method to call.
+ * @param args an array of arguments to be
+ * passed to the extension, which may be either
+ * Vectors of Nodes, or Strings.
+ */
+ Object callStatic(Class rexxclass, String method, Object[] args)
+ throws BSFException
+ {
+ //***** ISSUE: Currently supports only static methods
+ Object retval = null;
+ try
+ {
+ if (rexxclass != null)
+ {
+ //***** This should call the lookup used in BML, for typesafety
+ Class[] argtypes=new Class[args.length];
+ for(int i=0;i
+ * Nobody knows whether javac is threadsafe.
+ * I'm going to serialize access to the compilers to protect it.
+ */
+ public Object execEvalShared (String source, int lineNo, int columnNo,
+ Object oscript,boolean returnsObject)
+ throws BSFException
+ {
+ Object retval=null;
+ String classname=null;
+ GeneratedFile gf=null;
+
+ // Moved into the exec process; see comment above.
+ Class rexxclass=null;
+
+ String basescript=oscript.toString();
+ String script=basescript; // May be altered by $$CLASSNAME$$ expansion
+
+ try {
+ // Do we already have a class exactly matching this code?
+ rexxclass=(Class)codeToClass.get(basescript);
+
+ if(rexxclass!=null)
+
+ {
+ logger.debug("NetRexxEngine: Found pre-compiled class" +
+ " for script '" + basescript + "'");
+ classname=rexxclass.getName();
+ }
+ else
+ {
+ gf=openUniqueFile(tempDir,"BSFNetRexx",".nrx");
+ if(gf==null)
+ throw new BSFException("couldn't create NetRexx scratchfile");
+
+ // Obtain classname
+ classname=gf.className;
+
+ // Decide whether to declare a return type
+ String returnsDecl="";
+ if(returnsObject)
+ returnsDecl="returns java.lang.Object";
+
+ // Write the kluge header to the file.
+ // ***** By doing so we give up the ability to use Property blocks.
+ gf.fos.write(("class "+classname+";\n")
+ .getBytes());
+ gf.fos.write(
+ ("method BSFNetRexxEngineEntry(bsf=com.volmit.iris.util.bsf.util.BSFFunctions) "+
+ " public static "+returnsDecl+";\n")
+ .getBytes());
+
+ // Edit the script to replace placeholder with the generated
+ // classname. Note that this occurs _after_ the cache was
+ // checked!
+ int startpoint,endpoint;
+ if((startpoint=script.indexOf(placeholder))>=0)
+ {
+ StringBuffer changed=new StringBuffer();
+ for(;
+ startpoint>=0;
+ startpoint=script.indexOf(placeholder,startpoint))
+ {
+ changed.setLength(0); // Reset for 2nd pass or later
+ if(startpoint>0)
+ changed.append(script.substring(0,startpoint));
+ changed.append(classname);
+ endpoint=startpoint+placeholder.length();
+ if(endpoint
+ *
+ * @author Sanjiva Weerawarana
+ * @author Olivier Gruber (added original debugging support)
+ */
+
+public abstract class BSFEngineImpl implements BSFEngine {
+
+ protected BSFManager mgr; // my manager
+ protected String lang; // my language string
+ protected Vector declaredBeans; // BSFDeclaredBeans
+ protected String classPath;
+ protected String tempDir;
+ protected ClassLoader classLoader;
+
+ /**
+ * Default impl of apply - calls eval ignoring parameters and returns
+ * the result.
+ */
+ public Object apply(String source, int lineNo, int columnNo,
+ Object funcBody, Vector paramNames, Vector arguments)
+ throws BSFException {
+ return eval(source, lineNo, columnNo, funcBody);
+ }
+
+ /**
+ * Default impl of compileApply - calls compileExpr ignoring parameters.
+ */
+ public void compileApply(String source, int lineNo, int columnNo,
+ Object funcBody, Vector paramNames,
+ Vector arguments, CodeBuffer cb)
+ throws BSFException {
+ compileExpr(source, lineNo, columnNo, funcBody, cb);
+ }
+
+ /**
+ * Default impl of compileExpr - generates code that'll create a new
+ * manager, evaluate the expression, and return the value.
+ */
+ public void compileExpr(String source, int lineNo, int columnNo,
+ Object expr, CodeBuffer cb) throws BSFException {
+ ObjInfo bsfInfo = cb.getSymbol("bsf");
+
+ if (bsfInfo == null) {
+ bsfInfo = new ObjInfo(BSFManager.class, "bsf");
+ cb.addFieldDeclaration("com.volmit.iris.util.bsf.BSFManager bsf = " +
+ "new com.volmit.iris.util.bsf.BSFManager();");
+ cb.putSymbol("bsf", bsfInfo);
+ }
+
+ String evalString = bsfInfo.objName + ".eval(\"" + lang + "\", ";
+ evalString += "request.getRequestURI(), " + lineNo + ", " + columnNo;
+ evalString += "," + StringUtils.lineSeparator;
+ evalString += StringUtils.getSafeString(expr.toString()) + ")";
+
+ ObjInfo oldRet = cb.getFinalServiceMethodStatement();
+
+ if (oldRet != null && oldRet.isExecutable()) {
+ cb.addServiceMethodStatement(oldRet.objName + ";");
+ }
+
+ cb.setFinalServiceMethodStatement(new ObjInfo(Object.class,
+ evalString));
+
+ cb.addServiceMethodException("com.volmit.iris.util.bsf.BSFException");
+ }
+
+ /**
+ * Default impl of compileScript - generates code that'll create a new
+ * manager, and execute the script.
+ */
+ public void compileScript(String source, int lineNo, int columnNo,
+ Object script, CodeBuffer cb)
+ throws BSFException {
+ ObjInfo bsfInfo = cb.getSymbol("bsf");
+
+ if (bsfInfo == null) {
+ bsfInfo = new ObjInfo(BSFManager.class, "bsf");
+ cb.addFieldDeclaration("com.volmit.iris.util.bsf.BSFManager bsf = " +
+ "new com.volmit.iris.util.bsf.BSFManager();");
+ cb.putSymbol("bsf", bsfInfo);
+ }
+
+ String execString = bsfInfo.objName + ".exec(\"" + lang + "\", ";
+ execString += "request.getRequestURI(), " + lineNo + ", " + columnNo;
+ execString += "," + StringUtils.lineSeparator;
+ execString += StringUtils.getSafeString(script.toString()) + ")";
+
+ ObjInfo oldRet = cb.getFinalServiceMethodStatement();
+
+ if (oldRet != null && oldRet.isExecutable()) {
+ cb.addServiceMethodStatement(oldRet.objName + ";");
+ }
+
+ cb.setFinalServiceMethodStatement(new ObjInfo(void.class, execString));
+
+ cb.addServiceMethodException("com.volmit.iris.util.bsf.BSFException");
+ }
+
+ public void declareBean(BSFDeclaredBean bean) throws BSFException {
+ throw new BSFException(BSFException.REASON_UNSUPPORTED_FEATURE,
+ "language " + lang +
+ " does not support declareBean(...).");
+ }
+
+ /**
+ * Default impl of execute - calls eval and ignores the result.
+ */
+ public void exec(String source, int lineNo, int columnNo, Object script)
+ throws BSFException {
+ eval(source, lineNo, columnNo, script);
+ }
+
+ /**
+ * Default impl of interactive execution - calls eval and ignores the result.
+ */
+ public void iexec(String source, int lineNo, int columnNo, Object script)
+ throws BSFException {
+ eval(source, lineNo, columnNo, script);
+ }
+
+ /**
+ * initialize the engine; called right after construction by
+ * the manager. Declared beans are simply kept in a vector and
+ * that's it. Subclasses must do whatever they want with it.
+ */
+ public void initialize(BSFManager mgr, String lang, Vector declaredBeans)
+ throws BSFException {
+
+ this.mgr = mgr;
+ this.lang = lang;
+ this.declaredBeans = declaredBeans;
+
+ // initialize my properties from those of the manager. It'll send
+ // propagate change events to me
+ this.classPath = mgr.getClassPath();
+ this.tempDir = mgr.getTempDir();
+ this.classLoader = mgr.getClassLoader();
+ }
+
+ /**
+ * Receive property change events from the manager and update my fields
+ * as needed.
+ *
+ * @param e PropertyChange event with the change data
+ */
+ public void propertyChange(PropertyChangeEvent e) {
+ String name = e.getPropertyName();
+ Object value = e.getNewValue();
+
+ if (name.equals("classPath")) {
+ classPath = (String) value;
+ }
+ else if (name.equals("tempDir")) {
+ tempDir = (String) value;
+ }
+ else if (name.equals("classLoader")) {
+ classLoader = (ClassLoader) value;
+ }
+ }
+
+ public void terminate() {
+ mgr = null;
+ declaredBeans = null;
+ classLoader = null;
+ }
+
+ public void undeclareBean(BSFDeclaredBean bean) throws BSFException {
+ throw new BSFException(BSFException.REASON_UNSUPPORTED_FEATURE,
+ "language " + lang +
+ " does not support undeclareBean(...).");
+ }
+}
diff --git a/src/main/java/com/volmit/iris/util/bsf/util/BSFEventProcessor.java b/src/main/java/com/volmit/iris/util/bsf/util/BSFEventProcessor.java
new file mode 100644
index 000000000..b59baca29
--- /dev/null
+++ b/src/main/java/com/volmit/iris/util/bsf/util/BSFEventProcessor.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright 2004,2004 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.volmit.iris.util.bsf.util;
+
+import com.volmit.iris.util.bsf.BSFEngine;
+import com.volmit.iris.util.bsf.BSFException;
+import com.volmit.iris.util.bsf.BSFManager;
+import com.volmit.iris.util.bsf.util.event.EventProcessor;
+
+/**
+ * This is used to support binding scripts to be run when an event
+ * occurs.
+ *
+ * @author Sanjiva Weerawarana
+ */
+public class BSFEventProcessor implements EventProcessor {
+ BSFEngine engine;
+ BSFManager manager;
+ String filter;
+ String source;
+ int lineNo;
+ int columnNo;
+ Object script;
+
+ /**
+ * Package-protected constructor makes this class unavailable for
+ * public use.
+ */
+ BSFEventProcessor (BSFEngine engine, BSFManager manager, String filter,
+ String source, int lineNo, int columnNo, Object script)
+ throws BSFException {
+ this.engine = engine;
+ this.manager = manager;
+ this.filter = filter;
+ this.source = source;
+ this.lineNo = lineNo;
+ this.columnNo = columnNo;
+ this.script = script;
+ }
+ //////////////////////////////////////////////////////////////////////////
+ //
+ // event is delegated to me by the adapters using this. inFilter is
+ // in general the name of the method via which the event was received
+ // at the adapter. For prop/veto change events, inFilter is the name
+ // of the property. In any case, in the event processor, I only forward
+ // those events if for which the filters match (if one is specified).
+
+ public void processEvent (String inFilter, Object[] evtInfo) {
+ try {
+ processExceptionableEvent (inFilter, evtInfo);
+ } catch (RuntimeException re) {
+ // rethrow this .. I don't want to intercept run-time stuff
+ // that can in fact occur legit
+ throw re;
+ } catch (Exception e) {
+ // should not occur
+ System.err.println ("BSFError: non-exceptionable event delivery " +
+ "threw exception (that's not nice): " + e);
+ e.printStackTrace ();
+ }
+ }
+ //////////////////////////////////////////////////////////////////////////
+ //
+ // same as above, but used when the method event method may generate
+ // an exception which must go all the way back to the source (as in
+ // the vetoableChange case)
+
+ public void processExceptionableEvent (String inFilter, Object[] evtInfo) throws Exception
+ {
+ if ((filter != null) && !filter.equals (inFilter)) {
+ // ignore this event
+ return;
+ }
+
+ // run the script
+ engine.exec (source, lineNo, columnNo, script);
+ }
+}
diff --git a/src/main/java/com/volmit/iris/util/bsf/util/BSFEventProcessorReturningEventInfos.java b/src/main/java/com/volmit/iris/util/bsf/util/BSFEventProcessorReturningEventInfos.java
new file mode 100644
index 000000000..a8aac16b1
--- /dev/null
+++ b/src/main/java/com/volmit/iris/util/bsf/util/BSFEventProcessorReturningEventInfos.java
@@ -0,0 +1,164 @@
+/*
+ * This software consists of voluntary contributions made by many individuals
+ * on behalf of the Apache Software Foundation and was originally created by
+ * Sanjiva Weerawarana and others at International Business Machines
+ * Corporation. For more information on the Apache Software Foundation,
+ * please see
+ * The CFDriver is a stand-alone tool that will instantiate a
+ *
+ * Usage:
+ *
+ * args:
+ *
+ * [-in fileName] default: <STDIN>
+ * [-out fileName] default: <STDOUT>
+ * [-maxLine length] default: 74
+ * [-step size] default: 2
+ * [-delim group] default: (+
+ * [-sdelim group] default: ,
+ *
+ * Each character represents one delimiter. If a line is ready to be
+ * word-wrapped and a delimiter is encountered, the delimiter will
+ * appear as the first character on the following line.
+ * A quotation mark,
+ * This is the number of spaces that lines will be indented (when appropriate).
+ *
+ * @param newIndentationStep the new size of the indentation step.
+ * @see #getIndentationStep
+ */
+ public void setIndentationStep(int newIndentationStep)
+ {
+ indentationStep = (newIndentationStep < 0 ? 0 : newIndentationStep);
+ }
+ /**
+ * Sets the (desired) maximum line length; default length is
+ *
+ * If a token is longer than the requested maximum line length,
+ * then the line containing that token will obviously be longer
+ * than the desired maximum.
+ *
+ * @param newMaxLineLength the new maximum line length.
+ * @see #getMaxLineLength
+ */
+ public void setMaxLineLength(int newMaxLineLength)
+ {
+ maxLineLength = (newMaxLineLength < 0 ? 0 : newMaxLineLength);
+ }
+ /**
+ * Sets the set of sticky delimiters; default set is
+ * Each character represents one sticky delimiter. If a line is ready
+ * to be word-wrapped and a sticky delimiter is encountered, the sticky
+ * delimiter will appear as the last character on the current line.
+ * A quotation mark,
+ * This implementation first looks for an adapter in its lookup table
+ * and if it doesn't find one looks for a standard implementation of
+ * that adapter in the com.volmit.iris.util.bsf.util.event.adapters package with a
+ * standard naming convention. The naming convention it assumes is the
+ * following: for event listener type a.b.c.FooListener,
+ * it loads an adapter of type
+ * com.volmit.iris.util.bsf.util.event.adapters.a_b_c_FooAdapter.
+ * If both the loading and the dynamic generation fail, then a
+ *
+ *
+ * @author Sanjiva Weerawarana
+ * @author Matthew J. Duftler
+ * @see EventAdapter
+ */
+public class EventAdapterRegistry {
+ private static Hashtable reg = new Hashtable ();
+ private static ClassLoader cl = null;
+ private static String adapterPackage = "com.volmit.iris.util.bsf.util.event.adapters";
+ private static String adapterSuffix = "Adapter";
+ private static boolean dynamic = true;
+
+ public static Class lookup (Class listenerType) {
+ String key = listenerType.getName().replace ('.', '_');
+ Class adapterClass = (Class) reg.get (key);
+
+ if (adapterClass == null) {
+ String en = key.substring (0, key.lastIndexOf ("Listener"));
+ String cn = adapterPackage + "." + en + adapterSuffix;
+
+ try {
+ // Try to resolve one.
+ // adapterClass = (cl != null) ? cl.loadClass (cn) : Class.forName (cn);
+ adapterClass = (cl != null) ? cl.loadClass (cn)
+ : Thread.currentThread().getContextClassLoader().loadClass (cn); // rgf, 2006-01-05
+
+ } catch (ClassNotFoundException e) {
+ if (dynamic) {
+ // Unable to resolve one, try to generate one.
+ adapterClass = // if second argument is set to 'true', then the class file will be stored in the filesystem
+ EventAdapterGenerator.makeEventAdapterClass (listenerType, false);
+ }
+ }
+
+ if (adapterClass != null) {
+ reg.put (key, adapterClass);
+ }
+ }
+
+ return adapterClass;
+ }
+ public static void register (Class listenerType, Class eventAdapterClass) {
+ String key = listenerType.getName().replace('.', '_');
+ reg.put (key, eventAdapterClass);
+ }
+ /**
+ * Class loader to use to load event adapter classes.
+ */
+ public static void setClassLoader (ClassLoader cloader) {
+ cl = cloader;
+ }
+ /**
+ * Indicates whether or not to dynamically generate adapters; default is
+ *
+ * If the
+ *
+ * $$CLASSNAME$$ will be replaced by a generated classname of the form
+ * BSFJava*, and the bsf parameter can be used to retrieve application
+ * objects registered with the Bean Scripting Framework.
+ *
+ * import java.lang.*;
+ * import java.util.*;
+ * public class $$CLASSNAME$$ {
+ * static public Object BSFJavaEngineEntry(com.volmit.iris.util.bsf.BSFManager bsf) {
+ * // Your code will be placed here
+ * }
+ * }
+ *
+ * Hazards:
+ *
+ *
+ * $$CLASSNAME$$ will be replaced by a generated classname of the form
+ * BSFNetRexx*, and the bsf parameter can be used to retrieve application
+ * objects registered with the Bean Scripting Framework.
+ *
+ * class $$CLASSNAME$$;
+ * method BSFNetRexxEngineEntry(bsf=com.volmit.iris.util.bsf.BSFManager) public static;
+ *
+ * Hazards:
+ * CodeBuffer
object is used as a code repository for generated Java code.
+ * It provides buffers which correspond to the various sections of a Java class.
+ *
+ * @author Matthew J. Duftler
+ */
+public class CodeBuffer
+{
+ private StringWriter fieldDeclSW = new StringWriter(),
+ methodDeclSW = new StringWriter(),
+ initializerSW = new StringWriter(),
+ constructorSW = new StringWriter(),
+ serviceMethodSW = new StringWriter();
+
+ private PrintWriter fieldDeclPW = new PrintWriter(fieldDeclSW),
+ methodDeclPW = new PrintWriter(methodDeclSW),
+ initializerPW = new PrintWriter(initializerSW),
+ constructorPW = new PrintWriter(constructorSW),
+ serviceMethodPW = new PrintWriter(serviceMethodSW);
+
+ private Stack symbolTableStack = new Stack();
+ private Hashtable symbolTable = new Hashtable(),
+ usedSymbolIndices = new Hashtable();
+
+ private ObjInfo finalStatementInfo;
+ private CodeBuffer parent;
+
+
+ {
+ symbolTableStack.push(symbolTable);
+ }
+
+ // New stuff...
+ private Vector imports = new Vector(),
+ constructorArguments = new Vector(),
+ constructorExceptions = new Vector(),
+ serviceMethodExceptions = new Vector(),
+ implementsVector = new Vector();
+ private String packageName = null,
+ className = "Test",
+ serviceMethodName = "exec",
+ extendsName = null;
+ private Class serviceMethodReturnType = void.class;
+
+ public CodeBuffer()
+ {
+ }
+ public CodeBuffer(CodeBuffer parent)
+ {
+ this.parent = parent;
+ }
+ public void addConstructorArgument(ObjInfo arg)
+ {
+ constructorArguments.addElement(arg);
+ }
+ public void addConstructorException(String exceptionName)
+ {
+ if (!constructorExceptions.contains(exceptionName))
+ {
+ constructorExceptions.addElement(exceptionName);
+ }
+ }
+ public void addConstructorStatement(String statement)
+ {
+ constructorPW.println(statement);
+ }
+ public void addFieldDeclaration(String statement)
+ {
+ fieldDeclPW.println(statement);
+ }
+ public void addImplements(String importName)
+ {
+ if (!implementsVector.contains(importName))
+ {
+ implementsVector.addElement(importName);
+ }
+ }
+ public void addImport(String importName)
+ {
+ if (!imports.contains(importName))
+ {
+ imports.addElement(importName);
+ }
+ }
+ public void addInitializerStatement(String statement)
+ {
+ initializerPW.println(statement);
+ }
+ public void addMethodDeclaration(String statement)
+ {
+ methodDeclPW.println(statement);
+ }
+ public void addServiceMethodException(String exceptionName)
+ {
+ if (!serviceMethodExceptions.contains(exceptionName))
+ {
+ serviceMethodExceptions.addElement(exceptionName);
+ }
+ }
+ public void addServiceMethodStatement(String statement)
+ {
+ serviceMethodPW.println(statement);
+ }
+ // Used internally by merge(...).
+ private void appendIfNecessary(PrintWriter pw, StringBuffer buf)
+ {
+ if (buf.length() > 0)
+ {
+ pw.print(buf.toString());
+ }
+ }
+ public String buildNewSymbol(String prefix)
+ {
+ Integer nextNum = getSymbolIndex(prefix);
+
+ if (nextNum == null)
+ {
+ nextNum = new Integer(0);
+ }
+
+ int iNextNum = nextNum.intValue();
+ String symbol = prefix + "_" + iNextNum;
+
+ while (getSymbol(symbol) != null)
+ {
+ iNextNum++;
+ symbol = prefix + "_" + iNextNum;
+ }
+
+ putSymbolIndex(prefix, new Integer(iNextNum + 1));
+
+ return symbol;
+ }
+ public void clearSymbolTable()
+ {
+ symbolTable = new Hashtable();
+ symbolTableStack = new Stack();
+ symbolTableStack.push(symbolTable);
+
+ usedSymbolIndices = new Hashtable();
+ }
+ public String getClassName()
+ {
+ return className;
+ }
+ public Vector getConstructorArguments()
+ {
+ return constructorArguments;
+ }
+ public StringBuffer getConstructorBuffer()
+ {
+ constructorPW.flush();
+
+ return constructorSW.getBuffer();
+ }
+ public Vector getConstructorExceptions()
+ {
+ return constructorExceptions;
+ }
+ public String getExtends()
+ {
+ return extendsName;
+ }
+ public StringBuffer getFieldBuffer()
+ {
+ fieldDeclPW.flush();
+
+ return fieldDeclSW.getBuffer();
+ }
+ public ObjInfo getFinalServiceMethodStatement()
+ {
+ return finalStatementInfo;
+ }
+ public Vector getImplements()
+ {
+ return implementsVector;
+ }
+ public Vector getImports()
+ {
+ return imports;
+ }
+ public StringBuffer getInitializerBuffer()
+ {
+ initializerPW.flush();
+
+ return initializerSW.getBuffer();
+ }
+ public StringBuffer getMethodBuffer()
+ {
+ methodDeclPW.flush();
+
+ return methodDeclSW.getBuffer();
+ }
+ public String getPackageName()
+ {
+ return packageName;
+ }
+ public StringBuffer getServiceMethodBuffer()
+ {
+ serviceMethodPW.flush();
+
+ return serviceMethodSW.getBuffer();
+ }
+ public Vector getServiceMethodExceptions()
+ {
+ return serviceMethodExceptions;
+ }
+ public String getServiceMethodName()
+ {
+ return serviceMethodName;
+ }
+ public Class getServiceMethodReturnType()
+ {
+ if (finalStatementInfo != null)
+ {
+ return finalStatementInfo.objClass;
+ }
+ else if (serviceMethodReturnType != null)
+ {
+ return serviceMethodReturnType;
+ }
+ else
+ {
+ return void.class;
+ }
+ }
+ public ObjInfo getSymbol(String symbol)
+ {
+ ObjInfo ret = (ObjInfo)symbolTable.get(symbol);
+
+ if (ret == null && parent != null)
+ ret = parent.getSymbol(symbol);
+
+ return ret;
+ }
+ Integer getSymbolIndex(String prefix)
+ {
+ if (parent != null)
+ {
+ return parent.getSymbolIndex(prefix);
+ }
+ else
+ {
+ return (Integer)usedSymbolIndices.get(prefix);
+ }
+ }
+ public Hashtable getSymbolTable()
+ {
+ return symbolTable;
+ }
+ public void merge(CodeBuffer otherCB)
+ {
+ Vector otherImports = otherCB.getImports();
+
+ for (int i = 0; i < otherImports.size(); i++)
+ {
+ addImport((String)otherImports.elementAt(i));
+ }
+
+ appendIfNecessary(fieldDeclPW, otherCB.getFieldBuffer());
+ appendIfNecessary(methodDeclPW, otherCB.getMethodBuffer());
+ appendIfNecessary(initializerPW, otherCB.getInitializerBuffer());
+ appendIfNecessary(constructorPW, otherCB.getConstructorBuffer());
+ appendIfNecessary(serviceMethodPW, otherCB.getServiceMethodBuffer());
+
+ ObjInfo oldRet = getFinalServiceMethodStatement();
+
+ if (oldRet != null && oldRet.isExecutable())
+ {
+ addServiceMethodStatement(oldRet.objName + ";");
+ }
+
+ setFinalServiceMethodStatement(otherCB.getFinalServiceMethodStatement());
+ }
+ public void popSymbolTable()
+ {
+ symbolTableStack.pop();
+ symbolTable = (Hashtable)symbolTableStack.peek();
+ }
+ public void print(PrintWriter out, boolean formatOutput)
+ {
+ if (formatOutput)
+ {
+ new CodeFormatter().formatCode(new StringReader(toString()), out);
+ }
+ else
+ {
+ out.print(toString());
+ }
+
+ out.flush();
+ }
+ public void pushSymbolTable()
+ {
+ symbolTable = (Hashtable)symbolTableStack.push(new ScriptSymbolTable(symbolTable));
+ }
+ public void putSymbol(String symbol, ObjInfo obj)
+ {
+ symbolTable.put(symbol, obj);
+ }
+ void putSymbolIndex(String prefix, Integer index)
+ {
+ if (parent != null)
+ {
+ parent.putSymbolIndex(prefix, index);
+ }
+ else
+ {
+ usedSymbolIndices.put(prefix, index);
+ }
+ }
+ public void setClassName(String className)
+ {
+ this.className = className;
+ }
+ public void setExtends(String extendsName)
+ {
+ this.extendsName = extendsName;
+ }
+ public void setFinalServiceMethodStatement(ObjInfo finalStatementInfo)
+ {
+ this.finalStatementInfo = finalStatementInfo;
+ }
+ public void setPackageName(String packageName)
+ {
+ this.packageName = packageName;
+ }
+ public void setServiceMethodName(String serviceMethodName)
+ {
+ this.serviceMethodName = serviceMethodName;
+ }
+ public void setServiceMethodReturnType(Class serviceMethodReturnType)
+ {
+ this.serviceMethodReturnType = serviceMethodReturnType;
+ }
+ public void setSymbolTable(Hashtable symbolTable)
+ {
+ this.symbolTable = symbolTable;
+ }
+ public boolean symbolTableIsStacked()
+ {
+ return (symbolTable instanceof ScriptSymbolTable);
+ }
+ public String toString()
+ {
+ StringWriter sw = new StringWriter();
+ PrintWriter pw = new PrintWriter(sw);
+ ObjInfo ret = finalStatementInfo;
+
+ if (packageName != null && !packageName.equals(""))
+ {
+ pw.println("package " + packageName + ";");
+ pw.println();
+ }
+
+ if (imports.size() > 0)
+ {
+ for (int i = 0; i < imports.size(); i++)
+ {
+ pw.println("import " + imports.elementAt(i) + ";");
+ }
+
+ pw.println();
+ }
+
+ pw.println("public class " + className +
+ (extendsName != null && !extendsName.equals("")
+ ? " extends " + extendsName
+ : "") +
+ (implementsVector.size() > 0
+ ? " implements " +
+ StringUtils.getCommaListFromVector(implementsVector)
+ : "")
+ );
+ pw.println("{");
+
+ pw.print(getFieldBuffer().toString());
+
+ StringBuffer buf = getInitializerBuffer();
+
+ if (buf.length() > 0)
+ {
+ pw.println();
+ pw.println("{");
+ pw.print(buf.toString());
+ pw.println("}");
+ }
+
+ buf = getConstructorBuffer();
+
+ if (buf.length() > 0)
+ {
+ pw.println();
+ pw.println("public " + className + "(" +
+ (constructorArguments.size() > 0
+ ? StringUtils.getCommaListFromVector(constructorArguments)
+ : ""
+ ) + ")" +
+ (constructorExceptions.size() > 0
+ ? " throws " +
+ StringUtils.getCommaListFromVector(constructorExceptions)
+ : ""
+ )
+ );
+ pw.println("{");
+ pw.print(buf.toString());
+ pw.println("}");
+ }
+
+ buf = getServiceMethodBuffer();
+
+ if (buf.length() > 0 || ret != null)
+ {
+ pw.println();
+ pw.println("public " +
+ StringUtils.getClassName(getServiceMethodReturnType()) + " " +
+ serviceMethodName + "()" +
+ (serviceMethodExceptions.size() > 0
+ ? " throws " +
+ StringUtils.getCommaListFromVector(serviceMethodExceptions)
+ : ""
+ )
+ );
+ pw.println("{");
+
+ pw.print(buf.toString());
+
+ if (ret != null)
+ {
+ if (ret.isValueReturning())
+ {
+ pw.println();
+ pw.println("return " + ret.objName + ";");
+ }
+ else if (ret.isExecutable())
+ {
+ pw.println(ret.objName + ";");
+ }
+ }
+
+ pw.println("}");
+ }
+
+ pw.print(getMethodBuffer().toString());
+
+ pw.println("}");
+
+ pw.flush();
+
+ return sw.toString();
+ }
+}
diff --git a/src/main/java/com/volmit/iris/util/bsf/util/EngineUtils.java b/src/main/java/com/volmit/iris/util/bsf/util/EngineUtils.java
new file mode 100644
index 000000000..90e32f73f
--- /dev/null
+++ b/src/main/java/com/volmit/iris/util/bsf/util/EngineUtils.java
@@ -0,0 +1,379 @@
+/*
+ * Copyright 2004,2004 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.volmit.iris.util.bsf.util;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+
+import com.volmit.iris.util.bsf.BSFEngine;
+import com.volmit.iris.util.bsf.BSFException;
+import com.volmit.iris.util.bsf.BSFManager;
+
+/**
+ * This class contains utilities that language integrators can use
+ * when implementing the BSFEngine interface.
+ *
+ * @author Sanjiva Weerawarana
+ * @author Sam Ruby
+ * @author Rony G. Flatscher (added addEventListenerReturningEventInfos)
+ */
+public class EngineUtils {
+ // the BSF class loader that knows how to load from the a specific
+ // temp directory
+ static BSFClassLoader bsfCL;
+
+ // ---rgf, 2003-02-13, determine whether changing accessibility of Methods is possible
+ static boolean bMethodHasSetAccessible=false;
+ static {
+ Class mc=Method.class; // get the "Method" class object
+ Class arg[]={boolean.class}; // define an array with the primitive "boolean" pseudo class object
+ try {
+ mc.getMethod("setAccessible", arg ); // is this method available?
+ bMethodHasSetAccessible=true; // no exception, hence method exists
+ }
+ catch (Exception e)
+ {
+ bMethodHasSetAccessible=false;// exception occurred, hence method does not exist
+ }
+ }
+
+
+ /**
+ * Add a script as a listener to some event coming out of an object. The
+ * first two args identify the src of the event and the event set
+ * and the rest identify the script which should be run when the event
+ * fires.
+ *
+ * @param bean event source
+ * @param eventSetName name of event set from event src to bind to
+ * @param filter filter for events
+ * @param engine BSFEngine which can run this script
+ * @param manager BSFManager of the above engine
+ * @param source (context info) the source of this expression
+ * (e.g., filename)
+ * @param lineNo (context info) the line number in source for expr
+ * @param columnNo (context info) the column number in source for expr
+ * @param script the script to execute when the event occurs
+ *
+ * @exception BSFException if anything goes wrong while running the script
+ */
+ public static void addEventListener (Object bean, String eventSetName,
+ String filter, BSFEngine engine,
+ BSFManager manager, String source,
+ int lineNo, int columnNo,
+ Object script) throws BSFException {
+ BSFEventProcessor ep = new BSFEventProcessor (engine, manager, filter,
+ source, lineNo, columnNo,
+ script);
+
+ try {
+ ReflectionUtils.addEventListener (bean, eventSetName, ep);
+ } catch (Exception e) {
+ e.printStackTrace ();
+ throw new BSFException (BSFException.REASON_OTHER_ERROR,
+ "ouch while adding event listener: "
+ + e, e);
+ }
+ }
+
+
+ /**
+ * Add a script as a listener to some event coming out of an object. The
+ * first two args identify the src of the event and the event set
+ * and the rest identify the script which should be run when the event
+ * fires. The processing will use the engine's apply() method.
+ *
+ * @param bean event source
+ * @param eventSetName name of event set from event src to bind to
+ * @param filter filter for events
+ * @param engine BSFEngine which can run this script
+ * @param manager BSFManager of the above engine
+ * @param source (context info) the source of this expression (e.g., filename)
+ * @param lineNo (context info) the line number in source for expr
+ * @param columnNo (context info) the column number in source for expr
+ * @param script the script to execute when the event occurs
+ * @param dataFromScriptingEngine
+ * this contains any object supplied by the scripting engine and gets sent
+ * back with the supplied script, if the event occurs.
+ * This could be used e.g. for indicating to the scripting engine which
+ * scripting engine object/routine/function/procedure
+ * should be ultimately informed of the event occurrence.
+ *
+ * @exception BSFException if anything goes wrong while running the script
+ */
+ public static void addEventListenerReturningEventInfos ( Object bean,
+ String eventSetName,
+ String filter,
+ BSFEngine engine,
+ BSFManager manager,
+ String source,
+ int lineNo,
+ int columnNo,
+ Object script,
+ Object dataFromScriptingEngine
+ ) throws BSFException
+ {
+ BSFEventProcessorReturningEventInfos ep =
+ new BSFEventProcessorReturningEventInfos (engine,
+ manager,
+ filter,
+ source,
+ lineNo,
+ columnNo,
+ script,
+ dataFromScriptingEngine
+ );
+
+ try {
+ ReflectionUtils.addEventListener (bean, eventSetName, ep);
+ } catch (Exception e) {
+ e.printStackTrace ();
+ throw new BSFException (BSFException.REASON_OTHER_ERROR,
+ "ouch while adding event listener: "
+ + e, e);
+ }
+ }
+
+ /**
+ * Finds and invokes a method with the given signature on the given
+ * bean. The signature of the method that's invoked is first taken
+ * as the types of the args, but if that fails, this tries to convert
+ * any primitive wrapper type args to their primitive counterparts
+ * to see whether a method exists that way. If it does, done.
+ *
+ * @param bean the object on which to invoke the method
+ * @param methodName name of the method
+ * @param args arguments to be given to the method
+ *
+ * @return the result of invoking the method, if any
+ *
+ * @exception BSFException if something goes wrong
+ */
+ public static Object callBeanMethod (Object bean, String methodName,
+ Object[] args) throws BSFException {
+ Class[] argTypes = null;
+ // determine arg types. note that a null argtype
+ // matches any object type
+
+ if (args != null) {
+ argTypes = new Class[args.length];
+ for (int i = 0; i < args.length; i++) {
+ argTypes[i] = (args[i] == null) ? null : args[i].getClass ();
+ }
+ }
+
+ // we want to allow a static call to occur on an object, similar
+ // to what Java allows. So isStaticOnly is set to false.
+ boolean isStaticOnly = false;
+ Class beanClass = (bean instanceof Class) ? (Class)bean :
+ bean.getClass ();
+
+ // now try to call method with the right signature
+ try {
+ Method m;
+ try {
+ m = MethodUtils.getMethod (beanClass, methodName, argTypes,
+ isStaticOnly);
+ } catch (NoSuchMethodException e) {
+ // ok, so that didn't work - now try converting any primitive
+ // wrapper types to their primitive counterparts
+ try {
+ // if args is null the NullPointerException will get caught
+ // below and the right thing'll happen .. ugly but works
+ for (int i = 0; i < args.length; i++) {
+ if (args[i] instanceof Number)
+ {
+ if (args[i] instanceof Byte) argTypes[i] = byte.class;
+ else if (args[i] instanceof Integer) argTypes[i] = int.class;
+ else if (args[i] instanceof Long) argTypes[i] = long.class;
+ else if (args[i] instanceof Float) argTypes[i] = float.class;
+ else if (args[i] instanceof Double ) argTypes[i] = double.class;
+ else if (args[i] instanceof Short ) argTypes[i] = short.class;
+ }
+ else if (args[i] instanceof Boolean) argTypes[i] = boolean.class;
+ else if (args[i] instanceof Character) argTypes[i] = char.class;
+ }
+
+ m = MethodUtils.getMethod (beanClass, methodName, argTypes,
+ isStaticOnly);
+ } catch (Exception e2) {
+ // throw the original
+ throw e;
+ }
+ }
+
+ // call it, and return the result
+ try {
+ return m.invoke (bean, args);
+ }
+ catch (Exception e) // 2003-02-23, --rgf, maybe an IllegalAccessException?
+ {
+ if (e instanceof IllegalAccessException &&
+ bMethodHasSetAccessible &&
+ Modifier.isPublic(m.getModifiers()) ) // if a public method allow access to it
+ {
+ m.setAccessible(true); // allow unconditional access to method
+ return m.invoke (bean, args);
+ }
+ // re-throw the exception
+ throw e;
+ }
+
+ } catch (Exception e) {
+ // something went wrong while invoking method
+ Throwable t = (e instanceof InvocationTargetException) ?
+ ((InvocationTargetException)e).getTargetException () :
+ null;
+ throw new BSFException (BSFException.REASON_OTHER_ERROR,
+ "method invocation failed: " + e +
+ ((t==null) ? "" :
+ (" target exception: " + t)), t);
+ }
+ }
+
+ /**
+ * Creates a new bean. The signature of the constructor that's invoked
+ * is first taken as the types of the args, but if that fails, this tries
+ * to convert any primitive wrapper type args to their primitive
+ * counterparts to see whether a method exists that way. If it does, done.
+ *
+ * @param className fully qualified name of class to instantiate
+ * @param args array of constructor args (or null if none)
+ *
+ * @return the created bean
+ *
+ * @exception BSFException if something goes wrong (@see
+ * org.apache.cs.util.MethodUtils for the real
+ * exceptions that can occur).
+ */
+ public static Object createBean (String className, Object args[])
+ throws BSFException {
+ Bean obj;
+ Class[] argTypes = null;
+
+ if (args != null) {
+ argTypes = new Class[args.length];
+ for (int i = 0; i < args.length; i++) {
+ argTypes[i] = (args[i] != null) ? args[i].getClass () : null;
+ }
+ }
+
+ try {
+ try {
+ obj = ReflectionUtils.createBean (null, className,
+ argTypes, args);
+ return obj.value;
+ } catch (NoSuchMethodException me) {
+ // ok, so that didn't work - now try converting any primitive
+ // wrapper types to their primitive counterparts
+ try {
+ // if args is null the NullPointerException will get caught
+ // below and the right thing'll happen .. ugly but works
+ for (int i = 0; i < args.length; i++) {
+ if (args[i] instanceof Number)
+ argTypes[i] = byte.class;
+ else if (args[i] instanceof Boolean)
+ argTypes[i] = boolean.class;
+ else if (args[i] instanceof Character)
+ argTypes[i] = char.class;
+ }
+ obj = ReflectionUtils.createBean (null, className,
+ argTypes, args);
+ return obj.value;
+ } catch (Exception e) {
+ // throw the previous exception
+ throw me;
+ }
+ }
+ } catch (Exception e) {
+ throw new BSFException (BSFException.REASON_OTHER_ERROR,
+ e.getMessage (), e);
+ }
+ }
+
+ /**
+ * Given a class return the type signature string fragment for it.
+ * That is, return "I" for int, "J" for long, ... etc..
+ *
+ * @param cl class object for whom the signature fragment is needed.
+ *
+ * @return the string representing the type signature
+ */
+ public static String getTypeSignatureString (Class cl) {
+ if (cl.isPrimitive ()) {
+ if (cl == boolean.class)
+ return "Z";
+ else if (cl == byte.class)
+ return "B";
+ else if (cl == char.class)
+ return "C";
+ else if (cl == short.class)
+ return "S";
+ else if (cl == int.class)
+ return "I";
+ else if (cl == long.class)
+ return "J";
+ else if (cl == float.class)
+ return "F";
+ else if (cl == double.class)
+ return "D";
+ else
+ return "V";
+ } else {
+ StringBuffer sb = new StringBuffer ("L");
+ sb.append (cl.getName ());
+ sb.append (";");
+ return sb.toString().replace ('.', '/');
+ }
+ }
+
+ /**
+ * Load a class using the class loader of given manager. If that fails
+ * try using a class loader that loads from the tempdir of the manager.
+ *
+ * @param mgr BSFManager who's classLoader and tempDir props are
+ * consulted
+ * @param name name of the class to load
+ *
+ * @return the loaded class
+ *
+ * @exception BSFException if something goes wrong.
+ */
+ public static Class loadClass (BSFManager mgr, String name)
+ throws BSFException {
+ ClassLoader classLoader = mgr.getClassLoader ();
+
+ try {
+ return (classLoader == null) ?
+ // Class.forName (name)
+ Thread.currentThread().getContextClassLoader().loadClass (name)
+ : classLoader.loadClass (name);
+ } catch (ClassNotFoundException e) {
+ // try to load it from the temp dir using my own class loader
+ try {
+ if (bsfCL == null)
+ bsfCL = new BSFClassLoader ();
+ bsfCL.setTempDir (mgr.getTempDir ());
+ return bsfCL.loadClass (name);
+ } catch (ClassNotFoundException e2) {
+ throw new BSFException (BSFException.REASON_OTHER_ERROR,
+ "unable to load class '" + name + "':" + e, e);
+ }
+ }
+ }
+}
diff --git a/src/main/java/com/volmit/iris/util/bsf/util/IOUtils.java b/src/main/java/com/volmit/iris/util/bsf/util/IOUtils.java
new file mode 100644
index 000000000..45b5a0764
--- /dev/null
+++ b/src/main/java/com/volmit/iris/util/bsf/util/IOUtils.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2004,2004 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.volmit.iris.util.bsf.util;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.Reader;
+import java.io.StringWriter;
+
+/**
+ * This file is a collection of input/output utilities.
+ *
+ * @author Sanjiva Weerawarana
+ * @author Matthew J. Duftler
+ */
+public class IOUtils {
+ // debug flag - generates debug stuff if true
+ static boolean debug = false;
+
+ //////////////////////////////////////////////////////////////////////////
+
+ public static String getStringFromReader (Reader reader) throws IOException {
+ BufferedReader bufIn = new BufferedReader(reader);
+ StringWriter swOut = new StringWriter();
+ PrintWriter pwOut = new PrintWriter(swOut);
+ String tempLine;
+
+ while ((tempLine = bufIn.readLine()) != null) {
+ pwOut.println(tempLine);
+ }
+
+ pwOut.flush();
+
+ return swOut.toString();
+ }
+}
diff --git a/src/main/java/com/volmit/iris/util/bsf/util/IndentWriter.java b/src/main/java/com/volmit/iris/util/bsf/util/IndentWriter.java
new file mode 100644
index 000000000..7141bc041
--- /dev/null
+++ b/src/main/java/com/volmit/iris/util/bsf/util/IndentWriter.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright 2004,2004 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.volmit.iris.util.bsf.util;
+
+import java.io.OutputStream;
+import java.io.PrintWriter;
+import java.io.Writer;
+
+/**
+ * An IndentWriter
object behaves the same as a
+ * PrintWriter
object, with the additional capability
+ * of being able to print strings that are prepended with a specified
+ * amount of spaces.
+ *
+ * @author Matthew J. Duftler
+ */
+public class IndentWriter extends PrintWriter
+{
+ /**
+ * Forwards its arguments to the PrintWriter
constructor
+ * with the same signature.
+ */
+ public IndentWriter(OutputStream out)
+ {
+ super(out);
+ }
+ /**
+ * Forwards its arguments to the PrintWriter
constructor
+ * with the same signature.
+ */
+ public IndentWriter(OutputStream out, boolean autoFlush)
+ {
+ super(out, autoFlush);
+ }
+ /**
+ * Forwards its arguments to the PrintWriter
constructor
+ * with the same signature.
+ */
+ public IndentWriter(Writer out)
+ {
+ super(out);
+ }
+ /**
+ * Forwards its arguments to the PrintWriter
constructor
+ * with the same signature.
+ */
+ public IndentWriter(Writer out, boolean autoFlush)
+ {
+ super(out, autoFlush);
+ }
+ /**
+ * Print the text (indented the specified amount) without inserting a linefeed.
+ *
+ * @param numberOfSpaces the number of spaces to indent the text.
+ * @param text the text to print.
+ */
+ public void print(int numberOfSpaces, String text)
+ {
+ super.print(StringUtils.getChars(numberOfSpaces, ' ') + text);
+ }
+ /**
+ * Print the text (indented the specified amount) and insert a linefeed.
+ *
+ * @param numberOfSpaces the number of spaces to indent the text.
+ * @param text the text to print.
+ */
+ public void println(int numberOfSpaces, String text)
+ {
+ super.println(StringUtils.getChars(numberOfSpaces, ' ') + text);
+ }
+}
diff --git a/src/main/java/com/volmit/iris/util/bsf/util/JNIUtils.c b/src/main/java/com/volmit/iris/util/bsf/util/JNIUtils.c
new file mode 100644
index 000000000..0c18b0cdc
--- /dev/null
+++ b/src/main/java/com/volmit/iris/util/bsf/util/JNIUtils.c
@@ -0,0 +1,228 @@
+/*
+ * Copyright 2003,2004 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include ObjInfo
object is used by a compiler to track the name and
+ * type of a bean.
+ *
+ * @author Matthew J. Duftler
+ */
+public class ObjInfo
+{
+ static private String QUOTE_CHARS = "\'\"",
+ EXEC_CHARS = "(=";
+ public String objName;
+ public Class objClass;
+
+ public ObjInfo(Class objClass, String objName)
+ {
+ this.objClass = objClass;
+ this.objName = objName;
+ }
+ public boolean isExecutable()
+ {
+ char[] chars = objName.toCharArray();
+ char openingChar = ' ';
+ boolean inString = false,
+ inEscapeSequence = false;
+
+ for (int i = 0; i < chars.length; i++)
+ {
+ if (inEscapeSequence)
+ {
+ inEscapeSequence = false;
+ }
+ else if (QUOTE_CHARS.indexOf(chars[i]) != -1)
+ {
+ if (!inString)
+ {
+ openingChar = chars[i];
+ inString = true;
+ }
+ else
+ {
+ if (chars[i] == openingChar)
+ {
+ inString = false;
+ }
+ }
+ }
+ else if (EXEC_CHARS.indexOf(chars[i]) != -1)
+ {
+ if (!inString)
+ {
+ return true;
+ }
+ }
+ else if (inString && chars[i] == '\\')
+ {
+ inEscapeSequence = true;
+ }
+ }
+
+ return false;
+ }
+ public boolean isValueReturning()
+ {
+ return (objClass != void.class && objClass != Void.class);
+ }
+ public String toString()
+ {
+ return StringUtils.getClassName(objClass) + " " + objName;
+ }
+}
diff --git a/src/main/java/com/volmit/iris/util/bsf/util/ObjectRegistry.java b/src/main/java/com/volmit/iris/util/bsf/util/ObjectRegistry.java
new file mode 100644
index 000000000..af6b72267
--- /dev/null
+++ b/src/main/java/com/volmit/iris/util/bsf/util/ObjectRegistry.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2004,2004 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.volmit.iris.util.bsf.util;
+
+import java.util.Hashtable;
+
+/**
+ * The ObjectRegistry is used to do name-to-object reference lookups.
+ * If an ObjectRegistry is passed as a constructor argument, then this
+ * ObjectRegistry will be a cascading registry: when a lookup is
+ * invoked, it will first look in its own table for a name, and if it's not
+ * there, it will cascade to the parent ObjectRegistry.
+ * All registration is always local. [??]
+ *
+ * @author Sanjiva Weerawarana
+ * @author Matthew J. Duftler
+ */
+public class ObjectRegistry {
+ Hashtable reg = new Hashtable ();
+ ObjectRegistry parent = null;
+
+ public ObjectRegistry () {
+ }
+ public ObjectRegistry (ObjectRegistry parent) {
+ this.parent = parent;
+ }
+ // lookup an object: cascade up if needed
+ public Object lookup (String name) throws IllegalArgumentException {
+ Object obj = reg.get (name);
+
+ if (obj == null && parent != null) {
+ obj = parent.lookup (name);
+ }
+
+ if (obj == null) {
+ throw new IllegalArgumentException ("object '" + name + "' not in registry");
+ }
+
+ return obj;
+ }
+ // register an object
+ public void register (String name, Object obj) {
+ reg.put (name, obj);
+ }
+ // unregister an object (silent if unknown name)
+ public void unregister (String name) {
+ reg.remove (name);
+ }
+}
diff --git a/src/main/java/com/volmit/iris/util/bsf/util/ReflectionUtils.java b/src/main/java/com/volmit/iris/util/bsf/util/ReflectionUtils.java
new file mode 100644
index 000000000..ae9e0c36a
--- /dev/null
+++ b/src/main/java/com/volmit/iris/util/bsf/util/ReflectionUtils.java
@@ -0,0 +1,421 @@
+/*
+ * Copyright 2004,2004 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.volmit.iris.util.bsf.util;
+
+import java.beans.BeanInfo;
+import java.beans.Beans;
+import java.beans.EventSetDescriptor;
+import java.beans.FeatureDescriptor;
+import java.beans.IndexedPropertyDescriptor;
+import java.beans.IntrospectionException;
+import java.beans.Introspector;
+import java.beans.PropertyDescriptor;
+import java.io.IOException;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+import com.volmit.iris.util.bsf.util.event.EventAdapter;
+import com.volmit.iris.util.bsf.util.event.EventAdapterRegistry;
+import com.volmit.iris.util.bsf.util.event.EventProcessor;
+import com.volmit.iris.util.bsf.util.type.TypeConvertor;
+import com.volmit.iris.util.bsf.util.type.TypeConvertorRegistry;
+
+/**
+ * This file is a collection of reflection utilities. There are utilities
+ * for creating beans, getting bean infos, setting/getting properties,
+ * and binding events.
+ *
+ * @author Sanjiva Weerawarana
+ * @author Joseph Kesselman
+ */
+public class ReflectionUtils {
+
+ //////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Add an event processor as a listener to some event coming out of an
+ * object.
+ *
+ * @param source event source
+ * @param eventSetName name of event set from event src to bind to
+ * @param processor event processor the event should be delegated to
+ * when it occurs; either via processEvent or
+ * processExceptionableEvent.
+ *
+ * @exception IntrospectionException if unable to introspect
+ * @exception IllegalArgumentException if event set is unknown
+ * @exception IllegalAccessException if the event adapter class or
+ * initializer is not accessible.
+ * @exception InstantiationException if event adapter instantiation fails
+ * @exception InvocationTargetException if something goes wrong while
+ * running add event listener method
+ */
+ public static void addEventListener (Object source, String eventSetName,
+ EventProcessor processor)
+ throws IntrospectionException, IllegalArgumentException,
+ IllegalAccessException, InstantiationException,
+ InvocationTargetException {
+ // find the event set descriptor for this event
+ BeanInfo bi = Introspector.getBeanInfo (source.getClass ());
+ EventSetDescriptor esd = (EventSetDescriptor)
+ findFeatureByName ("event", eventSetName, bi.getEventSetDescriptors ());
+
+ if (esd == null) // no events found, maybe a proxy from OpenOffice.org?
+ {
+ throw new IllegalArgumentException ("event set '" + eventSetName +
+ "' unknown for source type '" + source.getClass () + "'");
+ }
+
+ // get the class object for the event
+ Class listenerType=esd.getListenerType(); // get ListenerType class object from EventSetDescriptor
+
+ // find an event adapter class of the right type
+ Class adapterClass = EventAdapterRegistry.lookup (listenerType);
+ if (adapterClass == null) {
+ throw new IllegalArgumentException ("event adapter for listener type " +
+ "'" + listenerType + "' (eventset " +
+ "'" + eventSetName + "') unknown");
+ }
+
+ // create the event adapter and give it the event processor
+ EventAdapter adapter = (EventAdapter) adapterClass.newInstance ();
+ adapter.setEventProcessor (processor);
+
+ // bind the adapter to the source bean
+ Method addListenerMethod;
+ Object[] args;
+ if (eventSetName.equals ("propertyChange") ||
+ eventSetName.equals ("vetoableChange")) {
+ // In Java 1.2, beans may have direct listener adding methods
+ // for property and vetoable change events which take the
+ // property name as a filter to be applied at the event source.
+ // The filter property of the event processor should be used
+ // in this case to support the source-side filtering.
+ //
+ // ** TBD **: the following two lines need to change appropriately
+ addListenerMethod = esd.getAddListenerMethod ();
+ args = new Object[] {adapter};
+ }
+ else
+ {
+ addListenerMethod = esd.getAddListenerMethod ();
+ args = new Object[] {adapter};
+ }
+ addListenerMethod.invoke (source, args);
+ }
+ //////////////////////////////////////////////////////////////////////////
+
+
+ /**
+ * Create a bean using given class loader and using the appropriate
+ * constructor for the given args of the given arg types.
+
+ * @param cld the class loader to use. If null, Class.forName is used.
+ * @param className name of class to instantiate
+ * @param argTypes array of argument types
+ * @param args array of arguments
+ *
+ * @return the newly created bean
+ *
+ * @exception ClassNotFoundException if class is not loaded
+ * @exception NoSuchMethodException if constructor can't be found
+ * @exception InstantiationException if class can't be instantiated
+ * @exception IllegalAccessException if class is not accessible
+ * @exception IllegalArgumentException if argument problem
+ * @exception InvocationTargetException if constructor excepted
+ * @exception IOException if I/O error in beans.instantiate
+ */
+ public static Bean createBean (ClassLoader cld, String className,
+ Class[] argTypes, Object[] args)
+ throws ClassNotFoundException, NoSuchMethodException,
+ InstantiationException, IllegalAccessException,
+ IllegalArgumentException, InvocationTargetException,
+ IOException {
+ if (argTypes != null) {
+ // find the right constructor and use that to create bean
+ Class cl = (cld != null) ? cld.loadClass (className)
+ : Thread.currentThread().getContextClassLoader().loadClass (className); // rgf, 2006-01-05
+ // : Class.forName (className);
+
+ Constructor c = MethodUtils.getConstructor (cl, argTypes);
+ return new Bean (cl, c.newInstance (args));
+ } else {
+ // create the bean with no args constructor
+ Object obj = Beans.instantiate (cld, className);
+ return new Bean (obj.getClass (), obj);
+ }
+ }
+ //////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Create a bean using given class loader and using the appropriate
+ * constructor for the given args. Figures out the arg types and
+ * calls above.
+
+ * @param cld the class loader to use. If null, Class.forName is used.
+ * @param className name of class to instantiate
+ * @param args array of arguments
+ *
+ * @return the newly created bean
+ *
+ * @exception ClassNotFoundException if class is not loaded
+ * @exception NoSuchMethodException if constructor can't be found
+ * @exception InstantiationException if class can't be instantiated
+ * @exception IllegalAccessException if class is not accessible
+ * @exception IllegalArgumentException if argument problem
+ * @exception InvocationTargetException if constructor excepted
+ * @exception IOException if I/O error in beans.instantiate
+ */
+ public static Bean createBean (ClassLoader cld, String className,
+ Object[] args)
+ throws ClassNotFoundException, NoSuchMethodException,
+ InstantiationException, IllegalAccessException,
+ IllegalArgumentException, InvocationTargetException,
+ IOException {
+ Class[] argTypes = null;
+ if (args != null) {
+ argTypes = new Class[args.length];
+ for (int i = 0; i < args.length; i++) {
+ argTypes[i] = (args[i] != null) ? args[i].getClass () : null;
+ }
+ }
+ return createBean (cld, className, argTypes, args);
+ }
+ //////////////////////////////////////////////////////////////////////////
+
+ /**
+ * locate the item in the fds array whose name is as given. returns
+ * null if not found.
+ */
+ private static
+ FeatureDescriptor findFeatureByName (String featureType, String name,
+ FeatureDescriptor[] fds) {
+ for (int i = 0; i < fds.length; i++) {
+ if (name.equals (fds[i].getName())) {
+ return fds[i];
+ }
+ }
+ return null;
+ }
+ public static Bean getField (Object target, String fieldName)
+ throws IllegalArgumentException, IllegalAccessException {
+ // This is to handle how we do static fields.
+ Class targetClass = (target instanceof Class)
+ ? (Class) target
+ : target.getClass ();
+
+ try {
+ Field f = targetClass.getField (fieldName);
+ Class fieldType = f.getType ();
+
+ // Get the value and return it.
+ Object value = f.get (target);
+ return new Bean (fieldType, value);
+ } catch (NoSuchFieldException e) {
+ throw new IllegalArgumentException ("field '" + fieldName + "' is " +
+ "unknown for '" + target + "'");
+ }
+ }
+ //////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Get a property of a bean.
+ *
+ * @param target the object whose prop is to be gotten
+ * @param propName name of the property to set
+ * @param index index to get (if property is indexed)
+ *
+ * @exception IntrospectionException if unable to introspect
+ * @exception IllegalArgumentException if problems with args: if the
+ * property is unknown, or if the property is given an index
+ * when its not, or if the property is not writeable, or if
+ * the given value cannot be assigned to the it (type mismatch).
+ * @exception IllegalAccessException if read method is not accessible
+ * @exception InvocationTargetException if read method excepts
+ */
+ public static Bean getProperty (Object target, String propName,
+ Integer index)
+ throws IntrospectionException, IllegalArgumentException,
+ IllegalAccessException, InvocationTargetException {
+ // find the property descriptor
+ BeanInfo bi = Introspector.getBeanInfo (target.getClass ());
+ PropertyDescriptor pd = (PropertyDescriptor)
+ findFeatureByName ("property", propName, bi.getPropertyDescriptors ());
+ if (pd == null) {
+ throw new IllegalArgumentException ("property '" + propName + "' is " +
+ "unknown for '" + target + "'");
+ }
+
+ // get read method and type of property
+ Method rm;
+ Class propType;
+ if (index != null) {
+ // if index != null, then property is indexed - pd better be so too
+ if (!(pd instanceof IndexedPropertyDescriptor)) {
+ throw new IllegalArgumentException ("attempt to get non-indexed " +
+ "property '" + propName +
+ "' as being indexed");
+ }
+ IndexedPropertyDescriptor ipd = (IndexedPropertyDescriptor) pd;
+ rm = ipd.getIndexedReadMethod ();
+ propType = ipd.getIndexedPropertyType ();
+ } else {
+ rm = pd.getReadMethod ();
+ propType = pd.getPropertyType ();
+ }
+
+ if (rm == null) {
+ throw new IllegalArgumentException ("property '" + propName +
+ "' is not readable");
+ }
+
+ // now get the value
+ Object propVal = null;
+ if (index != null) {
+ propVal = rm.invoke (target, new Object[] {index});
+ } else {
+ propVal = rm.invoke (target, null);
+ }
+ return new Bean (propType, propVal);
+ }
+ public static void setField (Object target, String fieldName, Bean value,
+ TypeConvertorRegistry tcr)
+ throws IllegalArgumentException, IllegalAccessException {
+ // This is to handle how we do static fields.
+ Class targetClass = (target instanceof Class)
+ ? (Class) target
+ : target.getClass ();
+
+ try {
+ Field f = targetClass.getField (fieldName);
+ Class fieldType = f.getType ();
+
+ // type convert the value if necessary
+ Object fieldVal = null;
+ boolean okeydokey = true;
+ if (fieldType.isAssignableFrom (value.type)) {
+ fieldVal = value.value;
+ } else if (tcr != null) {
+ TypeConvertor cvtor = tcr.lookup (value.type, fieldType);
+ if (cvtor != null) {
+ fieldVal = cvtor.convert (value.type, fieldType, value.value);
+ } else {
+ okeydokey = false;
+ }
+ } else {
+ okeydokey = false;
+ }
+ if (!okeydokey) {
+ throw new IllegalArgumentException ("unable to assign '" + value.value +
+ "' to field '" + fieldName + "'");
+ }
+
+ // now set the value
+ f.set (target, fieldVal);
+ } catch (NoSuchFieldException e) {
+ throw new IllegalArgumentException ("field '" + fieldName + "' is " +
+ "unknown for '" + target + "'");
+ }
+ }
+ //////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Set a property of a bean to a given value.
+ *
+ * @param target the object whose prop is to be set
+ * @param propName name of the property to set
+ * @param index index to set (if property is indexed)
+ * @param value the property value
+ * @param valueType the type of the above (needed when its null)
+ * @param tcr type convertor registry to use to convert value type to
+ * property type if necessary
+ *
+ * @exception IntrospectionException if unable to introspect
+ * @exception IllegalArgumentException if problems with args: if the
+ * property is unknown, or if the property is given an index
+ * when its not, or if the property is not writeable, or if
+ * the given value cannot be assigned to the it (type mismatch).
+ * @exception IllegalAccessException if write method is not accessible
+ * @exception InvocationTargetException if write method excepts
+ */
+ public static void setProperty (Object target, String propName,
+ Integer index, Object value,
+ Class valueType, TypeConvertorRegistry tcr)
+ throws IntrospectionException, IllegalArgumentException,
+ IllegalAccessException, InvocationTargetException {
+ // find the property descriptor
+ BeanInfo bi = Introspector.getBeanInfo (target.getClass ());
+ PropertyDescriptor pd = (PropertyDescriptor)
+ findFeatureByName ("property", propName, bi.getPropertyDescriptors ());
+ if (pd == null) {
+ throw new IllegalArgumentException ("property '" + propName + "' is " +
+ "unknown for '" + target + "'");
+ }
+
+ // get write method and type of property
+ Method wm;
+ Class propType;
+ if (index != null) {
+ // if index != null, then property is indexed - pd better be so too
+ if (!(pd instanceof IndexedPropertyDescriptor)) {
+ throw new IllegalArgumentException ("attempt to set non-indexed " +
+ "property '" + propName +
+ "' as being indexed");
+ }
+ IndexedPropertyDescriptor ipd = (IndexedPropertyDescriptor) pd;
+ wm = ipd.getIndexedWriteMethod ();
+ propType = ipd.getIndexedPropertyType ();
+ } else {
+ wm = pd.getWriteMethod ();
+ propType = pd.getPropertyType ();
+ }
+
+ if (wm == null) {
+ throw new IllegalArgumentException ("property '" + propName +
+ "' is not writeable");
+ }
+
+ // type convert the value if necessary
+ Object propVal = null;
+ boolean okeydokey = true;
+ if (propType.isAssignableFrom (valueType)) {
+ propVal = value;
+ } else if (tcr != null) {
+ TypeConvertor cvtor = tcr.lookup (valueType, propType);
+ if (cvtor != null) {
+ propVal = cvtor.convert (valueType, propType, value);
+ } else {
+ okeydokey = false;
+ }
+ } else {
+ okeydokey = false;
+ }
+ if (!okeydokey) {
+ throw new IllegalArgumentException ("unable to assign '" + value +
+ "' to property '" + propName + "'");
+ }
+
+ // now set the value
+ if (index != null) {
+ wm.invoke (target, new Object[] {index, propVal});
+ } else {
+ wm.invoke (target, new Object[] {propVal});
+ }
+ }
+}
diff --git a/src/main/java/com/volmit/iris/util/bsf/util/ScriptSymbolTable.java b/src/main/java/com/volmit/iris/util/bsf/util/ScriptSymbolTable.java
new file mode 100644
index 000000000..358e365eb
--- /dev/null
+++ b/src/main/java/com/volmit/iris/util/bsf/util/ScriptSymbolTable.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2004,2004 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.volmit.iris.util.bsf.util;
+
+import java.util.Hashtable;
+
+/**
+ * An ScriptSymbolTable
object is used by a CodeBuffer
+ * object to implement nested scopes.
+ *
+ * @author Matthew J. Duftler
+ */
+class ScriptSymbolTable extends Hashtable
+{
+ private Hashtable parentTable;
+
+ ScriptSymbolTable(Hashtable parentTable)
+ {
+ this.parentTable = parentTable;
+ }
+ public synchronized Object get(Object key)
+ {
+ Object ret = super.get(key);
+
+ if (ret == null && parentTable != null)
+ ret = parentTable.get(key);
+
+ return ret;
+ }
+}
diff --git a/src/main/java/com/volmit/iris/util/bsf/util/StringUtils.java b/src/main/java/com/volmit/iris/util/bsf/util/StringUtils.java
new file mode 100644
index 000000000..b512ffc76
--- /dev/null
+++ b/src/main/java/com/volmit/iris/util/bsf/util/StringUtils.java
@@ -0,0 +1,412 @@
+/*
+ * Copyright 2004,2004 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.volmit.iris.util.bsf.util;
+
+import java.beans.Introspector;
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.io.StringReader;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.StringTokenizer;
+import java.util.Vector;
+
+/**
+ * Deals with strings (probably need to elaborate some more).
+ *
+ * @author Matthew J. Duftler
+ */
+public class StringUtils
+{
+ public static final String lineSeparator =
+ System.getProperty("line.separator", "\n");
+ public static final String lineSeparatorStr = cleanString(lineSeparator);
+
+ public static String classNameToVarName(String className)
+ {
+ // Might represent an array.
+ int arrayDim = 0;
+
+ while (className.endsWith("[]"))
+ {
+ className = className.substring(0, className.length() - 2);
+ arrayDim++;
+ }
+
+ int iLastPeriod = className.lastIndexOf('.');
+ String varName = Introspector.decapitalize(
+ iLastPeriod != -1
+ ? className.substring(iLastPeriod + 1)
+ : className);
+
+ if (arrayDim > 0)
+ {
+ varName += "_" + arrayDim + "D";
+ }
+
+ return getValidIdentifierName(varName);
+ }
+ // Ensure that escape sequences are passed through properly.
+ public static String cleanString(String str)
+ {
+ if (str == null)
+ return null;
+ else
+ {
+ char[] charArray = str.toCharArray();
+ StringBuffer sBuf = new StringBuffer();
+
+ for (int i = 0; i < charArray.length; i++)
+ switch (charArray[i])
+ {
+ case '\"' : sBuf.append("\\\"");
+ break;
+ case '\\' : sBuf.append("\\\\");
+ break;
+ case '\n' : sBuf.append("\\n");
+ break;
+ case '\r' : sBuf.append("\\r");
+ break;
+ default : sBuf.append(charArray[i]);
+ break;
+ }
+
+ return sBuf.toString();
+ }
+ }
+ /**
+ * Get a string consisting of numberOfChars
theChars.
+ *
+ * @return a string consisting of numberOfChars
theChars.
+ */
+ public static String getChars(int numberOfChars, char theChar)
+ {
+ if (numberOfChars <= 0)
+ return "";
+
+ StringBuffer sRet = new StringBuffer(numberOfChars);
+
+ for (int i = 0; i < numberOfChars; i++)
+ sRet.append(theChar);
+
+ return sRet.toString();
+ }
+ /*
+ This method will return the correct name for a class object representing
+ a primitive, a single instance of a class, as well as n-dimensional arrays
+ of primitives or instances. This logic is needed to handle the string returned
+ from Class.getName(). If the class object represents a single instance (or
+ a primitive), Class.getName() returns the fully-qualified name of the class
+ and no further work is needed. However, if the class object represents an
+ array (of n dimensions), Class.getName() returns a Descriptor (the Descriptor
+ grammar is defined in section 4.3 of the Java VM Spec). This method will
+ parse the Descriptor if necessary.
+ */
+ public static String getClassName(Class targetClass)
+ {
+ String className = targetClass.getName();
+
+ return targetClass.isArray() ? parseDescriptor(className) : className;
+ }
+ public static String getCommaListFromVector(Vector sourceVector)
+ {
+ StringBuffer strBuf = new StringBuffer();
+
+ for (int i = 0; i < sourceVector.size(); i++)
+ {
+ strBuf.append((i > 0 ? ", " : "") +
+ sourceVector.elementAt(i));
+ }
+
+ return strBuf.toString();
+ }
+ /*
+ Returns a Reader for reading from the specified resource, if the resource
+ points to a stream.
+ */
+ public static Reader getContentAsReader(URL url) throws SecurityException,
+ IllegalArgumentException,
+ IOException
+ {
+ if (url == null)
+ {
+ throw new IllegalArgumentException("URL cannot be null.");
+ }
+
+ try
+ {
+ Object content = url.getContent();
+
+ if (content == null)
+ {
+ throw new IllegalArgumentException("No content.");
+ }
+
+ if (content instanceof InputStream)
+ {
+ Reader in = new InputStreamReader((InputStream)content);
+
+ if (in.ready())
+ {
+ return in;
+ }
+ else
+ {
+ throw new FileNotFoundException();
+ }
+ }
+ else
+ {
+ throw new IllegalArgumentException((content instanceof String)
+ ? (String)content
+ : "This URL points to a: " +
+ StringUtils.getClassName(content.getClass()));
+ }
+ }
+ catch (SecurityException e)
+ {
+ throw new SecurityException("Your JVM's SecurityManager has disallowed this.");
+ }
+ catch (FileNotFoundException e)
+ {
+ throw new FileNotFoundException("This file was not found: " + url);
+ }
+ }
+ /*
+ Shorthand for: IOUtils.getStringFromReader(getContentAsReader(url)).
+ */
+ public static String getContentAsString(URL url) throws SecurityException,
+ IllegalArgumentException,
+ IOException
+ {
+ return IOUtils.getStringFromReader(getContentAsReader(url));
+ }
+ // Handles multi-line strings.
+ public static String getSafeString(String scriptStr)
+ {
+ BufferedReader in = new BufferedReader(new StringReader(scriptStr));
+ StringBuffer strBuf = new StringBuffer();
+ String tempLine,
+ previousLine = null;
+
+ try
+ {
+ while ((tempLine = in.readLine()) != null)
+ {
+ if (previousLine != null)
+ {
+ strBuf.append("\"" + previousLine + lineSeparatorStr + "\" +" +
+ lineSeparator);
+ }
+
+ previousLine = cleanString(tempLine);
+ }
+ }
+ catch (IOException e)
+ {
+ }
+
+ strBuf.append("\"" + (previousLine != null ? previousLine : "") + "\"" +
+ lineSeparator);
+
+ return strBuf.toString();
+ }
+ /*
+ */
+ public static URL getURL(URL contextURL, String spec) throws MalformedURLException
+ {
+ return getURL(contextURL, spec, 1);
+ }
+ /*
+ The recursiveDepth argument is used to insure that the algorithm gives up
+ after hunting 2 levels up in the contextURL's path.
+ */
+ private static URL getURL(URL contextURL, String spec, int recursiveDepth)
+ throws MalformedURLException
+ {
+ URL url = null;
+
+ try
+ {
+ url = new URL(contextURL, spec);
+
+ try
+ {
+ url.openStream();
+ }
+ catch (IOException ioe1)
+ {
+ throw new MalformedURLException("This file was not found: " + url);
+ }
+ }
+ catch (MalformedURLException e1)
+ {
+ url = new URL("file", "", spec);
+
+ try
+ {
+ url.openStream();
+ }
+ catch (IOException ioe2)
+ {
+ if (contextURL != null)
+ {
+ String contextFileName = contextURL.getFile();
+ String parentName = new File(contextFileName).getParent();
+
+ if (parentName != null && recursiveDepth < 3)
+ {
+ return getURL(new URL("file", "", parentName + '/'),
+ spec,
+ recursiveDepth + 1);
+ }
+ }
+
+ throw new MalformedURLException("This file was not found: " + url);
+ }
+ }
+
+ return url;
+ }
+ public static String getValidIdentifierName(String identifierName)
+ {
+ if (identifierName == null || identifierName.length() == 0)
+ return null;
+
+ StringBuffer strBuf = new StringBuffer();
+
+ char[] chars = identifierName.toCharArray();
+
+ strBuf.append(Character.isJavaIdentifierStart(chars[0])
+ ? chars[0]
+ : '_'
+ );
+
+ for (int i = 1; i < chars.length; i++)
+ {
+ strBuf.append(Character.isJavaIdentifierPart(chars[i])
+ ? chars[i]
+ : '_'
+ );
+ }
+
+ return strBuf.toString();
+ }
+ public static boolean isValidIdentifierName(String identifierName)
+ {
+ if (identifierName == null || identifierName.length() == 0)
+ return false;
+
+ char[] chars = identifierName.toCharArray();
+
+ if (!Character.isJavaIdentifierStart(chars[0]))
+ return false;
+
+ for (int i = 1; i < chars.length; i++)
+ if (!Character.isJavaIdentifierPart(chars[i]))
+ return false;
+
+ return true;
+ }
+ public static boolean isValidPackageName(String packageName)
+ {
+ if (packageName == null)
+ return false;
+ else if (packageName.length() == 0)
+ // Empty is ok.
+ return true;
+
+ StringTokenizer strTok = new StringTokenizer(packageName, ".", true);
+
+ // Should have an odd number of tokens (including '.' delimiters).
+ if (strTok.countTokens() % 2 != 1)
+ return false;
+
+ // Must start with a valid identifier name.
+ if (!isValidIdentifierName(strTok.nextToken()))
+ return false;
+
+ // ... followed by 0 or more of ".ValidIdentifier".
+ while (strTok.hasMoreTokens())
+ {
+ // Must be a '.'.
+ if (!strTok.nextToken().equals("."))
+ return false;
+
+ // Must be a valid identifier name.
+ if (strTok.hasMoreTokens())
+ {
+ if (!isValidIdentifierName(strTok.nextToken()))
+ return false;
+ }
+ else
+ return false;
+ }
+
+ return true;
+ }
+ /*
+ See the comment above for getClassName(targetClass)...
+ */
+ private static String parseDescriptor(String className)
+ {
+ char[] classNameChars = className.toCharArray();
+ int arrayDim = 0;
+ int i = 0;
+
+ while (classNameChars[i] == '[')
+ {
+ arrayDim++;
+ i++;
+ }
+
+ StringBuffer classNameBuf = new StringBuffer();
+
+ switch (classNameChars[i++])
+ {
+ case 'B' : classNameBuf.append("byte");
+ break;
+ case 'C' : classNameBuf.append("char");
+ break;
+ case 'D' : classNameBuf.append("double");
+ break;
+ case 'F' : classNameBuf.append("float");
+ break;
+ case 'I' : classNameBuf.append("int");
+ break;
+ case 'J' : classNameBuf.append("long");
+ break;
+ case 'S' : classNameBuf.append("short");
+ break;
+ case 'Z' : classNameBuf.append("boolean");
+ break;
+ case 'L' : classNameBuf.append(classNameChars,
+ i, classNameChars.length - i - 1);
+ break;
+ }
+
+ for (i = 0; i < arrayDim; i++)
+ classNameBuf.append("[]");
+
+ return classNameBuf.toString();
+ }
+}
diff --git a/src/main/java/com/volmit/iris/util/bsf/util/cf/CFDriver.java b/src/main/java/com/volmit/iris/util/bsf/util/cf/CFDriver.java
new file mode 100644
index 000000000..90352395b
--- /dev/null
+++ b/src/main/java/com/volmit/iris/util/bsf/util/cf/CFDriver.java
@@ -0,0 +1,196 @@
+/*
+ * Copyright 2004,2004 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.volmit.iris.util.bsf.util.cf;
+
+import java.io.FileNotFoundException;
+import java.io.FileReader;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.OutputStreamWriter;
+import java.io.Reader;
+import java.io.Writer;
+
+/**
+ * This is an example of how a CodeFormatter
bean can be used.
+ * CodeFormatter
bean, configure it according to your
+ * command-line arguments, and invoke the formatting. Since the
+ * default source of input is stdin
, and the default
+ * target for output is stdout
, a CFDriver
+ * can also be used as a filter.
+ *
+ * @see CodeFormatter
+ *
+ * @version 1.0
+ * @author Matthew J. Duftler
+ */
+public class CFDriver
+{
+ /**
+ * Not used.
+ */
+ public CFDriver()
+ {
+ }
+ /**
+ * A driver for CodeFormatter
.
+ *
+ */
+ public static void main(String[] argv)
+ {
+ if (argv.length % 2 == 0)
+ {
+ String inFile = null,
+ outFile = null,
+ maxLine = null,
+ indStep = null,
+ delim = null,
+ sDelim = null;
+ Reader in = null;
+ Writer out = null;
+ CodeFormatter cf = new CodeFormatter();
+
+ for (int i = 0; i < argv.length; i += 2)
+ {
+ if (argv[i].startsWith("-i"))
+ inFile = argv[i + 1];
+ else if (argv[i].startsWith("-o"))
+ outFile = argv[i + 1];
+ else if (argv[i].startsWith("-m"))
+ maxLine = argv[i + 1];
+ else if (argv[i].startsWith("-st"))
+ indStep = argv[i + 1];
+ else if (argv[i].startsWith("-d"))
+ delim = argv[i + 1];
+ else if (argv[i].startsWith("-sd"))
+ sDelim = argv[i + 1];
+ }
+
+ if (inFile != null)
+ {
+ try
+ {
+ in = new FileReader(inFile);
+ }
+ catch (FileNotFoundException e)
+ {
+ printError("Cannot open input file: " + inFile);
+
+ return;
+ }
+ }
+ else
+ {
+ in = new InputStreamReader(System.in);
+ }
+
+ if (outFile != null)
+ {
+ try
+ {
+ out = new FileWriter(outFile);
+ }
+ catch (IOException e)
+ {
+ printError("Cannot open output file: " + outFile);
+
+ return;
+ }
+ }
+ else
+ {
+ out = new OutputStreamWriter(System.out);
+ }
+
+ if (maxLine != null)
+ {
+ try
+ {
+ cf.setMaxLineLength(Integer.parseInt(maxLine));
+ }
+ catch (NumberFormatException nfe)
+ {
+ printError("Not a valid integer: " + maxLine);
+
+ return;
+ }
+ }
+
+ if (indStep != null)
+ {
+ try
+ {
+ cf.setIndentationStep(Integer.parseInt(indStep));
+ }
+ catch (NumberFormatException nfe)
+ {
+ printError("Not a valid integer: " + indStep);
+
+ return;
+ }
+ }
+
+ if (delim != null)
+ cf.setDelimiters(delim);
+
+ if (sDelim != null)
+ cf.setStickyDelimiters(sDelim);
+
+ cf.formatCode(in, out);
+ }
+ else
+ printHelp();
+ }
+ private static void printError(String errMsg)
+ {
+ System.err.println("ERROR: " + errMsg);
+ }
+ private static void printHelp()
+ {
+ System.out.println("Usage:");
+ System.out.println();
+ System.out.println(" java " + CFDriver.class.getName() + " [args]");
+ System.out.println();
+ System.out.println(" args:");
+ System.out.println();
+ System.out.println(" [-in fileName] default:
+ * java org.apache.cf.CFDriver [args]
+ *
CodeFormatter
bean is used to format raw Java code. It
+ * indents, word-wraps, and replaces tab characters with an amount of space
+ * characters equal to the size of the indentationStep
property.
+ * To create and use a CodeFormatter
, you simply instantiate a
+ * new CodeFormatter
bean, and invoke
+ * formatCode(Reader source, Writer target)
with appropriate
+ * arguments.
+ *
+ * @version 1.0
+ * @author Matthew J. Duftler
+ */
+public class CodeFormatter
+{
+ /**
+ * The default maximum line length.
+ */
+ public static final int DEFAULT_MAX = 74;
+ /**
+ * The default size of the indentation step.
+ */
+ public static final int DEFAULT_STEP = 2;
+ /**
+ * The default set of delimiters.
+ */
+ public static final String DEFAULT_DELIM = "(+";
+ /**
+ * The default set of sticky delimiters.
+ */
+ public static final String DEFAULT_S_DELIM = ",";
+
+ // Configurable Parameters
+ private int maxLineLength = DEFAULT_MAX;
+ private int indentationStep = DEFAULT_STEP;
+ private String delimiters = DEFAULT_DELIM;
+ private String stickyDelimiters = DEFAULT_S_DELIM;
+
+ // Global Variables
+ private int indent;
+ private int hangingIndent;
+ private int origIndent;
+ private boolean inCPP_Comment;
+
+ private void addTok(StringBuffer targetBuf, StringBuffer tokBuf,
+ IndentWriter out)
+ {
+ int tokLength = tokBuf.length(),
+ targetLength = targetBuf.length();
+
+ if (indent + targetLength + tokLength > maxLineLength)
+ {
+ if (targetLength == 0)
+ {
+ out.println(indent, tokBuf.toString());
+ indent = hangingIndent;
+ targetBuf.setLength(0);
+
+ return;
+ }
+ else
+ {
+ out.println(indent, targetBuf.toString().trim());
+ indent = hangingIndent;
+ targetBuf.setLength(0);
+ }
+ }
+
+ targetBuf.append(tokBuf.toString());
+
+ return;
+ }
+ /**
+ * Formats the code read from source
, and writes the formatted
+ * code to target
.
+ *
+ * @param source where to read the unformatted code from.
+ * @param target where to write the formatted code to.
+ */
+ public void formatCode(Reader source, Writer target)
+ {
+ String line;
+ BufferedReader in = new BufferedReader(source);
+ IndentWriter out = new IndentWriter(new BufferedWriter(target), true);
+
+ try
+ {
+ origIndent = 0;
+ inCPP_Comment = false;
+
+ while ((line = in.readLine()) != null)
+ {
+ line = line.trim();
+
+ if (line.length() > 0)
+ {
+ indent = origIndent;
+ hangingIndent = indent + indentationStep;
+ printLine(line, out);
+ }
+ else
+ out.println();
+ }
+ }
+ catch (IOException e)
+ {
+ e.printStackTrace();
+ }
+ }
+ /**
+ * Gets the set of delimiters.
+ *
+ * @return the set of delimiters.
+ * @see #setDelimiters
+ */
+ public String getDelimiters()
+ {
+ return delimiters;
+ }
+ /**
+ * Gets the size of the indentation step.
+ *
+ * @return the size of the indentation step.
+ * @see #setIndentationStep
+ */
+ public int getIndentationStep()
+ {
+ return indentationStep;
+ }
+ /**
+ * Gets the maximum line length.
+ *
+ * @return the maximum line length.
+ * @see #setMaxLineLength
+ */
+ public int getMaxLineLength()
+ {
+ return maxLineLength;
+ }
+ /**
+ * Gets the set of sticky delimiters.
+ *
+ * @return the set of sticky delimiters.
+ * @see #setStickyDelimiters
+ */
+ public String getStickyDelimiters()
+ {
+ return stickyDelimiters;
+ }
+ private void printLine(String line, IndentWriter out)
+ {
+ char[] source = line.toCharArray();
+ char ch;
+ char quoteChar = ' ';
+ boolean inEscapeSequence = false;
+ boolean inString = false;
+ StringBuffer tokBuf = new StringBuffer(),
+ targetBuf = new StringBuffer(hangingIndent + line.length());
+
+ for (int i = 0; i < source.length; i++)
+ {
+ ch = source[i];
+
+ if (inEscapeSequence)
+ {
+ tokBuf.append(ch);
+ inEscapeSequence = false;
+ }
+ else
+ {
+ if (inString)
+ {
+ switch (ch)
+ {
+ case '\\' :
+ tokBuf.append('\\');
+ inEscapeSequence = true;
+ break;
+ case '\'' :
+ case '\"' :
+ tokBuf.append(ch);
+
+ if (ch == quoteChar)
+ {
+ addTok(targetBuf, tokBuf, out);
+ tokBuf.setLength(0);
+ inString = false;
+ }
+ break;
+ case 9 : // pass thru tab characters...
+ tokBuf.append(ch);
+ break;
+ default :
+ if (ch > 31)
+ tokBuf.append(ch);
+ break;
+ }
+ }
+ else // !inString
+ {
+ if (inCPP_Comment)
+ {
+ tokBuf.append(ch);
+
+ if (ch == '/' && i > 0 && source[i - 1] == '*')
+ inCPP_Comment = false;
+ }
+ else
+ {
+ switch (ch)
+ {
+ case '/' :
+ tokBuf.append(ch);
+
+ if (i > 0 && source[i - 1] == '/')
+ {
+ String tokStr = tokBuf.append(source,
+ i + 1,
+ source.length - (i + 1)).toString();
+
+ out.println(indent, targetBuf.append(tokStr).toString());
+
+ return;
+ }
+ break;
+ case '*' :
+ tokBuf.append(ch);
+
+ if (i > 0 && source[i - 1] == '/')
+ inCPP_Comment = true;
+ break;
+ case '\'' :
+ case '\"' :
+ addTok(targetBuf, tokBuf, out);
+ tokBuf.setLength(0);
+ tokBuf.append(ch);
+ quoteChar = ch;
+ inString = true;
+ break;
+ case 9 : // replace tab characters...
+ tokBuf.append(StringUtils.getChars(indentationStep, ' '));
+ break;
+ case '{' :
+ tokBuf.append(ch);
+ origIndent += indentationStep;
+ break;
+ case '}' :
+ tokBuf.append(ch);
+ origIndent -= indentationStep;
+
+ if (i == 0)
+ indent = origIndent;
+ break;
+ default :
+ if (ch > 31)
+ {
+ if (delimiters.indexOf(ch) != -1)
+ {
+ addTok(targetBuf, tokBuf, out);
+ tokBuf.setLength(0);
+ tokBuf.append(ch);
+ }
+ else if (stickyDelimiters.indexOf(ch) != -1)
+ {
+ tokBuf.append(ch);
+ addTok(targetBuf, tokBuf, out);
+ tokBuf.setLength(0);
+ }
+ else
+ tokBuf.append(ch);
+ }
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ if (tokBuf.length() > 0)
+ addTok(targetBuf, tokBuf, out);
+
+ String lastLine = targetBuf.toString().trim();
+
+ if (lastLine.length() > 0)
+ out.println(indent, lastLine);
+ }
+ /**
+ * Sets the set of delimiters; default set is "(+"
.
+ * "
or '
, opening a string
+ * is always a delimiter, whether you specify it or not.
+ *
+ * @param newDelimiters the new set of delimiters.
+ * @see #getDelimiters
+ */
+ public void setDelimiters(String newDelimiters)
+ {
+ delimiters = newDelimiters;
+ }
+ /**
+ * Sets the size of the indentation step; default size is 2
.
+ * 74
.
+ * ","
.
+ * "
or '
, closing a string
+ * is always a sticky delimiter, whether you specify it or not.
+ *
+ * @param newStickyDelimiters the new set of sticky delimiters.
+ * @see #getStickyDelimiters
+ */
+ public void setStickyDelimiters(String newStickyDelimiters)
+ {
+ stickyDelimiters = newStickyDelimiters;
+ }
+}
diff --git a/src/main/java/com/volmit/iris/util/bsf/util/event/EventAdapter.java b/src/main/java/com/volmit/iris/util/bsf/util/event/EventAdapter.java
new file mode 100644
index 000000000..d5faaf2fd
--- /dev/null
+++ b/src/main/java/com/volmit/iris/util/bsf/util/event/EventAdapter.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2004,2004 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.volmit.iris.util.bsf.util.event;
+
+/**
+ * EventAdapter is the interface that all event adapters must
+ * implement in order to work with the automatic event adapter generation
+ * model. This interface requires that the adapter implement a method
+ * that allows setting the event processor delegated to process the event
+ * after the adapter has received the event from the event source. The
+ * task of any event adapter is to receive the event and then delegate it
+ * to the event processor assigned to it, using either
+ * eventProcessor.processEvent or eventProcessor.processExceptionableEvent.
+ *
+ * @author Sanjiva Weerawarana
+ * @author Matthew J. Duftler
+ * @see EventProcessor
+ */
+public interface EventAdapter {
+ public void setEventProcessor (EventProcessor eventProcessor);
+}
diff --git a/src/main/java/com/volmit/iris/util/bsf/util/event/EventAdapterImpl.java b/src/main/java/com/volmit/iris/util/bsf/util/event/EventAdapterImpl.java
new file mode 100644
index 000000000..5d2297388
--- /dev/null
+++ b/src/main/java/com/volmit/iris/util/bsf/util/event/EventAdapterImpl.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2004,2004 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.volmit.iris.util.bsf.util.event;
+
+/**
+ * EventAdapterImpl is a default implementation of the EventAdapter
+ * interface that specific event adapters may choose to subclass from
+ * instead of implementing the interface themselves. Saves 5 lines of code
+ * mebbe.
+ *
+ * @author Sanjiva Weerawarana
+ * @author Matthew J. Duftler
+ * @see EventAdapter
+ */
+public class EventAdapterImpl implements EventAdapter {
+ protected EventProcessor eventProcessor;
+
+ public void setEventProcessor (EventProcessor eventProcessor) {
+ this.eventProcessor = eventProcessor;
+ }
+}
diff --git a/src/main/java/com/volmit/iris/util/bsf/util/event/EventAdapterRegistry.java b/src/main/java/com/volmit/iris/util/bsf/util/event/EventAdapterRegistry.java
new file mode 100644
index 000000000..1c9d6a7e9
--- /dev/null
+++ b/src/main/java/com/volmit/iris/util/bsf/util/event/EventAdapterRegistry.java
@@ -0,0 +1,103 @@
+/*
+ * Copyright 2004,2004 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.volmit.iris.util.bsf.util.event;
+
+import java.util.Hashtable;
+
+import com.volmit.iris.util.bsf.util.event.generator.EventAdapterGenerator;
+
+/**
+ * The EventAdapterRegistry is the registry of event adapters.
+ * If a desired adapter is not found, the adapter will be dynamically
+ * generated when lookup is attempted. Set the dynamic
property
+ * to false
to disable this feature.
+ * null
is returned.
+ * true
.
+ * dynamic
property is set to true, and the
+ * ClassLoader
is unable to resolve an adapter, one will be
+ * dynamically generated.
+ *
+ * @param dynamic whether or not to dynamically generate adapters.
+ */
+ public static void setDynamic (boolean dynamic) {
+ EventAdapterRegistry.dynamic = dynamic;
+ }
+}
diff --git a/src/main/java/com/volmit/iris/util/bsf/util/event/EventProcessor.java b/src/main/java/com/volmit/iris/util/bsf/util/event/EventProcessor.java
new file mode 100644
index 000000000..7b5db8ac7
--- /dev/null
+++ b/src/main/java/com/volmit/iris/util/bsf/util/event/EventProcessor.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2004,2004 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.volmit.iris.util.bsf.util.event;
+
+
+/**
+ * EventProcessor is the interface that event adapters use to
+ * delegate events they received to be delivered to the appropriate target.
+ * They can simply deliver the event using processEvent or, if the event
+ * can be excepted to, via processExceptionableEvent (in which case the
+ * adapter is expected to forward on an exception to the source bean).
+ *
+ * @author Sanjiva Weerawarana
+ * @author Matthew J. Duftler
+ * @see EventAdapter
+ */
+public interface EventProcessor {
+ public void processEvent (String filter, Object[] eventInfo);
+ public void processExceptionableEvent (String filter, Object[] eventInfo)
+ throws Exception;
+}
diff --git a/src/main/java/com/volmit/iris/util/bsf/util/event/adapters/java_awt_event_ActionAdapter.java b/src/main/java/com/volmit/iris/util/bsf/util/event/adapters/java_awt_event_ActionAdapter.java
new file mode 100644
index 000000000..2ff05d93e
--- /dev/null
+++ b/src/main/java/com/volmit/iris/util/bsf/util/event/adapters/java_awt_event_ActionAdapter.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2004,2004 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.volmit.iris.util.bsf.util.event.adapters;
+
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+
+import com.volmit.iris.util.bsf.util.event.EventAdapterImpl;
+
+public class java_awt_event_ActionAdapter extends EventAdapterImpl
+ implements ActionListener {
+
+ public void actionPerformed (ActionEvent e) {
+ eventProcessor.processEvent ("actionPerformed", new Object[]{e});
+ }
+}
diff --git a/src/main/java/com/volmit/iris/util/bsf/util/event/adapters/java_awt_event_AdjustmentAdapter.java b/src/main/java/com/volmit/iris/util/bsf/util/event/adapters/java_awt_event_AdjustmentAdapter.java
new file mode 100644
index 000000000..b19e2092e
--- /dev/null
+++ b/src/main/java/com/volmit/iris/util/bsf/util/event/adapters/java_awt_event_AdjustmentAdapter.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2004,2004 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.volmit.iris.util.bsf.util.event.adapters;
+
+import java.awt.event.AdjustmentEvent;
+import java.awt.event.AdjustmentListener;
+
+import com.volmit.iris.util.bsf.util.event.EventAdapterImpl;
+
+public class java_awt_event_AdjustmentAdapter extends EventAdapterImpl
+ implements AdjustmentListener {
+
+ public void adjustmentValueChanged (AdjustmentEvent e) {
+ eventProcessor.processEvent ("adjustmentValueChanged", new Object[]{e});
+ }
+}
diff --git a/src/main/java/com/volmit/iris/util/bsf/util/event/adapters/java_awt_event_ComponentAdapter.java b/src/main/java/com/volmit/iris/util/bsf/util/event/adapters/java_awt_event_ComponentAdapter.java
new file mode 100644
index 000000000..2d5a0add4
--- /dev/null
+++ b/src/main/java/com/volmit/iris/util/bsf/util/event/adapters/java_awt_event_ComponentAdapter.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2004,2004 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.volmit.iris.util.bsf.util.event.adapters;
+
+import java.awt.event.ComponentEvent;
+import java.awt.event.ComponentListener;
+
+import com.volmit.iris.util.bsf.util.event.EventAdapterImpl;
+
+public class java_awt_event_ComponentAdapter extends EventAdapterImpl
+ implements ComponentListener {
+
+ public void componentHidden (ComponentEvent e) {
+ eventProcessor.processEvent ("componentHidden", new Object[]{e});
+ }
+ public void componentMoved (ComponentEvent e) {
+ eventProcessor.processEvent ("componentMoved", new Object[]{e});
+ }
+ public void componentResized (ComponentEvent e) {
+ eventProcessor.processEvent ("componentResized", new Object[]{e});
+ }
+ public void componentShown (ComponentEvent e) {
+ eventProcessor.processEvent ("componentShown", new Object[]{e});
+ }
+}
diff --git a/src/main/java/com/volmit/iris/util/bsf/util/event/adapters/java_awt_event_ContainerAdapter.java b/src/main/java/com/volmit/iris/util/bsf/util/event/adapters/java_awt_event_ContainerAdapter.java
new file mode 100644
index 000000000..74c935d5b
--- /dev/null
+++ b/src/main/java/com/volmit/iris/util/bsf/util/event/adapters/java_awt_event_ContainerAdapter.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2004,2004 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.volmit.iris.util.bsf.util.event.adapters;
+
+import java.awt.event.ContainerEvent;
+import java.awt.event.ContainerListener;
+
+import com.volmit.iris.util.bsf.util.event.EventAdapterImpl;
+
+public class java_awt_event_ContainerAdapter extends EventAdapterImpl
+ implements ContainerListener {
+
+ public void componentAdded (ContainerEvent e) {
+ eventProcessor.processEvent ("componentAdded", new Object[]{e});
+ }
+ public void componentRemoved (ContainerEvent e) {
+ eventProcessor.processEvent ("componentRemoved", new Object[]{e});
+ }
+}
diff --git a/src/main/java/com/volmit/iris/util/bsf/util/event/adapters/java_awt_event_FocusAdapter.java b/src/main/java/com/volmit/iris/util/bsf/util/event/adapters/java_awt_event_FocusAdapter.java
new file mode 100644
index 000000000..a7740188d
--- /dev/null
+++ b/src/main/java/com/volmit/iris/util/bsf/util/event/adapters/java_awt_event_FocusAdapter.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2004,2004 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.volmit.iris.util.bsf.util.event.adapters;
+
+import java.awt.event.FocusEvent;
+import java.awt.event.FocusListener;
+
+import com.volmit.iris.util.bsf.util.event.EventAdapterImpl;
+
+public class java_awt_event_FocusAdapter extends EventAdapterImpl
+ implements FocusListener {
+
+ public void focusGained (FocusEvent e) {
+ eventProcessor.processEvent ("focusGained", new Object[]{e});
+ }
+ public void focusLost (FocusEvent e) {
+ eventProcessor.processEvent ("focusLost", new Object[]{e});
+ }
+}
diff --git a/src/main/java/com/volmit/iris/util/bsf/util/event/adapters/java_awt_event_ItemAdapter.java b/src/main/java/com/volmit/iris/util/bsf/util/event/adapters/java_awt_event_ItemAdapter.java
new file mode 100644
index 000000000..9f7508110
--- /dev/null
+++ b/src/main/java/com/volmit/iris/util/bsf/util/event/adapters/java_awt_event_ItemAdapter.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2004,2004 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.volmit.iris.util.bsf.util.event.adapters;
+
+import java.awt.event.ItemEvent;
+import java.awt.event.ItemListener;
+
+import com.volmit.iris.util.bsf.util.event.EventAdapterImpl;
+
+public class java_awt_event_ItemAdapter extends EventAdapterImpl
+ implements ItemListener {
+
+ public void itemStateChanged (ItemEvent e) {
+ eventProcessor.processEvent ("itemStateChanged", new Object[]{e});
+ }
+}
diff --git a/src/main/java/com/volmit/iris/util/bsf/util/event/adapters/java_awt_event_KeyAdapter.java b/src/main/java/com/volmit/iris/util/bsf/util/event/adapters/java_awt_event_KeyAdapter.java
new file mode 100644
index 000000000..21c3a7e2c
--- /dev/null
+++ b/src/main/java/com/volmit/iris/util/bsf/util/event/adapters/java_awt_event_KeyAdapter.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2004,2004 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.volmit.iris.util.bsf.util.event.adapters;
+
+import java.awt.event.KeyEvent;
+import java.awt.event.KeyListener;
+
+import com.volmit.iris.util.bsf.util.event.EventAdapterImpl;
+
+public class java_awt_event_KeyAdapter extends EventAdapterImpl
+ implements KeyListener {
+
+ public void keyPressed (KeyEvent e) {
+ eventProcessor.processEvent ("keyPressed", new Object[]{e});
+ }
+ public void keyReleased (KeyEvent e) {
+ eventProcessor.processEvent ("keyReleased", new Object[]{e});
+ }
+ public void keyTyped (KeyEvent e) {
+ eventProcessor.processEvent ("keyTyped", new Object[]{e});
+ }
+}
diff --git a/src/main/java/com/volmit/iris/util/bsf/util/event/adapters/java_awt_event_MouseAdapter.java b/src/main/java/com/volmit/iris/util/bsf/util/event/adapters/java_awt_event_MouseAdapter.java
new file mode 100644
index 000000000..a0ec4950f
--- /dev/null
+++ b/src/main/java/com/volmit/iris/util/bsf/util/event/adapters/java_awt_event_MouseAdapter.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2004,2004 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.volmit.iris.util.bsf.util.event.adapters;
+
+import java.awt.event.MouseEvent;
+import java.awt.event.MouseListener;
+
+import com.volmit.iris.util.bsf.util.event.EventAdapterImpl;
+
+public class java_awt_event_MouseAdapter extends EventAdapterImpl
+ implements MouseListener {
+
+ public void mouseClicked (MouseEvent e) {
+ eventProcessor.processEvent ("mouseClicked", new Object[]{e});
+ }
+ public void mouseEntered (MouseEvent e) {
+ eventProcessor.processEvent ("mouseEntered", new Object[]{e});
+ }
+ public void mouseExited (MouseEvent e) {
+ eventProcessor.processEvent ("mouseExited", new Object[]{e});
+ }
+ public void mousePressed (MouseEvent e) {
+ eventProcessor.processEvent ("mousePressed", new Object[]{e});
+ }
+ public void mouseReleased (MouseEvent e) {
+ eventProcessor.processEvent ("mouseReleased", new Object[]{e});
+ }
+}
diff --git a/src/main/java/com/volmit/iris/util/bsf/util/event/adapters/java_awt_event_MouseMotionAdapter.java b/src/main/java/com/volmit/iris/util/bsf/util/event/adapters/java_awt_event_MouseMotionAdapter.java
new file mode 100644
index 000000000..ec80769e3
--- /dev/null
+++ b/src/main/java/com/volmit/iris/util/bsf/util/event/adapters/java_awt_event_MouseMotionAdapter.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2004,2004 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.volmit.iris.util.bsf.util.event.adapters;
+
+import java.awt.event.MouseEvent;
+import java.awt.event.MouseMotionListener;
+
+import com.volmit.iris.util.bsf.util.event.EventAdapterImpl;
+
+public class java_awt_event_MouseMotionAdapter extends EventAdapterImpl
+ implements MouseMotionListener {
+
+ public void mouseDragged(MouseEvent e) {
+ eventProcessor.processEvent ("mouseDragged", new Object[]{e});
+ }
+ public void mouseMoved(MouseEvent e) {
+ eventProcessor.processEvent ("mouseMoved", new Object[]{e});
+ }
+}
diff --git a/src/main/java/com/volmit/iris/util/bsf/util/event/adapters/java_awt_event_TextAdapter.java b/src/main/java/com/volmit/iris/util/bsf/util/event/adapters/java_awt_event_TextAdapter.java
new file mode 100644
index 000000000..f0ab8010a
--- /dev/null
+++ b/src/main/java/com/volmit/iris/util/bsf/util/event/adapters/java_awt_event_TextAdapter.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2004,2004 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.volmit.iris.util.bsf.util.event.adapters;
+
+import java.awt.event.TextEvent;
+import java.awt.event.TextListener;
+
+import com.volmit.iris.util.bsf.util.event.EventAdapterImpl;
+
+public class java_awt_event_TextAdapter extends EventAdapterImpl
+ implements TextListener {
+
+ public void textValueChanged (TextEvent e) {
+ eventProcessor.processEvent ("textValueChanged", new Object[]{e});
+ }
+}
diff --git a/src/main/java/com/volmit/iris/util/bsf/util/event/adapters/java_awt_event_WindowAdapter.java b/src/main/java/com/volmit/iris/util/bsf/util/event/adapters/java_awt_event_WindowAdapter.java
new file mode 100644
index 000000000..866387eb3
--- /dev/null
+++ b/src/main/java/com/volmit/iris/util/bsf/util/event/adapters/java_awt_event_WindowAdapter.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2004,2004 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.volmit.iris.util.bsf.util.event.adapters;
+
+import java.awt.event.WindowEvent;
+import java.awt.event.WindowListener;
+
+import com.volmit.iris.util.bsf.util.event.EventAdapterImpl;
+
+public class java_awt_event_WindowAdapter extends EventAdapterImpl
+ implements WindowListener {
+
+ public void windowActivated (WindowEvent e) {
+ eventProcessor.processEvent ("windowActivated", new Object[]{e});
+ }
+ public void windowClosed (WindowEvent e) {
+ eventProcessor.processEvent ("windowClosed", new Object[]{e});
+ }
+ public void windowClosing (WindowEvent e) {
+ eventProcessor.processEvent ("windowClosing", new Object[]{e});
+ }
+ public void windowDeactivated (WindowEvent e) {
+ eventProcessor.processEvent ("windowDeactivated", new Object[]{e});
+ }
+ public void windowDeiconified (WindowEvent e) {
+ eventProcessor.processEvent ("windowDeiconified", new Object[]{e});
+ }
+ public void windowIconified (WindowEvent e) {
+ eventProcessor.processEvent ("windowIconified", new Object[]{e});
+ }
+ public void windowOpened (WindowEvent e) {
+ eventProcessor.processEvent ("windowOpened", new Object[]{e});
+ }
+}
diff --git a/src/main/java/com/volmit/iris/util/bsf/util/event/adapters/java_beans_PropertyChangeAdapter.java b/src/main/java/com/volmit/iris/util/bsf/util/event/adapters/java_beans_PropertyChangeAdapter.java
new file mode 100644
index 000000000..9adbf4884
--- /dev/null
+++ b/src/main/java/com/volmit/iris/util/bsf/util/event/adapters/java_beans_PropertyChangeAdapter.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2004,2004 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.volmit.iris.util.bsf.util.event.adapters;
+
+import java.beans.PropertyChangeEvent;
+import java.beans.PropertyChangeListener;
+
+import com.volmit.iris.util.bsf.util.event.EventAdapterImpl;
+
+public class java_beans_PropertyChangeAdapter extends EventAdapterImpl
+ implements PropertyChangeListener {
+
+ public void propertyChange(PropertyChangeEvent e) {
+ eventProcessor.processEvent (e.getPropertyName(), new Object[]{e});
+ }
+}
diff --git a/src/main/java/com/volmit/iris/util/bsf/util/event/adapters/java_beans_VetoableChangeAdapter.java b/src/main/java/com/volmit/iris/util/bsf/util/event/adapters/java_beans_VetoableChangeAdapter.java
new file mode 100644
index 000000000..aafa64a98
--- /dev/null
+++ b/src/main/java/com/volmit/iris/util/bsf/util/event/adapters/java_beans_VetoableChangeAdapter.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2004,2004 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.volmit.iris.util.bsf.util.event.adapters;
+
+import java.beans.PropertyChangeEvent;
+import java.beans.PropertyVetoException;
+import java.beans.VetoableChangeListener;
+
+import com.volmit.iris.util.bsf.util.event.EventAdapterImpl;
+
+public class java_beans_VetoableChangeAdapter extends EventAdapterImpl
+ implements VetoableChangeListener {
+
+ public void vetoableChange (PropertyChangeEvent e) throws PropertyVetoException {
+ try
+ {
+ eventProcessor.processExceptionableEvent (e.getPropertyName(), new Object[]{e});
+ }
+ catch (PropertyVetoException ex)
+ {
+ throw ex;
+ }
+ catch (Exception ex)
+ {
+ }
+ }
+}
diff --git a/src/main/java/com/volmit/iris/util/bsf/util/event/generator/AdapterClassLoader.java b/src/main/java/com/volmit/iris/util/bsf/util/event/generator/AdapterClassLoader.java
new file mode 100644
index 000000000..59dec6c66
--- /dev/null
+++ b/src/main/java/com/volmit/iris/util/bsf/util/event/generator/AdapterClassLoader.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright 2004,2004 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.volmit.iris.util.bsf.util.event.generator;
+
+import java.util.Hashtable;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+public class AdapterClassLoader extends ClassLoader
+{
+ private static Hashtable classCache = new Hashtable();
+ private Class c;
+
+ private Log logger = LogFactory.getLog(this.getClass().getName());
+
+ public AdapterClassLoader()
+ {
+ super();
+ }
+ public synchronized Class defineClass(String name, byte[] b)
+ {
+ if ((c = getLoadedClass(name)) == null)
+ {
+ c = defineClass(name.replace('/','.'), b, 0, b.length); // rgf, 2006-02-03
+ put(name, c);
+ }
+ else
+ {
+ logger.error("AdapterClassLoader: " + c +
+ " previously loaded. Can not redefine class.");
+ }
+
+ return c;
+ }
+ final protected Class findClass(String name)
+ {
+ return get(name);
+ }
+ final protected Class get(String name)
+ {
+ return (Class)classCache.get(name);
+ }
+ public synchronized Class getLoadedClass(String name)
+ {
+ Class c = findLoadedClass(name);
+
+ if (c == null)
+ {
+ try
+ {
+ c = findSystemClass(name);
+ }
+ catch (ClassNotFoundException e)
+ {
+ }
+ }
+
+ if (c == null)
+ {
+ c = findClass(name);
+ }
+
+ return c;
+ }
+ protected synchronized Class loadClass(String name, boolean resolve)
+ throws ClassNotFoundException
+ {
+ Class c = getLoadedClass(name);
+
+ if (c != null && resolve)
+ {
+ resolveClass(c);
+ }
+
+ return c;
+ }
+ // Not in JDK 1.1, only in JDK 1.2.
+// public AdapterClassLoader(ClassLoader loader)
+// {
+// super(loader);
+// }
+
+ final protected void put(String name, Class c)
+ {
+ classCache.put(name, c);
+ }
+}
diff --git a/src/main/java/com/volmit/iris/util/bsf/util/event/generator/ByteUtility.java b/src/main/java/com/volmit/iris/util/bsf/util/event/generator/ByteUtility.java
new file mode 100644
index 000000000..1412696cf
--- /dev/null
+++ b/src/main/java/com/volmit/iris/util/bsf/util/event/generator/ByteUtility.java
@@ -0,0 +1,331 @@
+/*
+ * Copyright 2004,2004 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.volmit.iris.util.bsf.util.event.generator;
+
+/**
+ * Byte handling utilities
+ *
+ * 5 April 1999 - functions to append standard types to byte arrays
+ * functions to produce standard types from byte arrays
+ *
+ * @author Richard F. Boehme
+ *
+ */
+public class ByteUtility
+{
+ public static byte[] addBytes(byte[] array,byte[] value)
+ {
+ if( null != array )
+ {
+ byte newarray[] = new byte[array.length + value.length];
+ System.arraycopy(array,0,newarray,0,array.length);
+ System.arraycopy(value,0,newarray,array.length,value.length);
+ array = newarray;
+ }
+ else
+ {
+ array = value;
+ }
+ return array;
+ }
+ public static byte[] addBytes(byte[] array, byte value)
+ {
+ if( null != array )
+ {
+ byte newarray[] = new byte[array.length + 1];
+ System.arraycopy(array,0,newarray,0,array.length);
+ newarray[newarray.length-1] = value;
+ array = newarray;
+ }
+ else
+ {
+ array = new byte[1];
+ array[0] = value;
+ }
+ return array;
+ }
+ public static byte[] addBytes(byte[] array, int value)
+ {
+ if( null != array )
+ {
+ byte newarray[] = new byte[array.length + 3];
+ System.arraycopy(array,0,newarray,0,array.length);
+ newarray[newarray.length-3] = (byte) (( value >> 16 ) & 0xFF);
+ newarray[newarray.length-2] = (byte) (( value >> 8 ) & 0xFF);
+ newarray[newarray.length-1] = (byte) ( value & 0xFF);
+ array = newarray;
+ }
+ else
+ {
+ array = new byte[3];
+ array[0] = (byte) (( value >> 16 ) & 0xFF);
+ array[1] = (byte) (( value >> 8 ) & 0xFF);
+ array[2] = (byte) ( value & 0xFF);
+ }
+ return array;
+ }
+ public static byte[] addBytes(byte[] array, long value)
+ {
+ if( null != array )
+ {
+ byte newarray[] = new byte[array.length + 4];
+ System.arraycopy(array,0,newarray,0,array.length);
+ newarray[newarray.length-4] = (byte) (( value >> 24 ) & 0xFF);
+ newarray[newarray.length-3] = (byte) (( value >> 16 ) & 0xFF);
+ newarray[newarray.length-2] = (byte) (( value >> 8 ) & 0xFF);
+ newarray[newarray.length-1] = (byte) ( value & 0xFF);
+ array = newarray;
+ }
+ else
+ {
+ array = new byte[4];
+ array[0] = (byte) (( value >> 24 ) & 0xFF);
+ array[1] = (byte) (( value >> 16 ) & 0xFF);
+ array[2] = (byte) (( value >> 8 ) & 0xFF);
+ array[3] = (byte) (value & 0xFF);
+ }
+ return array;
+ }
+ public static byte[] addBytes(byte[] array,String value)
+ {
+ if( null != value )
+ {
+ if( null != array)
+ {
+ byte newarray[] = new byte[array.length + value.length()];
+ System.arraycopy(array,0,newarray,0,array.length);
+ System.arraycopy(value.getBytes(),0,newarray,array.length,value.length());
+ array = newarray;
+ }
+ else
+ {
+ array = value.getBytes();
+ }
+ }
+ return array;
+ }
+ public static byte[] addBytes(byte[] array, short value)
+ {
+ if( null != array)
+ {
+ byte newarray[] = new byte[array.length + 2];
+ System.arraycopy(array,0,newarray,0,array.length);
+ newarray[newarray.length-2] = (byte) (( value >> 8 ) & 0xFF);
+ newarray[newarray.length-1] = (byte) ( value & 0xFF);
+ array = newarray;
+ }
+ else
+ {
+ array = new byte[2];
+ array[0] = (byte) (( value >> 8 ) & 0xFF);
+ array[1] = (byte) ( value & 0xFF);
+ }
+ return array;
+ }
+ public static double byteArrayToDouble(byte high[], byte low[])
+ {
+ double temp = 0;
+ // high bytes
+ temp += (((long)high[0]) & 0xFF) << 56;
+ temp += (((long)high[1]) & 0xFF) << 48;
+ temp += (((long)high[2]) & 0xFF) << 40;
+ temp += (((long)high[3]) & 0xFF) << 32;
+ // low bytes
+ temp += (((long)low[0]) & 0xFF) << 24;
+ temp += (((long)low[1]) & 0xFF) << 16;
+ temp += (((long)low[2]) & 0xFF) << 8;
+ temp += (((long)low[3]) & 0xFF);
+ return temp;
+ }
+ public static double byteArrayToDouble(byte value[])
+ {
+ byte high[] = new byte[4];
+ byte low[] = new byte[4];
+ high[0] = value[0];
+ high[1] = value[1];
+ high[2] = value[2];
+ high[3] = value[3];
+ low[0] = value[4];
+ low[1] = value[5];
+ low[2] = value[6];
+ low[3] = value[7];
+ return byteArrayToDouble(high,low);
+ }
+ public static float byteArrayToFloat(byte value[])
+ {
+ float temp = 0;
+ temp += (((int)value[0]) & 0xFF) << 24;
+ temp += (((int)value[1]) & 0xFF) << 16;
+ temp += (((int)value[2]) & 0xFF) << 8;
+ temp += (((int)value[3]) & 0xFF);
+ return temp;
+ }
+ public static int byteArrayToInt(byte value[])
+ {
+ int temp = 0;
+ temp += (((int)value[0]) & 0xFF) << 24;
+ temp += (((int)value[1]) & 0xFF) << 16;
+ temp += (((int)value[2]) & 0xFF) << 8;
+ temp += (((int)value[3]) & 0xFF);
+ return temp;
+ }
+ public static long byteArrayToLong(byte value[])
+ {
+ byte high[] = new byte[4];
+ byte low[] = new byte[4];
+ high[0] = value[0];
+ high[1] = value[1];
+ high[2] = value[2];
+ high[3] = value[3];
+ low[0] = value[4];
+ low[1] = value[5];
+ low[2] = value[6];
+ low[3] = value[7];
+ return byteArrayToLong(high,low);
+ }
+ public static long byteArrayToLong(byte high[], byte low[])
+ {
+ long temp = 0;
+ // high bytes
+ temp += (((long)high[0]) & 0xFF) << 56;
+ temp += (((long)high[1]) & 0xFF) << 48;
+ temp += (((long)high[2]) & 0xFF) << 40;
+ temp += (((long)high[3]) & 0xFF) << 32;
+ // low bytes
+ temp += (((long)low[0]) & 0xFF) << 24;
+ temp += (((long)low[1]) & 0xFF) << 16;
+ temp += (((long)low[2]) & 0xFF) << 8;
+ temp += (((long)low[3]) & 0xFF);
+ return temp;
+ }
+ // make the following loops with check on array length *****************
+ public static short byteArrayToShort(byte value[])
+ {
+ short temp = 0;
+ temp += (((int)value[0]) & 0xFF) << 8;
+ temp += (((int)value[1]) & 0xFF);
+ return temp;
+ }
+ public static String byteToHexString(byte value)
+ {
+ String temp = null;
+
+ switch( (value & 0xF0) >> 4 )
+ {
+ case 0:
+ temp = "0";
+ break;
+ case 1:
+ temp = "1";
+ break;
+ case 2:
+ temp = "2";
+ break;
+ case 3:
+ temp = "3";
+ break;
+ case 4:
+ temp = "4";
+ break;
+ case 5:
+ temp = "5";
+ break;
+ case 6:
+ temp = "6";
+ break;
+ case 7:
+ temp = "7";
+ break;
+ case 8:
+ temp = "8";
+ break;
+ case 9:
+ temp = "9";
+ break;
+ case 10:
+ temp = "A";
+ break;
+ case 11:
+ temp = "B";
+ break;
+ case 12:
+ temp = "C";
+ break;
+ case 13:
+ temp = "D";
+ break;
+ case 14:
+ temp = "E";
+ break;
+ case 15:
+ temp = "F";
+ break;
+ }
+ switch( (value & 0x0F) )
+ {
+ case 0:
+ temp += "0";
+ break;
+ case 1:
+ temp += "1";
+ break;
+ case 2:
+ temp += "2";
+ break;
+ case 3:
+ temp += "3";
+ break;
+ case 4:
+ temp += "4";
+ break;
+ case 5:
+ temp += "5";
+ break;
+ case 6:
+ temp += "6";
+ break;
+ case 7:
+ temp += "7";
+ break;
+ case 8:
+ temp += "8";
+ break;
+ case 9:
+ temp += "9";
+ break;
+ case 10:
+ temp += "A";
+ break;
+ case 11:
+ temp += "B";
+ break;
+ case 12:
+ temp += "C";
+ break;
+ case 13:
+ temp += "D";
+ break;
+ case 14:
+ temp += "E";
+ break;
+ case 15:
+ temp += "F";
+ break;
+ }
+ return temp;
+ }
+}
diff --git a/src/main/java/com/volmit/iris/util/bsf/util/event/generator/Bytecode.java b/src/main/java/com/volmit/iris/util/bsf/util/event/generator/Bytecode.java
new file mode 100644
index 000000000..f89846113
--- /dev/null
+++ b/src/main/java/com/volmit/iris/util/bsf/util/event/generator/Bytecode.java
@@ -0,0 +1,105 @@
+/*
+ * Copyright 2004,2004 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.volmit.iris.util.bsf.util.event.generator;
+
+/**
+ * Bytecode handling utilities
+ *
+ * Handle standard byte arrays as defined in Java VM and Class File
+ *
+ * 5 April 1999 - functions to append Class File byte subarrays
+ * into a Class File byte array
+ *
+ * @author Richard F. Boehme
+ *
+ */
+public class Bytecode
+{
+ // Constant Pool Item Codes
+ public static final byte C_Utf8 = 0x01; // 1
+ public static final byte C_Integer = 0x03; // 3
+ public static final byte C_Float = 0x04; // 4
+ public static final byte C_Long = 0x05; // 5
+ public static final byte C_Double = 0x06; // 6
+ public static final byte C_Class = 0x07; // 7
+ public static final byte C_String = 0x08; // 8
+ public static final byte C_FieldRef = 0x09; // 9
+ public static final byte C_MethodRef = 0x0A; // 10
+ public static final byte C_InterfaceMethodRef = 0x0B; // 11
+ public static final byte C_NameAndType = 0x0C; // 12
+
+//public static byte[] addDouble(byte[] array,double value)
+//{
+// array = ByteUtility.addBytes(array,C_Double);
+// array = ByteUtility.addBytes(array,value);
+// return array;
+//}
+
+ public static byte[] addClass(byte[] array,short value)
+ { return addRef(C_Class,array,value); }
+ public static byte[] addFieldRef(byte[] array,short value1,short value2)
+ { return addRef(C_FieldRef,array,value1,value2); }
+ public static byte[] addInteger(byte[] array,int value)
+ {
+ array = ByteUtility.addBytes(array,C_Integer);
+ array = ByteUtility.addBytes(array,value);
+ return array;
+ }
+ public static byte[] addInterfaceMethodRef(byte[] array,short value1,short value2)
+ { return addRef(C_InterfaceMethodRef,array,value1,value2); }
+//public static byte[] addFloat(byte[] array,float value)
+//{
+// array = ByteUtility.addBytes(array,C_Float);
+// array = ByteUtility.addBytes(array,value);
+// return array;
+//}
+
+ public static byte[] addLong(byte[] array,long value)
+ {
+ array = ByteUtility.addBytes(array,C_Long);
+ array = ByteUtility.addBytes(array,value);
+ return array;
+ }
+ public static byte[] addMethodRef(byte[] array,short value1,short value2)
+ { return addRef(C_MethodRef,array,value1,value2); }
+ public static byte[] addNameAndType(byte[] array,short value1,short value2)
+ { return addRef(C_NameAndType,array,value1,value2); }
+ public static byte[] addRef(byte refType,byte[] array,short value)
+ {
+ array = ByteUtility.addBytes(array,refType);
+ array = ByteUtility.addBytes(array,value);
+ return array;
+ }
+ // Generic Bytecode Methods
+ public static byte[] addRef(byte refType,byte[] array,short value1,short value2)
+ {
+ array = ByteUtility.addBytes(array,refType);
+ array = ByteUtility.addBytes(array,value1);
+ array = ByteUtility.addBytes(array,value2);
+ return array;
+ }
+ public static byte[] addString(byte[] array,short value)
+ { return addRef(C_String,array,value); }
+ // Constant Pool Item Methods
+ public static byte[] addUtf8(byte[] array,String value)
+ {
+ array = ByteUtility.addBytes(array,C_Utf8);
+ array = ByteUtility.addBytes(array,(short)value.length());
+ array = ByteUtility.addBytes(array,value);
+ return array;
+ }
+}
diff --git a/src/main/java/com/volmit/iris/util/bsf/util/event/generator/EventAdapterGenerator.java b/src/main/java/com/volmit/iris/util/bsf/util/event/generator/EventAdapterGenerator.java
new file mode 100644
index 000000000..c38dcbe74
--- /dev/null
+++ b/src/main/java/com/volmit/iris/util/bsf/util/event/generator/EventAdapterGenerator.java
@@ -0,0 +1,568 @@
+/*
+ * Copyright 2004,2004 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.volmit.iris.util.bsf.util.event.generator;
+
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/** EventAdapterGenerator
+ *
+ * Generate an "Event Adapter" dynamically during program execution
+ *
+ **/
+public class EventAdapterGenerator
+{
+ public static AdapterClassLoader ldr = new AdapterClassLoader();
+ static Class EVENTLISTENER = null;
+ static String CLASSPACKAGE = "org/apache/bsf/util/event/adapters/";
+ static String WRITEDIRECTORY = null;
+
+ // starting 8 bytes of all Java Class files
+ static byte CLASSHEADER[];
+ // constant pool items found in all event adapters
+ static short BASECPCOUNT; // number of cp items + 1 ( cp item # 0 reserved for JVM )
+ static byte BASECP[]; //
+ // some bytes in the middle of the class file (see below)
+ static byte FIXEDCLASSBYTES[];
+ // the initialization method, noargs constructor
+ static byte INITMETHOD[];
+
+ private static Log logger;
+
+ /* The static initializer */
+ static
+ {
+ logger = LogFactory.getLog(
+ (com.volmit.iris.util.bsf.util.event.generator.EventAdapterGenerator.class).getName());
+
+ String USERCLASSPACKAGE = System.getProperty("DynamicEventClassPackage",
+ "");
+
+ if (!USERCLASSPACKAGE.equals(""))
+ {
+ CLASSPACKAGE = USERCLASSPACKAGE;
+ }
+
+ if(CLASSPACKAGE.length() > 0 )
+ {
+ CLASSPACKAGE = CLASSPACKAGE.replace('\\','/');
+ if(!CLASSPACKAGE.endsWith("/"))
+ { CLASSPACKAGE = CLASSPACKAGE+"/"; }
+ }
+ WRITEDIRECTORY = System.getProperty("DynamicEventClassWriteDirectory",CLASSPACKAGE);
+ if(WRITEDIRECTORY.length() > 0 )
+ {
+ WRITEDIRECTORY = WRITEDIRECTORY.replace('\\','/');
+ if(!WRITEDIRECTORY.endsWith("/"))
+ { WRITEDIRECTORY = WRITEDIRECTORY+"/"; }
+ }
+ try
+ // { EVENTLISTENER = Class.forName("java.util.EventListener"); }
+ { EVENTLISTENER = Thread.currentThread().getContextClassLoader().loadClass ("java.util.EventListener"); } // rgf, 2006-01-05
+ catch(ClassNotFoundException ex)
+ {
+ System.err.println(ex.getMessage());
+ ex.printStackTrace();
+ }
+
+
+ // start of the Java Class File
+ CLASSHEADER = ByteUtility.addBytes(CLASSHEADER,(byte)0xCA); // magic
+ CLASSHEADER = ByteUtility.addBytes(CLASSHEADER,(byte)0xFE); // magic
+ CLASSHEADER = ByteUtility.addBytes(CLASSHEADER,(byte)0xBA); // magic
+ CLASSHEADER = ByteUtility.addBytes(CLASSHEADER,(byte)0xBE); // magic
+ CLASSHEADER = ByteUtility.addBytes(CLASSHEADER,(short)3); // minor version
+ CLASSHEADER = ByteUtility.addBytes(CLASSHEADER,(short)45); // major version
+
+ // Start the constant pool for base items in all event adapter classes
+ BASECPCOUNT = 17; // number of cp items + 1 ( cp item # 0 reserved for JVM )
+
+ // cp item 01
+ BASECP = Bytecode.addUtf8(BASECP,"()V");
+
+ // cp item 02
+ BASECP = Bytecode.addUtf8(BASECP,"