-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 Applied.
Thanks, Sanka Kev Jackson wrote: > 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] - -- Sanka Samaranayake WSO2 Inc. T:+94-77-3506382 F:+94-11-2424304 http://sankas.blogspot.com/ http://www.wso2.net/ -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.2.1 (GNU/Linux) iD8DBQFE+dRq/Hd0ETKdgNIRAmjMAJ4kVRwsfhC64A4SiXo41uxoU5h7qQCfb3oB +bnId39GGWmi/PkuW2lkgOY= =6Ehm -----END PGP SIGNATURE----- --------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]