예제 #1
0
  /**
   * 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;
  }
예제 #2
0
  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;
  }
예제 #3
0
  /** 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);
  }
예제 #4
0
  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);
  }
예제 #5
0
  /**
   * 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;
  }
예제 #6
0
  /**
   * 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;
  }