alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

What this is

This file is included in the DevDaily.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Other links

The source code

/*****************************************************************************
 *                                                                           *
 *  This file is part of the BeanShell Java Scripting distribution.          *
 *  Documentation and updates may be found at http://www.beanshell.org/      *
 *                                                                           *
 *  Sun Public License Notice:                                               *
 *                                                                           *
 *  The contents of this file are subject to the Sun Public License Version  *
 *  1.0 (the "License"); you may not use this file except in compliance with *
 *  the License. A copy of the License is available at http://www.sun.com    * 
 *                                                                           *
 *  The Original Code is BeanShell. The Initial Developer of the Original    *
 *  Code is Pat Niemeyer. Portions created by Pat Niemeyer are Copyright     *
 *  (C) 2000.  All Rights Reserved.                                          *
 *                                                                           *
 *  GNU Public License Notice:                                               *
 *                                                                           *
 *  Alternatively, the contents of this file may be used under the terms of  *
 *  the GNU Lesser General Public License (the "LGPL"), in which case the    *
 *  provisions of LGPL are applicable instead of those above. If you wish to *
 *  allow use of your version of this file only under the  terms of the LGPL *
 *  and not to allow others to use your version of this file under the SPL,  *
 *  indicate your decision by deleting the provisions above and replace      *
 *  them with the notice and other provisions required by the LGPL.  If you  *
 *  do not delete the provisions above, a recipient may use your version of  *
 *  this file under either the SPL or the LGPL.                              *
 *                                                                           *
 *  Patrick Niemeyer (pat@pat.net)                                           *
 *  Author of Learning Java, O'Reilly & Associates                           *
 *  http://www.pat.net/~pat/                                                 *
 *                                                                           *
 *****************************************************************************/


package	bsh;

import java.util.*;

import java.io.InputStream;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.IOException;

import java.lang.reflect.Method;
import java.lang.reflect.Field;

/**
    A namespace	in which methods, variables, and imports (class names) live.  
	This is package public because it is used in the implementation of some 
	bsh commands.  However for normal use you should be using methods on 
	bsh.Interpreter to interact with your scripts.
	

A bsh.This object is a thin layer over a NameSpace that associates it with an Interpreter instance. Together they comprise a Bsh scripted object context.

Note: I'd really like to use collections here, but we have to keep this compatible with JDK1.1 */ /* Thanks to Slava Pestov (of jEdit fame) for import caching enhancements. Note: This class has gotten too big. It should be broken down a bit. */ public class NameSpace implements java.io.Serializable, BshClassManager.Listener, NameSource { public static final NameSpace JAVACODE = new NameSpace((BshClassManager)null, "Called from compiled Java code."); static { JAVACODE.isMethod = true; } // Begin instance data // Note: if we add something here we should reset it in the clear() method. /** The name of this namespace. If the namespace is a method body namespace then this is the name of the method. If it's a class or class instance then it's the name of the class. */ private String nsName; private NameSpace parent; private Hashtable variables; private Hashtable methods; protected Hashtable importedClasses; private Vector importedPackages; private Vector importedObjects; private Vector importedStatic; private Vector importedCommands; private String packageName; transient private BshClassManager classManager; // See notes in getThis() private This thisReference; /** Name resolver objects */ private Hashtable names; /** The node associated with the creation of this namespace. This is used support getInvocationLine() and getInvocationText(). */ SimpleNode callerInfoNode; /** Note that the namespace is a method body namespace. This is used for printing stack traces in exceptions. */ boolean isMethod; /** Note that the namespace is a class body or class instance namespace. This is used for controlling static/object import precedence, etc. */ /* Note: We will ll move this behavior out to a subclass of NameSpace, but we'll start here. */ boolean isClass; Class classStatic; Object classInstance; void setClassStatic( Class clas ) { this.classStatic = clas; importStatic( clas ); } void setClassInstance( Object instance ) { this.classInstance = instance; importObject( instance ); } Object getClassInstance() throws UtilEvalError { if ( classInstance != null ) return classInstance; if ( classStatic != null //|| ( getParent()!=null && getParent().classStatic != null ) ) throw new UtilEvalError( "Can't refer to class instance from static context."); else throw new InterpreterError( "Can't resolve class instance 'this' in: "+this); } /** Local class cache for classes resolved through this namespace using getClass() (taking into account imports). Only unqualified class names are cached here (those which might be imported). Qualified names are always absolute and are cached by BshClassManager. */ transient private Hashtable classCache; // End instance data // Begin constructors /** @parent the parent namespace of this namespace. Child namespaces inherit all variables and methods of their parent and can (of course) override / shadow them. */ public NameSpace( NameSpace parent, String name ) { // Note: in this case parent must have a class manager. this( parent, null, name ); } public NameSpace( BshClassManager classManager, String name ) { this( null, classManager, name ); } 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); } // End constructors public void setName( String name ) { this.nsName = name; } /** The name of this namespace. If the namespace is a method body namespace then this is the name of the method. If it's a class or class instance then it's the name of the class. */ public String getName() { return this.nsName; } /** Set the node associated with the creation of this namespace. This is used in debugging and to support the getInvocationLine() and getInvocationText() methods. */ void setNode( SimpleNode node ) { callerInfoNode = node; } /** */ SimpleNode getNode() { if ( callerInfoNode != null ) return callerInfoNode; if ( parent != null ) return parent.getNode(); else return null; } /** Resolve name to an object through this namespace. */ public Object get( String name, Interpreter interpreter ) throws UtilEvalError { CallStack callstack = new CallStack( this ); return getNameResolver( name ).toObject( callstack, interpreter ); } public void setVariable(String name, Object value) throws UtilEvalError { setVariable(name,value,false); } /** Set the variable through this namespace. This method obeys the LOCALSCOPING property to determine how variables are set.

Note: this method is primarily intended for use internally. If you use this method outside of the bsh package and wish to set variables with primitive values you will have to wrap them using bsh.Primitive. @see bsh.Primitive

Setting a new variable (which didn't exist before) or removing a variable causes a namespace change. @param strictJava specifies whether strict java rules are applied. */ public void setVariable( String name, Object value, boolean strictJava ) throws UtilEvalError { // if localscoping switch follow strictJava, else recurse boolean recurse = Interpreter.LOCALSCOPING ? strictJava : true; setVariable( name, value, strictJava, recurse ); } /** Set a variable explicitly in the local scope. */ void setLocalVariable( String name, Object value, boolean strictJava ) throws UtilEvalError { setVariable( name, value, strictJava, false/*recurse*/ ); } /** Set the value of a the variable 'name' through this namespace. The variable may be an existing or non-existing variable. It may live in this namespace or in a parent namespace if recurse is true.

Note: This method is not public and does *not* know about LOCALSCOPING. Its caller methods must set recurse intelligently in all situations (perhaps based on LOCALSCOPING).

Note: this method is primarily intended for use internally. If you use this method outside of the bsh package and wish to set variables with primitive values you will have to wrap them using bsh.Primitive. @see bsh.Primitive

Setting a new variable (which didn't exist before) or removing a variable causes a namespace change. @param strictJava specifies whether strict java rules are applied. @param recurse determines whether we will search for the variable in our parent's scope before assigning locally. */ void setVariable( String name, Object value, boolean strictJava, boolean recurse ) throws UtilEvalError { if ( variables == null ) variables = new Hashtable(); // primitives should have been wrapped if ( value == null ) { // don't break jEdit core and plugins! //throw new InterpreterError("null variable value"); unsetVariable(name); return; } // Locate the variable definition if it exists. Variable existing = getVariableImpl( name, recurse ); // Found an existing variable here (or above if recurse allowed) if ( existing != null ) { try { existing.setValue( value, Variable.ASSIGNMENT ); } catch ( UtilEvalError e ) { throw new UtilEvalError( "Variable assignment: " + name + ": " + e.getMessage()); } } else // No previous variable definition found here (or above if recurse) { if ( strictJava ) throw new UtilEvalError( "(Strict Java mode) Assignment to undeclared variable: " +name ); // If recurse, set global untyped var, else set it here. //NameSpace varScope = recurse ? getGlobal() : this; // This modification makes default allocation local NameSpace varScope = this; varScope.variables.put( name, new Variable( name, value, null/*modifiers*/ ) ); // nameSpaceChanged() on new variable addition nameSpaceChanged(); } } /** Remove the variable from the namespace. */ public void unsetVariable( String name ) { variables.remove( name ); nameSpaceChanged(); } /** Get the names of variables defined in this namespace. (This does not show variables in parent namespaces). */ public String [] getVariableNames() { if ( variables == null ) return new String [0]; else return enumerationToStringArray( variables.keys() ); } /** Get the names of methods declared in this namespace. (This does not include methods in parent namespaces). */ public String [] getMethodNames() { if ( methods == null ) return new String [0]; else return enumerationToStringArray( methods.keys() ); } /** Get the methods defined in this namespace. (This does not show methods in parent namespaces). Note: This will probably be renamed getDeclaredMethods() */ public BshMethod [] getMethods() { if ( methods == null ) return new BshMethod [0]; else return flattenMethodCollection( methods.elements() ); } private String [] enumerationToStringArray( Enumeration e ) { Vector v = new Vector(); while ( e.hasMoreElements() ) v.addElement( e.nextElement() ); String [] sa = new String [ v.size() ]; v.copyInto( sa ); return sa; } /** Flatten the vectors of overloaded methods to a single array. @see #getMethods() */ private BshMethod [] flattenMethodCollection( Enumeration e ) { Vector v = new Vector(); while ( e.hasMoreElements() ) { Object o = e.nextElement(); if ( o instanceof BshMethod ) v.addElement( o ); else { Vector ov = (Vector)o; for(int i=0; i The declaringInterpreter is here to support callbacks from Java through generated proxies. The scripted object "remembers" who created it for things like printing messages and other per-interpreter phenomenon when called externally from Java. */ /* Note: we need a singleton here so that things like 'this == this' work (and probably a good idea for speed). Caching a single instance here seems technically incorrect, considering the declaringInterpreter could be different under some circumstances. (Case: a child interpreter running a source() / eval() command ). However the effect is just that the main interpreter that executes your script should be the one involved in call-backs from Java. I do not know if there are corner cases where a child interpreter would be the first to use a This reference in a namespace or if that would even cause any problems if it did... We could do some experiments to find out... and if necessary we could cache on a per interpreter basis if we had weak references... We might also look at skipping over child interpreters and going to the parent for the declaring interpreter, so we'd be sure to get the top interpreter. */ This getThis( Interpreter declaringInterpreter ) { if ( thisReference == null ) thisReference = This.getThis( this, declaringInterpreter ); return thisReference; } 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; } void setClassManager( BshClassManager classManager ) { this.classManager = 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 void setParent( NameSpace parent ) { this.parent = parent; // If we are disconnected from root we need to handle the def imports if ( parent == null ) loadDefaultImports(); } /** Get the specified variable in this namespace or a parent namespace.

Note: this method is primarily intended for use internally. If you use this method outside of the bsh package you will have to use Primitive.unwrap() to get primitive values. @see Primitive#unwrap( Object ) @return The variable value or Primitive.VOID if it is not defined. */ public Object getVariable( String name ) throws UtilEvalError { return getVariable( name, true ); } /** Get the specified variable in this namespace. @param recurse If recurse is true then we recursively search through parent namespaces for the variable.

Note: this method is primarily intended for use internally. If you use this method outside of the bsh package you will have to use Primitive.unwrap() to get primitive values. @see Primitive#unwrap( Object ) @return The variable value or Primitive.VOID if it is not defined. */ public Object getVariable( String name, boolean recurse ) throws UtilEvalError { Variable var = getVariableImpl( name, recurse ); return unwrapVariable( var ); } /** Locate a variable and return the Variable object with optional recursion through parent name spaces.

If this namespace is static, return only static variables. @return the Variable value or null if it is not defined */ protected Variable getVariableImpl( String name, boolean recurse ) throws UtilEvalError { Variable var = null; // Change import precedence if we are a class body/instance // Get imported first. if ( var == null && isClass ) var = getImportedVar( name ); if ( var == null && variables != null ) var = (Variable)variables.get(name); // Change import precedence if we are a class body/instance if ( var == null && !isClass ) var = getImportedVar( name ); // try parent if ( recurse && (var == null) && (parent != null) ) var = parent.getVariableImpl( name, recurse ); return var; } /* Get variables declared in this namespace. */ public Variable [] getDeclaredVariables() { if ( variables == null ) return new Variable[0]; Variable [] vars = new Variable [ variables.size() ]; int i=0; for( Enumeration e = variables.elements(); e.hasMoreElements(); ) vars[i++] = (Variable)e.nextElement(); return vars; } /** Unwrap a variable to its value. @return return the variable value. A null var is mapped to Primitive.VOID */ protected Object unwrapVariable( Variable var ) throws UtilEvalError { return (var == null) ? Primitive.VOID : var.getValue(); } /** @deprecated See #setTypedVariable( String, Class, Object, Modifiers ) */ public void setTypedVariable( String name, Class type, Object value, boolean isFinal ) throws UtilEvalError { Modifiers modifiers = new Modifiers(); if ( isFinal ) modifiers.addModifier( Modifiers.FIELD, "final" ); setTypedVariable( name, type, value, modifiers ); } /** Declare a variable in the local scope and set its initial value. Value may be null to indicate that we would like the default value for the variable type. (e.g. 0 for integer types, null for object types). An existing typed variable may only be set to the same type. If an untyped variable of the same name exists it will be overridden with the new typed var. The set will perform a Types.getAssignableForm() on the value if necessary.

Note: this method is primarily intended for use internally. If you use this method outside of the bsh package and wish to set variables with primitive values you will have to wrap them using bsh.Primitive. @see bsh.Primitive @param value If value is null, you'll get the default value for the type @param modifiers may be null */ public void setTypedVariable( String name, Class type, Object value, Modifiers modifiers ) throws UtilEvalError { //checkVariableModifiers( name, modifiers ); if ( variables == null ) variables = new Hashtable(); // Setting a typed variable is always a local operation. Variable existing = getVariableImpl( name, false/*recurse*/ ); // Null value is just a declaration // Note: we might want to keep any existing value here instead of reset /* // Moved to Variable if ( value == null ) value = Primitive.getDefaultValue( type ); */ // does the variable already exist? if ( existing != null ) { // Is it typed? if ( existing.getType() != null ) { // If it had a different type throw error. // This allows declaring the same var again, but not with // a different (even if assignable) type. if ( existing.getType() != type ) { throw new UtilEvalError( "Typed variable: "+name +" was previously declared with type: " + existing.getType() ); } else { // else set it and return existing.setValue( value, Variable.DECLARATION ); return; } } // Careful here: // else fall through to override and install the new typed version } // Add the new typed var variables.put( name, new Variable( name, type, value, modifiers ) ); } /** Dissallow static vars outside of a class @param name is here just to allow the error message to use it protected void checkVariableModifiers( String name, Modifiers modifiers ) throws UtilEvalError { if ( modifiers!=null && modifiers.hasModifier("static") ) throw new UtilEvalError( "Can't declare static variable outside of class: "+name ); } */ /** Note: this is primarily for internal use. @see Interpreter#source( String ) @see Interpreter#eval( String ) */ public void setMethod( String name, BshMethod method ) throws UtilEvalError { //checkMethodModifiers( method ); if ( methods == null ) methods = new Hashtable(); Object m = methods.get(name); if ( m == null ) methods.put(name, method); else if ( m instanceof BshMethod ) { Vector v = new Vector(); v.addElement( m ); v.addElement( method ); methods.put( name, v ); } else // Vector ((Vector)m).addElement( method ); } /** @see #getMethod( String, Class [], boolean ) @see #getMethod( String, Class [] ) */ public BshMethod getMethod( String name, Class [] sig ) throws UtilEvalError { return getMethod( name, sig, false/*declaredOnly*/ ); } /** Get the bsh method matching the specified signature declared in this name space or a parent.

Note: this method is primarily intended for use internally. If you use this method outside of the bsh package you will have to be familiar with BeanShell's use of the Primitive wrapper class. @see bsh.Primitive @return the BshMethod or null if not found @param declaredOnly if true then only methods declared directly in this namespace will be found and no inherited or imported methods will be visible. */ public BshMethod getMethod( String name, Class [] sig, boolean declaredOnly ) throws UtilEvalError { BshMethod method = null; // Change import precedence if we are a class body/instance // Get import first. if ( method == null && isClass && !declaredOnly ) method = getImportedMethod( name, sig ); Object m = null; if ( method == null && methods != null ) { m = methods.get(name); // m contains either BshMethod or Vector of BshMethod if ( m != null ) { // unwrap BshMethod [] ma; if ( m instanceof Vector ) { Vector vm = (Vector)m; ma = new BshMethod[ vm.size() ]; vm.copyInto( ma ); } else ma = new BshMethod[] { (BshMethod)m }; // Apply most specific signature matching Class [][] candidates = new Class[ ma.length ][]; for( int i=0; i< ma.length; i++ ) candidates[i] = ma[i].getParameterTypes(); int match = Reflect.findMostSpecificSignature( sig, candidates ); if ( match != -1 ) method = ma[match]; } } if ( method == null && !isClass && !declaredOnly ) method = getImportedMethod( name, sig ); // try parent if ( !declaredOnly && (method == null) && (parent != null) ) return parent.getMethod( name, sig ); return method; } /** Import a class name. Subsequent imports override earlier ones */ public void importClass(String name) { if ( importedClasses == null ) importedClasses = new Hashtable(); importedClasses.put( Name.suffix(name, 1), name ); nameSpaceChanged(); } /** subsequent imports override earlier ones */ public void importPackage(String name) { if(importedPackages == null) importedPackages = new Vector(); // If it exists, remove it and add it at the end (avoid memory leak) if ( importedPackages.contains( name ) ) importedPackages.remove( name ); importedPackages.addElement(name); nameSpaceChanged(); } static class CommandPathEntry { String path; Class clas; CommandPathEntry(String path, Class clas) { this.path = path; this.clas = clas; } } /** Adds a URL to the command path. */ public void addCommandPath(String path, Class clas) { if(importedCommands == null) importedCommands = new Vector(); if(!path.endsWith("/")) path = path + "/"; importedCommands.addElement(new CommandPathEntry(path,clas)); } /** Remove a URLfrom the command path. */ public void removeCommandPath(String path, Class clas) { if(importedCommands == null) return; for(int i = 0; i < importedCommands.size(); i++) { CommandPathEntry entry = (CommandPathEntry)importedCommands .elementAt(i); if(entry.path.equals(path) && entry.clas == clas) { importedCommands.removeElementAt(i); return; } } } /** Looks up a command. */ public InputStream getCommand(String name) { if(importedCommands != null) { String extName = name + ".bsh"; for(int i = importedCommands.size() - 1; i >= 0; i--) { CommandPathEntry entry = (CommandPathEntry)importedCommands .elementAt(i); InputStream in = entry.clas.getResourceAsStream(entry.path + extName); if(in != null) return in; } } if(parent == null) return null; else return parent.getCommand(name); } /** 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.

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).

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.

@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(); InputStream in = getCommand( name ); if ( in != null ) return loadScriptedCommand( in, name, argTypes, name, interpreter ); /* // Chop leading "/" and change "/" to "." String className; if ( path.equals("/") ) className = name; else className = path.substring(1).replace('/','.') +"."+name; Class clas = bcm.classForName( className ); if ( clas != null ) return clas; */ if ( parent != null ) return parent.getCommand( name, argTypes, interpreter ); else return null; } protected BshMethod getImportedMethod( String name, Class [] sig ) throws UtilEvalError { // Try object imports if ( importedObjects != null ) for(int i=0; i Check the cache first. If an unqualified name look for imported class or package. Else try to load absolute name.

This method implements caching of unqualified names (normally imports). Qualified names are cached by the BshClassManager. Unqualified absolute class names (e.g. unpackaged Foo) are cached too so that we don't go searching through the imports for them each time. @return null if not found. */ private Class getClassImpl( String name ) throws UtilEvalError { Class c = null; // Check the cache if (classCache != null) { c = (Class)classCache.get(name); if ( c != null ) return c; } // Unqualified (simple, non-compound) name boolean unqualifiedName = !Name.isCompound(name); // Unqualified name check imported if ( unqualifiedName ) { // Try imported class if ( c == null ) c = getImportedClassImpl( name ); // if found as imported also cache it if ( c != null ) { cacheClass( name, c ); return c; } } // Try absolute c = classForName( name ); if ( c != null ) { // Cache unqualified names to prevent import check again if ( unqualifiedName ) cacheClass( name, c ); return c; } // Not found if ( Interpreter.DEBUG ) Interpreter.debug("getClass(): " + name + " not found in "+this); return null; } /** 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 = (String)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 = ((String)importedPackages.elementAt(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; } private Class classForName( String name ) { return getClassManager().classForName( name ); } /** Implements NameSource @return all variable and method names in this and all parent namespaces */ public String [] getAllNames() { Vector vec = new Vector(); getAllNamesAux( vec ); String [] names = new String [ vec.size() ]; vec.copyInto( names ); return names; } /** Helper for implementing NameSource */ protected void getAllNamesAux( Vector vec ) { Enumeration varNames = variables.keys(); while( varNames.hasMoreElements() ) vec.addElement( varNames.nextElement() ); Enumeration methodNames = methods.keys(); while( methodNames.hasMoreElements() ) vec.addElement( methodNames.nextElement() ); if ( parent != null ) parent.getAllNamesAux( vec ); } Vector nameSourceListeners; /** Implements NameSource Add a listener who is notified upon changes to names in this space. */ public void addNameSourceListener( NameSource.Listener listener ) { if ( nameSourceListeners == null ) nameSourceListeners = new Vector(); nameSourceListeners.addElement( listener ); } /** Perform "import *;" causing the entire classpath to be mapped. This can take a while. */ public void doSuperImport() throws UtilEvalError { getClassManager().doSuperImport(); } public String toString() { return "NameSpace: " + ( nsName==null ? super.toString() : nsName + " (" + super.toString() +")" ) + ( isClass ? " (isClass) " : "" ) + ( isMethod ? " (method) " : "" ) + ( classStatic != null ? " (class static) " : "" ) + ( classInstance != null ? " (class instance) " : "" ); } /* For serialization. Don't serialize non-serializable objects. */ private synchronized void writeObject(java.io.ObjectOutputStream s) throws IOException { // clear name resolvers... don't know if this is necessary. names = null; s.defaultWriteObject(); } /** Invoke a method in this namespace with the specified args and interpreter reference. No caller information or call stack is required. The method will appear as if called externally from Java.

@see bsh.This.invokeMethod( String methodName, Object [] args, Interpreter interpreter, CallStack callstack, SimpleNode callerInfo, boolean ) */ public Object invokeMethod( String methodName, Object [] args, Interpreter interpreter ) throws EvalError { return invokeMethod( methodName, args, interpreter, null, null ); } /** This method simply delegates to This.invokeMethod();

@see bsh.This.invokeMethod( String methodName, Object [] args, Interpreter interpreter, CallStack callstack, SimpleNode callerInfo ) */ public Object invokeMethod( String methodName, Object [] args, Interpreter interpreter, CallStack callstack, SimpleNode callerInfo ) throws EvalError { return getThis( interpreter ).invokeMethod( methodName, args, interpreter, callstack, callerInfo, false/*declaredOnly*/ ); } /** Clear all cached classes and names */ public void classLoaderChanged() { nameSpaceChanged(); } /** Clear all cached classes and names */ public void nameSpaceChanged() { classCache = null; names = null; } /** Import standard packages. Currently:

			importClass("bsh.EvalError");
			importClass("bsh.Interpreter");
			importPackage("javax.swing.event");
			importPackage("javax.swing");
			importPackage("java.awt.event");
			importPackage("java.awt");
			importPackage("java.net");
			importPackage("java.util");
			importPackage("java.io");
			importPackage("java.lang");
			addCommandPath("/bsh/commands",getClass());
		
*/ public void loadDefaultImports() { /** Note: the resolver looks through these in reverse order, per precedence rules... so for max efficiency put the most common ones later. */ importClass("bsh.EvalError"); importClass("bsh.Interpreter"); importPackage("javax.swing.event"); importPackage("javax.swing"); importPackage("java.awt.event"); importPackage("java.awt"); importPackage("java.net"); importPackage("java.util"); importPackage("java.io"); importPackage("java.lang"); addCommandPath("/bsh/commands",getClass()); } /** This is the factory for Name objects which resolve names within this namespace (e.g. toObject(), toClass(), toLHS()).

This was intended to support name resolver caching, allowing Name objects to cache info about the resolution of names for performance reasons. However this not proven useful yet.

We'll leave the caching as it will at least minimize Name object creation.

(This method would be called getName() if it weren't already used for the simple name of the NameSpace)

This method was public for a time, which was a mistake. Use get() instead. */ Name getNameResolver( String ambigname ) { if ( names == null ) names = new Hashtable(); Name name = (Name)names.get( ambigname ); if ( name == null ) { name = new Name( this, ambigname ); names.put( ambigname, name ); } return name; } public int getInvocationLine() { SimpleNode node = getNode(); if ( node != null ) return node.getLineNumber(); else return -1; } public String getInvocationText() { SimpleNode node = getNode(); if ( node != null ) return node.getText(); else return ""; } /** This is a helper method for working inside of bsh scripts and commands. In that context it is impossible to see a ClassIdentifier object for what it is. Attempting to access a method on a ClassIdentifier will look like a static method invocation. This method is in NameSpace for convenience (you don't have to import bsh.ClassIdentifier to use it ); */ public static Class identifierToClass( ClassIdentifier ci ) { return ci.getTargetClass(); } /** Clear all variables, methods, and imports from this namespace. If this namespace is the root, it will be reset to the default imports. @see #loadDefaultImports() */ public void clear() { variables = null; methods = null; importedClasses = null; importedPackages = null; importedCommands = null; importedObjects = null; if ( parent == null ) loadDefaultImports(); classCache = null; names = null; } /** Import a compiled Java object's methods and variables into this namespace. When no scripted method / command or variable is found locally in this namespace method / fields of the object will be checked. Objects are checked in the order of import with later imports taking precedence.

*/ /* Note: this impor pattern is becoming common... could factor it out into an importedObject Vector class. */ public void importObject( Object obj ) { if ( importedObjects == null ) importedObjects = new Vector(); // If it exists, remove it and add it at the end (avoid memory leak) if ( importedObjects.contains( obj ) ) importedObjects.remove( obj ); importedObjects.addElement( obj ); nameSpaceChanged(); } /** */ public void importStatic( Class clas ) { if ( importedStatic == null ) importedStatic = new Vector(); // If it exists, remove it and add it at the end (avoid memory leak) if ( importedStatic.contains( clas ) ) importedStatic.remove( clas ); importedStatic.addElement( clas ); nameSpaceChanged(); } /** Set the package name for classes defined in this namespace. Subsequent sets override the package. */ void setPackage( String packageName ) { this.packageName = packageName; } String getPackage() { if ( packageName != null ) return packageName; if ( parent != null ) return parent.getPackage(); return null; } }

... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.