Hi,
Another one:
- change style to Java style (braces, spacing general layout)
- remove extra lines
For this one the code makes use of a tempdir specified as "." - wouldn't
it make sense to use java.io.tmpdir? If the generated files were
created in a subdirectory of the real tmpdir, then it would be possible
to simply rmdir after instead of using the much more complicated Filter
code.
Kev
Index: .
===================================================================
--- . (revision 438751)
+++ . (working copy)
@@ -81,291 +81,272 @@
* <p>
* @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.
- * <p>
- * 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).
- * <p>
- * Nobody knows whether javac is threadsafe.
- * I'm going to serialize access to protect it.
- * <p>
- * 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(org.apache.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,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<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=internal_call(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[] minor_classfiles=
- 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<minor_classfiles.length;++i)
- {
- file=new File(minor_classfiles[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 internal_call (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<args.length;++i)
- argtypes[i]=args[i].getClass();
-
- Method m=MethodUtils.getMethod(javaclass,method,argtypes);
- retval=m.invoke(null,args);
- }
- }
- catch(Exception e)
- {
- throw new BSFException (BSFException.REASON_IO_ERROR, e.getMessage ());
- }
- return retval;
- }
- private GeneratedFile openUniqueFile(String directory,String prefix,String suffix)
- {
- File file=null;
- FileOutputStream fos=null;
- int max=1000; // Don't try forever
- GeneratedFile gf=null;
- int i;
- String className = null;
- for(i=max,++uniqueFileOffset;
- fos==null && i>0;
- --i,++uniqueFileOffset)
- {
- // Probably a timing hazard here... ***************
- try
- {
- className = prefix+uniqueFileOffset;
- file=new File(directory+File.separatorChar+className+suffix);
- if(file!=null && !file.exists())
- fos=new FileOutputStream(file);
- }
- catch(Exception e)
- {
- // File could not be opened for write, or Security Exception
- // was thrown. If someone else created the file before we could
- // open it, that's probably a threading conflict and we don't
- // bother reporting it.
- if(!file.exists())
- {
- logger.error("openUniqueFile: unexpected ", e);
- }
- }
- }
- if(fos==null)
- logger.error("openUniqueFile: Failed "+max+"attempts.");
- else
- gf=new GeneratedFile(file,fos,className);
- return gf;
- }
+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.
+ * <p>
+ * 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).
+ * <p>
+ * Nobody knows whether javac is threadsafe.
+ * I'm going to serialize access to protect it.
+ * <p>
+ * 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(org.apache.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<args.length; ++i) {
+ argtypes[i]=args[i].getClass();
+ }
+ Method m = MethodUtils.getMethod(javaclass, method, argtypes);
+ retval = m.invoke(null, args);
+ }
+ }
+ catch(Exception e) {
+ throw new BSFException (BSFException.REASON_IO_ERROR, e.getMessage ());
+ }
+ return retval;
+ }
+
+ private GeneratedFile openUniqueFile(String directory,String prefix,String suffix) {
+ File file = null;
+ FileOutputStream fos = null;
+ int max = 1000; // Don't try forever
+ GeneratedFile gf = null;
+ int i;
+ String className = null;
+ for(i=max,++uniqueFileOffset; fos==null && i>0;--i,++uniqueFileOffset) {
+ // Probably a timing hazard here... ***************
+ try {
+ className = prefix+uniqueFileOffset;
+ file = new File(directory+File.separatorChar+className+suffix);
+ if(file != null && !file.exists()) {
+ fos = new FileOutputStream(file);
+ }
+ }
+ catch(Exception e) {
+ // File could not be opened for write, or Security Exception
+ // was thrown. If someone else created the file before we could
+ // open it, that's probably a threading conflict and we don't
+ // bother reporting it.
+ if(!file.exists()) {
+ logger.error("openUniqueFile: unexpected ", e);
+ }
+ }
+ }
+ if(fos==null) {
+ logger.error("openUniqueFile: Failed "+max+"attempts.");
+ } else {
+ gf = new GeneratedFile(file,fos,className);
+ }
+ return gf;
+ }
}
---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]