/** * A command is a scripted method or compiled command class implementing a specified method * signature. Commands are loaded from the classpath and may be imported using the * importCommands() method. * * <p>This method searches the imported commands packages for a script or command object * corresponding to the name of the method. If it is a script the script is sourced into this * namespace and the BshMethod for the requested signature is returned. If it is a compiled class * the class is returned. (Compiled command classes implement static invoke() methods). * * <p>The imported packages are searched in reverse order, so that later imports take priority. * Currently only the first object (script or class) with the appropriate name is checked. If * another, overloaded form, is located in another package it will not currently be found. This * could be fixed. * * <p> * * @return a BshMethod, Class, or null if no such command is found. * @param name is the name of the desired command method * @param argTypes is the signature of the desired command method. * @throws UtilEvalError if loadScriptedCommand throws UtilEvalError i.e. on errors loading a * script that was found */ public Object getCommand(String name, Class[] argTypes, Interpreter interpreter) throws UtilEvalError { if (Interpreter.DEBUG) Interpreter.debug("getCommand: " + name); BshClassManager bcm = interpreter.getClassManager(); if (importedCommands != null) { // loop backwards for precedence for (int i = importedCommands.size() - 1; i >= 0; i--) { String path = importedCommands.get(i); String scriptPath; if (path.equals("/")) scriptPath = path + name + ".bsh"; else scriptPath = path + "/" + name + ".bsh"; Interpreter.debug("searching for script: " + scriptPath); InputStream in = bcm.getResourceAsStream(scriptPath); if (in != null) return loadScriptedCommand(in, name, argTypes, scriptPath, interpreter); // Chop leading "/" and change "/" to "." String className; if (path.equals("/")) className = name; else className = path.substring(1).replace('/', '.') + "." + name; Interpreter.debug("searching for class: " + className); Class clas = bcm.classForName(className); if (clas != null) return clas; } } if (parent != null) return parent.getCommand(name, argTypes, interpreter); else return null; }
public BshClassManager getClassManager() { if (classManager != null) return classManager; if (parent != null && parent != JAVACODE) return parent.getClassManager(); System.out.println("experiment: creating class manager"); classManager = BshClassManager.createClassManager(null /*interp*/); // Interpreter.debug("No class manager namespace:" +this); return classManager; }
/** Used for serialization */ public void prune() { // Cut off from parent, we must have our own class manager. // Can't do this in the run() command (needs to resolve stuff) // Should we do it by default when we create a namespace will no // parent of class manager? if (this.classManager == null) // XXX if we keep the createClassManager in getClassManager then we can axe // this? setClassManager(BshClassManager.createClassManager(null /*interp*/)); setParent(null); }
public NameSpace(NameSpace parent, BshClassManager classManager, String name) { // We might want to do this here rather than explicitly in Interpreter // for global (see also prune()) // if ( classManager == null && (parent == null ) ) // create our own class manager? setName(name); setParent(parent); setClassManager(classManager); // Register for notification of classloader change if (classManager != null) classManager.addListener(this); }
/** * Parse the BSHBlock for for the class definition and generate the class using ClassGenerator. */ public static Class generateClassImpl( String name, Modifiers modifiers, Class[] interfaces, Class superClass, BSHBlock block, boolean isInterface, CallStack callstack, Interpreter interpreter) throws EvalError { // Scripting classes currently requires accessibility // This can be eliminated with a bit more work. try { Capabilities.setAccessibility(true); } catch (Capabilities.Unavailable e) { throw new EvalError( "Defining classes currently requires reflective Accessibility.", block, callstack); } NameSpace enclosingNameSpace = callstack.top(); String packageName = enclosingNameSpace.getPackage(); String className = enclosingNameSpace.isClass ? (enclosingNameSpace.getName() + "$" + name) : name; String fqClassName = packageName == null ? className : packageName + "." + className; BshClassManager bcm = interpreter.getClassManager(); // Race condition here... bcm.definingClass(fqClassName); // Create the class static namespace NameSpace classStaticNameSpace = new NameSpace(enclosingNameSpace, className); classStaticNameSpace.isClass = true; callstack.push(classStaticNameSpace); // Evaluate any inner class class definitions in the block // effectively recursively call this method for contained classes first block.evalBlock(callstack, interpreter, true /*override*/, ClassNodeFilter.CLASSCLASSES); // Generate the type for our class Variable[] variables = getDeclaredVariables(block, callstack, interpreter, packageName); DelayedEvalBshMethod[] methods = getDeclaredMethods(block, callstack, interpreter, packageName); ClassGeneratorUtil classGenerator = new ClassGeneratorUtil( modifiers, className, packageName, superClass, interfaces, variables, methods, classStaticNameSpace, isInterface); byte[] code = classGenerator.generateClass(); // if debug, write out the class file to debugClasses directory if (DEBUG_DIR != null) try { FileOutputStream out = new FileOutputStream(DEBUG_DIR + '/' + className + ".class"); out.write(code); out.close(); } catch (IOException e) { throw new IllegalStateException( "cannot create file " + DEBUG_DIR + '/' + className + ".class", e); } // Define the new class in the classloader Class genClass = bcm.defineClass(fqClassName, code); // import the unq name into parent enclosingNameSpace.importClass(fqClassName.replace('$', '.')); try { classStaticNameSpace.setLocalVariable( ClassGeneratorUtil.BSHINIT, block, false /*strictJava*/); } catch (UtilEvalError e) { throw new InterpreterError("unable to init static: " + e); } // Give the static space its class static import // important to do this after all classes are defined classStaticNameSpace.setClassStatic(genClass); // evaluate the static portion of the block in the static space block.evalBlock(callstack, interpreter, true /*override*/, ClassNodeFilter.CLASSSTATIC); callstack.pop(); if (!genClass.isInterface()) { // Set the static bsh This callback String bshStaticFieldName = ClassGeneratorUtil.BSHSTATIC + className; try { LHS lhs = Reflect.getLHSStaticField(genClass, bshStaticFieldName); lhs.assign(classStaticNameSpace.getThis(interpreter), false /*strict*/); } catch (Exception e) { throw new InterpreterError("Error in class gen setup: " + e); } } bcm.doneDefiningClass(fqClassName); return genClass; }
/** * Try to make the name into an imported class. This method takes into account only imports (class * or package) found directly in this NameSpace (no parent chain). */ private Class getImportedClassImpl(String name) throws UtilEvalError { // Try explicitly imported class, e.g. import foo.Bar; String fullname = null; if (importedClasses != null) fullname = importedClasses.get(name); // not sure if we should really recurse here for explicitly imported // class in parent... if (fullname != null) { /* Found the full name in imported classes. */ // Try to make the full imported name Class clas = classForName(fullname); // Handle imported inner class case if (clas == null) { // Imported full name wasn't found as an absolute class // If it is compound, try to resolve to an inner class. // (maybe this should happen in the BshClassManager?) if (Name.isCompound(fullname)) try { clas = getNameResolver(fullname).toClass(); } catch (ClassNotFoundException e) { /* not a class */ } else if (Interpreter.DEBUG) Interpreter.debug("imported unpackaged name not found:" + fullname); // If found cache the full name in the BshClassManager if (clas != null) { // (should we cache info in not a class case too?) getClassManager().cacheClassInfo(fullname, clas); return clas; } } else return clas; // It was explicitly imported, but we don't know what it is. // should we throw an error here?? return null; } /* Try imported packages, e.g. "import foo.bar.*;" in reverse order of import... (give later imports precedence...) */ if (importedPackages != null) for (int i = importedPackages.size() - 1; i >= 0; i--) { String s = importedPackages.get(i) + "." + name; Class c = classForName(s); if (c != null) return c; } BshClassManager bcm = getClassManager(); /* Try super import if available Note: we do this last to allow explicitly imported classes and packages to take priority. This method will also throw an error indicating ambiguity if it exists... */ if (bcm.hasSuperImport()) { String s = bcm.getClassNameByUnqName(name); if (s != null) return classForName(s); } return null; }