KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > bsh > NameSpace


1 /*****************************************************************************
2  * *
3  * This file is part of the BeanShell Java Scripting distribution. *
4  * Documentation and updates may be found at http://www.beanshell.org/ *
5  * *
6  * Sun Public License Notice: *
7  * *
8  * The contents of this file are subject to the Sun Public License Version *
9  * 1.0 (the "License"); you may not use this file except in compliance with *
10  * the License. A copy of the License is available at http://www.sun.com *
11  * *
12  * The Original Code is BeanShell. The Initial Developer of the Original *
13  * Code is Pat Niemeyer. Portions created by Pat Niemeyer are Copyright *
14  * (C) 2000. All Rights Reserved. *
15  * *
16  * GNU Public License Notice: *
17  * *
18  * Alternatively, the contents of this file may be used under the terms of *
19  * the GNU Lesser General Public License (the "LGPL"), in which case the *
20  * provisions of LGPL are applicable instead of those above. If you wish to *
21  * allow use of your version of this file only under the terms of the LGPL *
22  * and not to allow others to use your version of this file under the SPL, *
23  * indicate your decision by deleting the provisions above and replace *
24  * them with the notice and other provisions required by the LGPL. If you *
25  * do not delete the provisions above, a recipient may use your version of *
26  * this file under either the SPL or the LGPL. *
27  * *
28  * Patrick Niemeyer (pat@pat.net) *
29  * Author of Learning Java, O'Reilly & Associates *
30  * http://www.pat.net/~pat/ *
31  * *
32  *****************************************************************************/

33
34
35 package bsh;
36
37 import java.util.*;
38
39 import java.io.InputStream JavaDoc;
40 import java.io.BufferedReader JavaDoc;
41 import java.io.InputStreamReader JavaDoc;
42 import java.io.IOException JavaDoc;
43
44 import java.lang.reflect.Method JavaDoc;
45 import java.lang.reflect.Field JavaDoc;
46
47 /**
48     A namespace in which methods, variables, and imports (class names) live.
49     This is package public because it is used in the implementation of some
50     bsh commands. However for normal use you should be using methods on
51     bsh.Interpreter to interact with your scripts.
52     <p>
53
54     A bsh.This object is a thin layer over a NameSpace that associates it with
55     an Interpreter instance. Together they comprise a Bsh scripted object
56     context.
57     <p>
58
59     Note: I'd really like to use collections here, but we have to keep this
60     compatible with JDK1.1
61 */

62 /*
63     Thanks to Slava Pestov (of jEdit fame) for import caching enhancements.
64     Note: This class has gotten too big. It should be broken down a bit.
65 */

66 public class NameSpace
67     implements java.io.Serializable JavaDoc, BshClassManager.Listener,
68     NameSource
69 {
70     public static final NameSpace JAVACODE =
71         new NameSpace((BshClassManager)null, "Called from compiled Java code.");
72     static {
73         JAVACODE.isMethod = true;
74     }
75
76     // Begin instance data
77
// Note: if we add something here we should reset it in the clear() method.
78

79     /**
80         The name of this namespace. If the namespace is a method body
81         namespace then this is the name of the method. If it's a class or
82         class instance then it's the name of the class.
83     */

84     private String JavaDoc nsName;
85     private NameSpace parent;
86     private Hashtable variables;
87     private Hashtable methods;
88
89     protected Hashtable importedClasses;
90     private Vector importedPackages;
91     private Vector importedCommands;
92     private Vector importedObjects;
93     private Vector importedStatic;
94     private String JavaDoc packageName;
95
96     transient private BshClassManager classManager;
97
98     // See notes in getThis()
99
private This thisReference;
100
101     /** Name resolver objects */
102     private Hashtable names;
103
104     /** The node associated with the creation of this namespace.
105         This is used support getInvocationLine() and getInvocationText(). */

106     SimpleNode callerInfoNode;
107
108     /**
109         Note that the namespace is a method body namespace. This is used for
110         printing stack traces in exceptions.
111     */

112     boolean isMethod;
113     /**
114         Note that the namespace is a class body or class instance namespace.
115         This is used for controlling static/object import precedence, etc.
116     */

117     /*
118         Note: We will ll move this behavior out to a subclass of
119         NameSpace, but we'll start here.
120     */

121     boolean isClass;
122     Class JavaDoc classStatic;
123     Object JavaDoc classInstance;
124
125     void setClassStatic( Class JavaDoc clas ) {
126         this.classStatic = clas;
127         importStatic( clas );
128     }
129     void setClassInstance( Object JavaDoc instance ) {
130         this.classInstance = instance;
131         importObject( instance );
132     }
133     Object JavaDoc getClassInstance()
134         throws UtilEvalError
135     {
136         if ( classInstance != null )
137             return classInstance;
138
139         if ( classStatic != null
140             //|| ( getParent()!=null && getParent().classStatic != null )
141
)
142             throw new UtilEvalError(
143                 "Can't refer to class instance from static context.");
144         else
145             throw new InterpreterError(
146                 "Can't resolve class instance 'this' in: "+this);
147     }
148
149
150     /**
151         Local class cache for classes resolved through this namespace using
152         getClass() (taking into account imports). Only unqualified class names
153         are cached here (those which might be imported). Qualified names are
154         always absolute and are cached by BshClassManager.
155     */

156     transient private Hashtable classCache;
157
158     // End instance data
159

160     // Begin constructors
161

162     /**
163         @parent the parent namespace of this namespace. Child namespaces
164         inherit all variables and methods of their parent and can (of course)
165         override / shadow them.
166     */

167     public NameSpace( NameSpace parent, String JavaDoc name )
168     {
169         // Note: in this case parent must have a class manager.
170
this( parent, null, name );
171     }
172
173     public NameSpace( BshClassManager classManager, String JavaDoc name )
174     {
175         this( null, classManager, name );
176     }
177
178     public NameSpace(
179         NameSpace parent, BshClassManager classManager, String JavaDoc name )
180     {
181         // We might want to do this here rather than explicitly in Interpreter
182
// for global (see also prune())
183
//if ( classManager == null && (parent == null ) )
184
// create our own class manager?
185

186         setName(name);
187         setParent(parent);
188         setClassManager( classManager );
189
190         // Register for notification of classloader change
191
if ( classManager != null )
192             classManager.addListener(this);
193     }
194
195     // End constructors
196

197     public void setName( String JavaDoc name ) {
198         this.nsName = name;
199     }
200
201     /**
202         The name of this namespace. If the namespace is a method body
203         namespace then this is the name of the method. If it's a class or
204         class instance then it's the name of the class.
205     */

206     public String JavaDoc getName() {
207         return this.nsName;
208     }
209
210     /**
211         Set the node associated with the creation of this namespace.
212         This is used in debugging and to support the getInvocationLine()
213         and getInvocationText() methods.
214     */

215     void setNode( SimpleNode node ) {
216         callerInfoNode = node;
217     }
218
219     /**
220     */

221     SimpleNode getNode()
222     {
223         if ( callerInfoNode != null )
224             return callerInfoNode;
225         if ( parent != null )
226             return parent.getNode();
227         else
228             return null;
229     }
230
231     /**
232         Resolve name to an object through this namespace.
233     */

234     public Object JavaDoc get( String JavaDoc name, Interpreter interpreter )
235         throws UtilEvalError
236     {
237         CallStack callstack = new CallStack( this );
238         return getNameResolver( name ).toObject( callstack, interpreter );
239     }
240
241     /**
242         Set the variable through this namespace.
243         This method obeys the LOCALSCOPING property to determine how variables
244         are set.
245         <p>
246         Note: this method is primarily intended for use internally. If you use
247         this method outside of the bsh package and wish to set variables with
248         primitive values you will have to wrap them using bsh.Primitive.
249         @see bsh.Primitive
250         <p>
251         Setting a new variable (which didn't exist before) or removing
252         a variable causes a namespace change.
253
254         @param strictJava specifies whether strict java rules are applied.
255     */

256     public void setVariable( String JavaDoc name, Object JavaDoc value, boolean strictJava )
257         throws UtilEvalError
258     {
259         // if localscoping switch follow strictJava, else recurse
260
boolean recurse = Interpreter.LOCALSCOPING ? strictJava : true;
261         setVariable( name, value, strictJava, recurse );
262     }
263
264     /**
265         Set a variable explicitly in the local scope.
266     */

267     void setLocalVariable(
268         String JavaDoc name, Object JavaDoc value, boolean strictJava )
269         throws UtilEvalError
270     {
271         setVariable( name, value, strictJava, false/*recurse*/ );
272     }
273
274     /**
275         Set the value of a the variable 'name' through this namespace.
276         The variable may be an existing or non-existing variable.
277         It may live in this namespace or in a parent namespace if recurse is
278         true.
279         <p>
280         Note: This method is not public and does *not* know about LOCALSCOPING.
281         Its caller methods must set recurse intelligently in all situations
282         (perhaps based on LOCALSCOPING).
283
284         <p>
285         Note: this method is primarily intended for use internally. If you use
286         this method outside of the bsh package and wish to set variables with
287         primitive values you will have to wrap them using bsh.Primitive.
288         @see bsh.Primitive
289         <p>
290         Setting a new variable (which didn't exist before) or removing
291         a variable causes a namespace change.
292
293         @param strictJava specifies whether strict java rules are applied.
294         @param recurse determines whether we will search for the variable in
295           our parent's scope before assigning locally.
296     */

297     void setVariable(
298         String JavaDoc name, Object JavaDoc value, boolean strictJava, boolean recurse )
299         throws UtilEvalError
300     {
301         if ( variables == null )
302             variables = new Hashtable();
303
304         // primitives should have been wrapped
305
// {{{ jEdit change
306
//if ( value == null )
307
// throw new InterpreterError("null variable value");
308

309         if ( value == null ) {
310             // don't break jEdit core and plugins!
311
unsetVariable(name);
312             return;
313         }
314
315         // }}}
316
// Locate the variable definition if it exists.
317
Variable existing = getVariableImpl( name, recurse );
318
319         // Found an existing variable here (or above if recurse allowed)
320
if ( existing != null )
321         {
322             try {
323                 existing.setValue( value, Variable.ASSIGNMENT );
324             } catch ( UtilEvalError e ) {
325                 throw new UtilEvalError(
326                     "Variable assignment: " + name + ": " + e.getMessage());
327             }
328         } else
329         // No previous variable definition found here (or above if recurse)
330
{
331             if ( strictJava )
332                 throw new UtilEvalError(
333                     "(Strict Java mode) Assignment to undeclared variable: "
334                     +name );
335
336             // If recurse, set global untyped var, else set it here.
337
//NameSpace varScope = recurse ? getGlobal() : this;
338
// This modification makes default allocation local
339
NameSpace varScope = this;
340
341             varScope.variables.put(
342                 name, new Variable( name, value, null/*modifiers*/ ) );
343
344             // nameSpaceChanged() on new variable addition
345
nameSpaceChanged();
346         }
347     }
348
349     /**
350         Remove the variable from the namespace.
351     */

352     public void unsetVariable( String JavaDoc name )
353     {
354         if ( variables != null )
355         {
356             variables.remove( name );
357             nameSpaceChanged();
358         }
359     }
360
361     /**
362         Get the names of variables defined in this namespace.
363         (This does not show variables in parent namespaces).
364     */

365     public String JavaDoc [] getVariableNames() {
366         if ( variables == null )
367             return new String JavaDoc [0];
368         else
369             return enumerationToStringArray( variables.keys() );
370     }
371
372     /**
373         Get the names of methods declared in this namespace.
374         (This does not include methods in parent namespaces).
375     */

376     public String JavaDoc [] getMethodNames()
377     {
378         if ( methods == null )
379             return new String JavaDoc [0];
380         else
381             return enumerationToStringArray( methods.keys() );
382     }
383
384     /**
385         Get the methods defined in this namespace.
386         (This does not show methods in parent namespaces).
387         Note: This will probably be renamed getDeclaredMethods()
388     */

389     public BshMethod [] getMethods()
390     {
391         if ( methods == null )
392             return new BshMethod [0];
393         else
394             return flattenMethodCollection( methods.elements() );
395     }
396
397     private String JavaDoc [] enumerationToStringArray( Enumeration e ) {
398         Vector v = new Vector();
399         while ( e.hasMoreElements() )
400             v.addElement( e.nextElement() );
401         String JavaDoc [] sa = new String JavaDoc [ v.size() ];
402         v.copyInto( sa );
403         return sa;
404     }
405
406     /**
407         Flatten the vectors of overloaded methods to a single array.
408         @see #getMethods()
409     */

410     private BshMethod [] flattenMethodCollection( Enumeration e ) {
411         Vector v = new Vector();
412         while ( e.hasMoreElements() ) {
413             Object JavaDoc o = e.nextElement();
414             if ( o instanceof BshMethod )
415                 v.addElement( o );
416             else {
417                 Vector ov = (Vector)o;
418                 for(int i=0; i<ov.size(); i++)
419                     v.addElement( ov.elementAt( i ) );
420             }
421         }
422         BshMethod [] bma = new BshMethod [ v.size() ];
423         v.copyInto( bma );
424         return bma;
425     }
426
427     /**
428         Get the parent namespace.
429         Note: this isn't quite the same as getSuper().
430         getSuper() returns 'this' if we are at the root namespace.
431     */

432     public NameSpace getParent() {
433         return parent;
434     }
435
436     /**
437         Get the parent namespace' This reference or this namespace' This
438         reference if we are the top.
439     */

440     public This getSuper( Interpreter declaringInterpreter )
441     {
442         if ( parent != null )
443             return parent.getThis( declaringInterpreter );
444         else
445             return getThis( declaringInterpreter );
446     }
447
448     /**
449         Get the top level namespace or this namespace if we are the top.
450         Note: this method should probably return type bsh.This to be consistent
451         with getThis();
452     */

453     public This getGlobal( Interpreter declaringInterpreter )
454     {
455         if ( parent != null )
456             return parent.getGlobal( declaringInterpreter );
457         else
458             return getThis( declaringInterpreter );
459     }
460
461
462     /**
463         A This object is a thin layer over a namespace, comprising a bsh object
464         context. It handles things like the interface types the bsh object
465         supports and aspects of method invocation on it.
466         <p>
467
468         The declaringInterpreter is here to support callbacks from Java through
469         generated proxies. The scripted object "remembers" who created it for
470         things like printing messages and other per-interpreter phenomenon
471         when called externally from Java.
472     */

473     /*
474         Note: we need a singleton here so that things like 'this == this' work
475         (and probably a good idea for speed).
476
477         Caching a single instance here seems technically incorrect,
478         considering the declaringInterpreter could be different under some
479         circumstances. (Case: a child interpreter running a source() / eval()
480         command ). However the effect is just that the main interpreter that
481         executes your script should be the one involved in call-backs from Java.
482
483         I do not know if there are corner cases where a child interpreter would
484         be the first to use a This reference in a namespace or if that would
485         even cause any problems if it did... We could do some experiments
486         to find out... and if necessary we could cache on a per interpreter
487         basis if we had weak references... We might also look at skipping
488         over child interpreters and going to the parent for the declaring
489         interpreter, so we'd be sure to get the top interpreter.
490     */

491     This getThis( Interpreter declaringInterpreter )
492     {
493         if ( thisReference == null )
494             thisReference = This.getThis( this, declaringInterpreter );
495
496         return thisReference;
497     }
498
499     public BshClassManager getClassManager()
500     {
501         if ( classManager != null )
502             return classManager;
503         if ( parent != null && parent != JAVACODE )
504             return parent.getClassManager();
505
506 System.out.println("experiment: creating class manager");
507         classManager = BshClassManager.createClassManager( null/*interp*/ );
508
509         //Interpreter.debug("No class manager namespace:" +this);
510
return classManager;
511     }
512
513     void setClassManager( BshClassManager classManager ) {
514         this.classManager = classManager;
515     }
516
517     /**
518         Used for serialization
519     */

520     public void prune()
521     {
522         // Cut off from parent, we must have our own class manager.
523
// Can't do this in the run() command (needs to resolve stuff)
524
// Should we do it by default when we create a namespace will no
525
// parent of class manager?
526

527         if ( this.classManager == null )
528 // XXX if we keep the createClassManager in getClassManager then we can axe
529
// this?
530
setClassManager(
531                 BshClassManager.createClassManager( null/*interp*/ ) );
532
533         setParent( null );
534     }
535
536     public void setParent( NameSpace parent )
537     {
538         this.parent = parent;
539
540         // If we are disconnected from root we need to handle the def imports
541
if ( parent == null )
542             loadDefaultImports();
543     }
544
545     /**
546         Get the specified variable in this namespace or a parent namespace.
547         <p>
548         Note: this method is primarily intended for use internally. If you use
549         this method outside of the bsh package you will have to use
550         Primitive.unwrap() to get primitive values.
551         @see Primitive#unwrap( Object )
552
553         @return The variable value or Primitive.VOID if it is not defined.
554     */

555     public Object JavaDoc getVariable( String JavaDoc name )
556         throws UtilEvalError
557     {
558         return getVariable( name, true );
559     }
560
561     /**
562         Get the specified variable in this namespace.
563         @param recurse If recurse is true then we recursively search through
564         parent namespaces for the variable.
565         <p>
566         Note: this method is primarily intended for use internally. If you use
567         this method outside of the bsh package you will have to use
568         Primitive.unwrap() to get primitive values.
569         @see Primitive#unwrap( Object )
570
571         @return The variable value or Primitive.VOID if it is not defined.
572     */

573     public Object JavaDoc getVariable( String JavaDoc name, boolean recurse )
574         throws UtilEvalError
575     {
576         Variable var = getVariableImpl( name, recurse );
577         return unwrapVariable( var );
578     }
579
580     /**
581         Locate a variable and return the Variable object with optional
582         recursion through parent name spaces.
583         <p/>
584         If this namespace is static, return only static variables.
585
586         @return the Variable value or null if it is not defined
587     */

588     protected Variable getVariableImpl( String JavaDoc name, boolean recurse )
589         throws UtilEvalError
590     {
591         Variable var = null;
592
593         // Change import precedence if we are a class body/instance
594
// Get imported first.
595
if ( var == null && isClass )
596             var = getImportedVar( name );
597
598         if ( var == null && variables != null )
599             var = (Variable)variables.get(name);
600
601         // Change import precedence if we are a class body/instance
602
if ( var == null && !isClass )
603             var = getImportedVar( name );
604
605         // try parent
606
if ( recurse && (var == null) && (parent != null) )
607             var = parent.getVariableImpl( name, recurse );
608
609         return var;
610     }
611
612     /*
613         Get variables declared in this namespace.
614     */

615     public Variable [] getDeclaredVariables()
616     {
617         if ( variables == null )
618             return new Variable[0];
619         Variable [] vars = new Variable [ variables.size() ];
620         int i=0;
621         for( Enumeration e = variables.elements(); e.hasMoreElements(); )
622             vars[i++] = (Variable)e.nextElement();
623         return vars;
624     }
625
626     /**
627         Unwrap a variable to its value.
628         @return return the variable value. A null var is mapped to
629             Primitive.VOID
630     */

631     protected Object JavaDoc unwrapVariable( Variable var )
632         throws UtilEvalError
633     {
634         return (var == null) ? Primitive.VOID : var.getValue();
635     }
636
637     /**
638         @deprecated See #setTypedVariable( String, Class, Object, Modifiers )
639     */

640     public void setTypedVariable(
641         String JavaDoc name, Class JavaDoc type, Object JavaDoc value, boolean isFinal )
642         throws UtilEvalError
643     {
644         Modifiers modifiers = new Modifiers();
645         if ( isFinal )
646             modifiers.addModifier( Modifiers.FIELD, "final" );
647         setTypedVariable( name, type, value, modifiers );
648     }
649
650     /**
651         Declare a variable in the local scope and set its initial value.
652         Value may be null to indicate that we would like the default value
653         for the variable type. (e.g. 0 for integer types, null for object
654         types). An existing typed variable may only be set to the same type.
655         If an untyped variable of the same name exists it will be overridden
656         with the new typed var.
657         The set will perform a Types.getAssignableForm() on the value if
658         necessary.
659
660         <p>
661         Note: this method is primarily intended for use internally. If you use
662         this method outside of the bsh package and wish to set variables with
663         primitive values you will have to wrap them using bsh.Primitive.
664         @see bsh.Primitive
665
666         @param value If value is null, you'll get the default value for the type
667         @param modifiers may be null
668     */

669     public void setTypedVariable(
670         String JavaDoc name, Class JavaDoc type, Object JavaDoc value, Modifiers modifiers )
671         throws UtilEvalError
672     {
673         //checkVariableModifiers( name, modifiers );
674

675         if ( variables == null )
676             variables = new Hashtable();
677
678         // Setting a typed variable is always a local operation.
679
Variable existing = getVariableImpl( name, false/*recurse*/ );
680
681
682         // Null value is just a declaration
683
// Note: we might want to keep any existing value here instead of reset
684
/*
685     // Moved to Variable
686         if ( value == null )
687             value = Primitive.getDefaultValue( type );
688     */

689
690         // does the variable already exist?
691
if ( existing != null )
692         {
693             // Is it typed?
694
if ( existing.getType() != null )
695             {
696                 // If it had a different type throw error.
697
// This allows declaring the same var again, but not with
698
// a different (even if assignable) type.
699
if ( existing.getType() != type )
700                 {
701                     throw new UtilEvalError( "Typed variable: "+name
702                         +" was previously declared with type: "
703                         + existing.getType() );
704                 } else
705                 {
706                     // else set it and return
707
existing.setValue( value, Variable.DECLARATION );
708                     return;
709                 }
710             }
711             // Careful here:
712
// else fall through to override and install the new typed version
713
}
714
715         // Add the new typed var
716
variables.put( name, new Variable( name, type, value, modifiers ) );
717     }
718
719     /**
720         Dissallow static vars outside of a class
721         @param name is here just to allow the error message to use it
722     protected void checkVariableModifiers( String name, Modifiers modifiers )
723         throws UtilEvalError
724     {
725         if ( modifiers!=null && modifiers.hasModifier("static") )
726             throw new UtilEvalError(
727                 "Can't declare static variable outside of class: "+name );
728     }
729     */

730
731     /**
732         Note: this is primarily for internal use.
733         @see Interpreter#source( String )
734         @see Interpreter#eval( String )
735     */

736     public void setMethod( String JavaDoc name, BshMethod method )
737         throws UtilEvalError
738     {
739         //checkMethodModifiers( method );
740

741         if ( methods == null )
742             methods = new Hashtable();
743
744         Object JavaDoc m = methods.get(name);
745
746         //{{{ jEdit version: properly handle methods with same signature.
747
if (m == null)
748             methods.put(name, method);
749         else if (m instanceof BshMethod)
750         {
751             // is the new method overriding the old method?
752
if (Arrays.equals(((BshMethod)m).getParameterTypes(),
753                               method.getParameterTypes()))
754             {
755                 methods.put(name, method);
756             }
757             else
758             {
759                 Vector v = new Vector();
760                 v.addElement( m );
761                 v.addElement( method );
762                 methods.put( name, v );
763             }
764         }
765         else
766         {
767             Vector _methods = (Vector) m;
768             for (int i = 0; i < _methods.size(); i++)
769             {
770                 // Check whether the new method overrides some old
771
// method in the list.
772
BshMethod _old_m = (BshMethod) _methods.get(i);
773                 if (Arrays.equals(_old_m.getParameterTypes(),
774                                   method.getParameterTypes()))
775                 {
776                     _methods.remove(i);
777                     break;
778                 }
779             }
780             _methods.addElement( method );
781         }
782         //}}}
783

784         //{{{ Original BeanShell code
785
// if ( m == null )
786
// methods.put(name, method);
787
// else
788
// if ( m instanceof BshMethod ) {
789
// Vector v = new Vector();
790
// v.addElement( m );
791
// v.addElement( method );
792
// methods.put( name, v );
793
// } else // Vector
794
// ((Vector)m).addElement( method );
795
//}}}
796
}
797
798     /**
799         @see #getMethod( String, Class [], boolean )
800         @see #getMethod( String, Class [] )
801     */

802     public BshMethod getMethod( String JavaDoc name, Class JavaDoc [] sig )
803         throws UtilEvalError
804     {
805         return getMethod( name, sig, false/*declaredOnly*/ );
806     }
807
808     /**
809         Get the bsh method matching the specified signature declared in
810         this name space or a parent.
811         <p>
812         Note: this method is primarily intended for use internally. If you use
813         this method outside of the bsh package you will have to be familiar
814         with BeanShell's use of the Primitive wrapper class.
815         @see bsh.Primitive
816         @return the BshMethod or null if not found
817         @param declaredOnly if true then only methods declared directly in this
818             namespace will be found and no inherited or imported methods will
819             be visible.
820     */

821     public BshMethod getMethod(
822         String JavaDoc name, Class JavaDoc [] sig, boolean declaredOnly )
823         throws UtilEvalError
824     {
825         BshMethod method = null;
826
827         // Change import precedence if we are a class body/instance
828
// Get import first.
829
if ( method == null && isClass && !declaredOnly )
830             method = getImportedMethod( name, sig );
831
832         Object JavaDoc m = null;
833         if ( method == null && methods != null )
834         {
835             m = methods.get(name);
836
837             // m contains either BshMethod or Vector of BshMethod
838
if ( m != null )
839             {
840                 // unwrap
841
BshMethod [] ma;
842                 if ( m instanceof Vector )
843                 {
844                     Vector vm = (Vector)m;
845                     ma = new BshMethod[ vm.size() ];
846                     vm.copyInto( ma );
847                 } else
848                     ma = new BshMethod[] { (BshMethod)m };
849
850                 // Apply most specific signature matching
851
Class JavaDoc [][] candidates = new Class JavaDoc[ ma.length ][];
852                 for( int i=0; i< ma.length; i++ )
853                     candidates[i] = ma[i].getParameterTypes();
854
855                 int match =
856                     Reflect.findMostSpecificSignature( sig, candidates );
857                 if ( match != -1 )
858                     method = ma[match];
859             }
860         }
861
862         if ( method == null && !isClass && !declaredOnly )
863             method = getImportedMethod( name, sig );
864
865         // try parent
866
if ( !declaredOnly && (method == null) && (parent != null) )
867             return parent.getMethod( name, sig );
868
869         return method;
870     }
871
872     /**
873         Import a class name.
874         Subsequent imports override earlier ones
875     */

876     public void importClass(String JavaDoc name)
877     {
878         if ( importedClasses == null )
879             importedClasses = new Hashtable();
880
881         importedClasses.put( Name.suffix(name, 1), name );
882         nameSpaceChanged();
883     }
884
885     /**
886         subsequent imports override earlier ones
887     */

888     public void importPackage(String JavaDoc name)
889     {
890         if(importedPackages == null)
891             importedPackages = new Vector();
892
893         // If it exists, remove it and add it at the end (avoid memory leak)
894
if ( importedPackages.contains( name ) )
895             importedPackages.remove( name );
896
897         importedPackages.addElement(name);
898         nameSpaceChanged();
899     }
900
901     /**
902         Import scripted or compiled BeanShell commands in the following package
903         in the classpath. You may use either "/" path or "." package notation.
904         e.g. importCommands("/bsh/commands") or importCommands("bsh.commands")
905         are equivalent. If a relative path style specifier is used then it is
906         made into an absolute path by prepending "/".
907     */

908     public void importCommands( String JavaDoc name )
909     {
910         if ( importedCommands == null )
911             importedCommands = new Vector();
912
913         // dots to slashes
914
name = name.replace('.','/');
915         // absolute
916
if ( !name.startsWith("/") )
917             name = "/"+name;
918         // remove trailing (but preserve case of simple "/")
919
if ( name.length() > 1 && name.endsWith("/") )
920             name = name.substring( 0, name.length()-1 );
921
922         // If it exists, remove it and add it at the end (avoid memory leak)
923
if ( importedCommands.contains( name ) )
924             importedCommands.remove( name );
925
926         importedCommands.addElement(name);
927         nameSpaceChanged();
928     }
929
930     /**
931         A command is a scripted method or compiled command class implementing a
932         specified method signature. Commands are loaded from the classpath
933         and may be imported using the importCommands() method.
934         <p/>
935
936         This method searches the imported commands packages for a script or
937         command object corresponding to the name of the method. If it is a
938         script the script is sourced into this namespace and the BshMethod for
939         the requested signature is returned. If it is a compiled class the
940         class is returned. (Compiled command classes implement static invoke()
941         methods).
942         <p/>
943
944         The imported packages are searched in reverse order, so that later
945         imports take priority.
946         Currently only the first object (script or class) with the appropriate
947         name is checked. If another, overloaded form, is located in another
948         package it will not currently be found. This could be fixed.
949         <p/>
950
951         @return a BshMethod, Class, or null if no such command is found.
952         @param name is the name of the desired command method
953         @param argTypes is the signature of the desired command method.
954         @throws UtilEvalError if loadScriptedCommand throws UtilEvalError
955             i.e. on errors loading a script that was found
956     */

957     // {{{ jEdit's getCommand
958
public Object JavaDoc getCommand(
959         String JavaDoc name, Class JavaDoc [] argTypes, Interpreter interpreter )
960         throws UtilEvalError
961     {
962         if (Interpreter.DEBUG) Interpreter.debug("getCommand: "+name);
963         BshClassManager bcm = interpreter.getClassManager();
964
965         InputStream JavaDoc in = getCommand( name );
966
967         if ( in != null )
968             return loadScriptedCommand(
969                 in, name, argTypes, name, interpreter );
970
971         /* // Chop leading "/" and change "/" to "."
972         String className;
973         if ( path.equals("/") )
974             className = name;
975         else
976             className = path.substring(1).replace('/','.') +"."+name;
977
978         Class clas = bcm.classForName( className );
979         if ( clas != null )
980             return clas; */

981
982         if ( parent != null )
983             return parent.getCommand( name, argTypes, interpreter );
984         else
985             return null;
986     }
987
988
989     /*
990     public Object getCommand(
991         String name, Class [] argTypes, Interpreter interpreter )
992         throws UtilEvalError
993     {
994         if (Interpreter.DEBUG) Interpreter.debug("getCommand: "+name);
995         BshClassManager bcm = interpreter.getClassManager();
996
997         if ( importedCommands != null )
998         {
999             // loop backwards for precedence
1000            for(int i=importedCommands.size()-1; i>=0; i--)
1001            {
1002                String path = (String)importedCommands.elementAt(i);
1003
1004                String scriptPath;
1005                if ( path.equals("/") )
1006                    scriptPath = path + name +".bsh";
1007                else
1008                    scriptPath = path +"/"+ name +".bsh";
1009
1010                Interpreter.debug("searching for script: "+scriptPath );
1011
1012                InputStream in = bcm.getResourceAsStream( scriptPath );
1013
1014                if ( in != null )
1015                    return loadScriptedCommand(
1016                        in, name, argTypes, scriptPath, interpreter );
1017
1018                // Chop leading "/" and change "/" to "."
1019                String className;
1020                if ( path.equals("/") )
1021                    className = name;
1022                else
1023                    className = path.substring(1).replace('/','.') +"."+name;
1024
1025                Interpreter.debug("searching for class: "+className);
1026                Class clas = bcm.classForName( className );
1027                if ( clas != null )
1028                    return clas;
1029            }
1030        }
1031
1032        if ( parent != null )
1033            return parent.getCommand( name, argTypes, interpreter );
1034        else
1035            return null;
1036    } */

1037    // }}}
1038
protected BshMethod getImportedMethod( String JavaDoc name, Class JavaDoc [] sig )
1039        throws UtilEvalError
1040    {
1041        // Try object imports
1042
if ( importedObjects != null )
1043        for(int i=0; i<importedObjects.size(); i++)
1044        {
1045            Object JavaDoc object = importedObjects.elementAt(i);
1046            Class JavaDoc clas = object.getClass();
1047            Method JavaDoc method = Reflect.resolveJavaMethod(
1048                getClassManager(), clas, name, sig, false/*onlyStatic*/ );
1049            if ( method != null )
1050                return new BshMethod( method, object );
1051        }
1052
1053        // Try static imports
1054
if ( importedStatic!= null )
1055        for(int i=0; i<importedStatic.size(); i++)
1056        {
1057            Class JavaDoc clas = (Class JavaDoc)importedStatic.elementAt(i);
1058            Method JavaDoc method = Reflect.resolveJavaMethod(
1059                getClassManager(), clas, name, sig, true/*onlyStatic*/ );
1060            if ( method != null )
1061                return new BshMethod( method, null/*object*/ );
1062        }
1063
1064        return null;
1065    }
1066
1067    protected Variable getImportedVar( String JavaDoc name )
1068        throws UtilEvalError
1069    {
1070        // Try object imports
1071
if ( importedObjects != null )
1072        for(int i=0; i<importedObjects.size(); i++)
1073        {
1074            Object JavaDoc object = importedObjects.elementAt(i);
1075            Class JavaDoc clas = object.getClass();
1076            Field JavaDoc field = Reflect.resolveJavaField(
1077                clas, name, false/*onlyStatic*/ );
1078            if ( field != null )
1079                return new Variable(
1080                    name, field.getType(), new LHS( object, field ) );
1081        }
1082
1083        // Try static imports
1084
if ( importedStatic!= null )
1085        for(int i=0; i<importedStatic.size(); i++)
1086        {
1087            Class JavaDoc clas = (Class JavaDoc)importedStatic.elementAt(i);
1088            Field JavaDoc field = Reflect.resolveJavaField(
1089                clas, name, true/*onlyStatic*/ );
1090            if ( field != null )
1091                return new Variable( name, field.getType(), new LHS( field ) );
1092        }
1093
1094        return null;
1095    }
1096
1097    /**
1098        Load a command script from the input stream and find the BshMethod in
1099        the target namespace.
1100        @throws UtilEvalError on error in parsing the script or if the the
1101            method is not found after parsing the script.
1102    */

1103    /*
1104        If we want to support multiple commands in the command path we need to
1105        change this to not throw the exception.
1106    */

1107    private BshMethod loadScriptedCommand(
1108        InputStream JavaDoc in, String JavaDoc name, Class JavaDoc [] argTypes, String JavaDoc resourcePath,
1109        Interpreter interpreter )
1110        throws UtilEvalError
1111    {
1112        try {
1113            interpreter.eval(
1114                new InputStreamReader JavaDoc(in), this, resourcePath );
1115        } catch ( EvalError e ) {
1116        /*
1117            Here we catch any EvalError from the interpreter because we are
1118            using it as a tool to load the command, not as part of the
1119            execution path.
1120        */

1121            Interpreter.debug( e.toString() );
1122            throw new UtilEvalError(
1123                "Error loading script: "+ e.getMessage());
1124        }
1125
1126        // Look for the loaded command
1127
BshMethod meth = getMethod( name, argTypes );
1128        /*
1129        if ( meth == null )
1130            throw new UtilEvalError("Loaded resource: " + resourcePath +
1131                "had an error or did not contain the correct method" );
1132        */

1133
1134        return meth;
1135    }
1136
1137    /**
1138        Helper that caches class.
1139    */

1140    void cacheClass( String JavaDoc name, Class JavaDoc c ) {
1141        if ( classCache == null ) {
1142            classCache = new Hashtable();
1143            //cacheCount++; // debug
1144
}
1145
1146        classCache.put(name, c);
1147    }
1148
1149    /**
1150        Load a class through this namespace taking into account imports.
1151        The class search will proceed through the parent namespaces if
1152        necessary.
1153
1154        @return null if not found.
1155    */

1156    public Class JavaDoc getClass( String JavaDoc name )
1157        throws UtilEvalError
1158    {
1159        Class JavaDoc c = getClassImpl(name);
1160        if ( c != null )
1161            return c;
1162        else
1163            // implement the recursion for getClassImpl()
1164
if ( parent != null )
1165                return parent.getClass( name );
1166            else
1167                return null;
1168    }
1169
1170    /**
1171        Implementation of getClass()
1172
1173        Load a class through this namespace taking into account imports.
1174        <p>
1175
1176        Check the cache first. If an unqualified name look for imported
1177        class or package. Else try to load absolute name.
1178        <p>
1179
1180        This method implements caching of unqualified names (normally imports).
1181        Qualified names are cached by the BshClassManager.
1182        Unqualified absolute class names (e.g. unpackaged Foo) are cached too
1183        so that we don't go searching through the imports for them each time.
1184
1185        @return null if not found.
1186    */

1187    private Class JavaDoc getClassImpl( String JavaDoc name )
1188        throws UtilEvalError
1189    {
1190        Class JavaDoc c = null;
1191
1192        // Check the cache
1193
if (classCache != null) {
1194            c = (Class JavaDoc)classCache.get(name);
1195
1196            if ( c != null )
1197                return c;
1198        }
1199
1200        // Unqualified (simple, non-compound) name
1201
boolean unqualifiedName = !Name.isCompound(name);
1202
1203        // Unqualified name check imported
1204
if ( unqualifiedName )
1205        {
1206            // Try imported class
1207
if ( c == null )
1208                c = getImportedClassImpl( name );
1209
1210            // if found as imported also cache it
1211
if ( c != null ) {
1212                cacheClass( name, c );
1213                return c;
1214            }
1215        }
1216
1217        // Try absolute
1218
c = classForName( name );
1219        if ( c != null ) {
1220            // Cache unqualified names to prevent import check again
1221
if ( unqualifiedName )
1222                cacheClass( name, c );
1223            return c;
1224        }
1225
1226        // Not found
1227
if ( Interpreter.DEBUG )
1228            Interpreter.debug("getClass(): " + name + " not found in "+this);
1229        return null;
1230    }
1231
1232    /**
1233        Try to make the name into an imported class.
1234        This method takes into account only imports (class or package)
1235        found directly in this NameSpace (no parent chain).
1236    */

1237    private Class JavaDoc getImportedClassImpl( String JavaDoc name )
1238        throws UtilEvalError
1239    {
1240        // Try explicitly imported class, e.g. import foo.Bar;
1241
String JavaDoc fullname = null;
1242        if ( importedClasses != null )
1243            fullname = (String JavaDoc)importedClasses.get(name);
1244
1245        // not sure if we should really recurse here for explicitly imported
1246
// class in parent...
1247

1248        if ( fullname != null )
1249        {
1250            /*
1251                Found the full name in imported classes.
1252            */

1253            // Try to make the full imported name
1254
Class JavaDoc clas=classForName(fullname);
1255
1256            // Handle imported inner class case
1257
if ( clas == null )
1258            {
1259                // Imported full name wasn't found as an absolute class
1260
// If it is compound, try to resolve to an inner class.
1261
// (maybe this should happen in the BshClassManager?)
1262

1263                if ( Name.isCompound( fullname ) )
1264                    try {
1265                        clas = getNameResolver( fullname ).toClass();
1266                    } catch ( ClassNotFoundException JavaDoc e ) { /* not a class */ }
1267                else
1268                    if ( Interpreter.DEBUG ) Interpreter.debug(
1269                        "imported unpackaged name not found:" +fullname);
1270
1271                // If found cache the full name in the BshClassManager
1272
if ( clas != null ) {
1273                    // (should we cache info in not a class case too?)
1274
getClassManager().cacheClassInfo( fullname, clas );
1275                    return clas;
1276                }
1277            } else
1278                return clas;
1279
1280            // It was explicitly imported, but we don't know what it is.
1281
// should we throw an error here??
1282
return null;
1283        }
1284
1285        /*
1286            Try imported packages, e.g. "import foo.bar.*;"
1287            in reverse order of import...
1288            (give later imports precedence...)
1289        */

1290        if ( importedPackages != null )
1291            for(int i=importedPackages.size()-1; i>=0; i--)
1292            {
1293                String JavaDoc s = ((String JavaDoc)importedPackages.elementAt(i)) + "." + name;
1294                Class JavaDoc c=classForName(s);
1295                if ( c != null )
1296                    return c;
1297            }
1298
1299        BshClassManager bcm = getClassManager();
1300        /*
1301            Try super import if available
1302            Note: we do this last to allow explicitly imported classes
1303            and packages to take priority. This method will also throw an
1304            error indicating ambiguity if it exists...
1305        */

1306        if ( bcm.hasSuperImport() )
1307        {
1308            String JavaDoc s = bcm.getClassNameByUnqName( name );
1309            if ( s != null )
1310                return classForName( s );
1311        }
1312
1313        return null;
1314    }
1315
1316    private Class JavaDoc classForName( String JavaDoc name )
1317    {
1318        return getClassManager().classForName( name );
1319    }
1320
1321    /**
1322        Implements NameSource
1323        @return all variable and method names in this and all parent
1324        namespaces
1325    */

1326    public String JavaDoc [] getAllNames()
1327    {
1328        Vector vec = new Vector();
1329        getAllNamesAux( vec );
1330        String JavaDoc [] names = new String JavaDoc [ vec.size() ];
1331        vec.copyInto( names );
1332        return names;
1333    }
1334
1335    /**
1336        Helper for implementing NameSource
1337    */

1338    protected void getAllNamesAux( Vector vec )
1339    {
1340        Enumeration varNames = variables.keys();
1341        while( varNames.hasMoreElements() )
1342            vec.addElement( varNames.nextElement() );
1343
1344        Enumeration methodNames = methods.keys();
1345        while( methodNames.hasMoreElements() )
1346            vec.addElement( methodNames.nextElement() );
1347
1348        if ( parent != null )
1349            parent.getAllNamesAux( vec );
1350    }
1351
1352    Vector nameSourceListeners;
1353    /**
1354        Implements NameSource
1355        Add a listener who is notified upon changes to names in this space.
1356    */

1357    public void addNameSourceListener( NameSource.Listener listener ) {
1358        if ( nameSourceListeners == null )
1359            nameSourceListeners = new Vector();
1360        nameSourceListeners.addElement( listener );
1361    }
1362
1363    /**
1364        Perform "import *;" causing the entire classpath to be mapped.
1365        This can take a while.
1366    */

1367    public void doSuperImport()
1368        throws UtilEvalError
1369    {
1370        getClassManager().doSuperImport();
1371    }
1372
1373
1374    public String JavaDoc toString() {
1375        return "NameSpace: "
1376            + ( nsName==null
1377                ? super.toString()
1378                : nsName + " (" + super.toString() +")" )
1379            + ( isClass ? " (isClass) " : "" )
1380            + ( isMethod ? " (method) " : "" )
1381            + ( classStatic != null ? " (class static) " : "" )
1382            + ( classInstance != null ? " (class instance) " : "" );
1383    }
1384
1385    /*
1386        For serialization.
1387        Don't serialize non-serializable objects.
1388    */

1389    private synchronized void writeObject(java.io.ObjectOutputStream JavaDoc s)
1390        throws IOException JavaDoc
1391    {
1392        // clear name resolvers... don't know if this is necessary.
1393
names = null;
1394
1395        s.defaultWriteObject();
1396    }
1397
1398    /**
1399        Invoke a method in this namespace with the specified args and
1400        interpreter reference. No caller information or call stack is
1401        required. The method will appear as if called externally from Java.
1402        <p>
1403
1404        @see bsh.This.invokeMethod(
1405            String methodName, Object [] args, Interpreter interpreter,
1406            CallStack callstack, SimpleNode callerInfo, boolean )
1407    */

1408    public Object JavaDoc invokeMethod(
1409        String JavaDoc methodName, Object JavaDoc [] args, Interpreter interpreter )
1410        throws EvalError
1411    {
1412        return invokeMethod(
1413            methodName, args, interpreter, null, null );
1414    }
1415
1416    /**
1417        This method simply delegates to This.invokeMethod();
1418        <p>
1419        @see bsh.This.invokeMethod(
1420            String methodName, Object [] args, Interpreter interpreter,
1421            CallStack callstack, SimpleNode callerInfo )
1422    */

1423    public Object JavaDoc invokeMethod(
1424        String JavaDoc methodName, Object JavaDoc [] args, Interpreter interpreter,
1425        CallStack callstack, SimpleNode callerInfo )
1426        throws EvalError
1427    {
1428        return getThis( interpreter ).invokeMethod(
1429            methodName, args, interpreter, callstack, callerInfo,
1430            false/*declaredOnly*/ );
1431    }
1432
1433    /**
1434        Clear all cached classes and names
1435    */

1436    public void classLoaderChanged() {
1437        nameSpaceChanged();
1438    }
1439
1440    /**
1441        Clear all cached classes and names
1442    */

1443    public void nameSpaceChanged() {
1444        classCache = null;
1445        names = null;
1446    }
1447
1448    /**
1449        Import standard packages. Currently:
1450        <pre>
1451            importClass("bsh.EvalError");
1452            importClass("bsh.Interpreter");
1453            importPackage("javax.swing.event");
1454            importPackage("javax.swing");
1455            importPackage("java.awt.event");
1456            importPackage("java.awt");
1457            importPackage("java.net");
1458            importPackage("java.util");
1459            importPackage("java.io");
1460            importPackage("java.lang");
1461            addCommandPath("/bsh/commands",getClass());
1462        </pre>
1463    */

1464    public void loadDefaultImports()
1465    {
1466        /**
1467            Note: the resolver looks through these in reverse order, per
1468            precedence rules... so for max efficiency put the most common
1469            ones later.
1470        */

1471        importClass("bsh.EvalError");
1472        importClass("bsh.Interpreter");
1473        importPackage("javax.swing.event");
1474        importPackage("javax.swing");
1475        importPackage("java.awt.event");
1476        importPackage("java.awt");
1477        importPackage("java.net");
1478        importPackage("java.util");
1479        importPackage("java.io");
1480        importPackage("java.lang");
1481            // {{{ jEdit modification
1482
//importCommands("/bsh/commands");
1483
addCommandPath("/bsh/commands",getClass());
1484         // }}}
1485
}
1486
1487    /**
1488        This is the factory for Name objects which resolve names within
1489        this namespace (e.g. toObject(), toClass(), toLHS()).
1490        <p>
1491
1492        This was intended to support name resolver caching, allowing
1493        Name objects to cache info about the resolution of names for
1494        performance reasons. However this not proven useful yet.
1495        <p>
1496
1497        We'll leave the caching as it will at least minimize Name object
1498        creation.
1499        <p>
1500
1501        (This method would be called getName() if it weren't already used for
1502        the simple name of the NameSpace)
1503        <p>
1504
1505        This method was public for a time, which was a mistake.
1506        Use get() instead.
1507    */

1508    Name getNameResolver( String JavaDoc ambigname )
1509    {
1510        if ( names == null )
1511            names = new Hashtable();
1512
1513        Name name = (Name)names.get( ambigname );
1514
1515        if ( name == null ) {
1516            name = new Name( this, ambigname );
1517            names.put( ambigname, name );
1518        }
1519
1520        return name;
1521    }
1522
1523    public int getInvocationLine() {
1524        SimpleNode node = getNode();
1525        if ( node != null )
1526            return node.getLineNumber();
1527        else
1528            return -1;
1529    }
1530    public String JavaDoc getInvocationText() {
1531        SimpleNode node = getNode();
1532        if ( node != null )
1533            return node.getText();
1534        else
1535            return "<invoked from Java code>";
1536    }
1537
1538    /**
1539        This is a helper method for working inside of bsh scripts and commands.
1540        In that context it is impossible to see a ClassIdentifier object
1541        for what it is. Attempting to access a method on a ClassIdentifier
1542        will look like a static method invocation.
1543
1544        This method is in NameSpace for convenience (you don't have to import
1545        bsh.ClassIdentifier to use it );
1546    */

1547    public static Class JavaDoc identifierToClass( ClassIdentifier ci )
1548    {
1549        return ci.getTargetClass();
1550    }
1551
1552
1553    /**
1554        Clear all variables, methods, and imports from this namespace.
1555        If this namespace is the root, it will be reset to the default
1556        imports.
1557        @see #loadDefaultImports()
1558    */

1559    public void clear()
1560    {
1561        variables = null;
1562        methods = null;
1563        importedClasses = null;
1564        importedPackages = null;
1565        importedCommands = null;
1566        importedObjects = null;
1567        if ( parent == null )
1568            loadDefaultImports();
1569        classCache = null;
1570        names = null;
1571    }
1572
1573    /**
1574        Import a compiled Java object's methods and variables into this
1575        namespace. When no scripted method / command or variable is found
1576        locally in this namespace method / fields of the object will be
1577        checked. Objects are checked in the order of import with later imports
1578        taking precedence.
1579        <p/>
1580    */

1581    /*
1582        Note: this impor pattern is becoming common... could factor it out into
1583        an importedObject Vector class.
1584    */

1585    public void importObject( Object JavaDoc obj )
1586    {
1587        if ( importedObjects == null )
1588            importedObjects = new Vector();
1589
1590        // If it exists, remove it and add it at the end (avoid memory leak)
1591
if ( importedObjects.contains( obj ) )
1592            importedObjects.remove( obj );
1593
1594        importedObjects.addElement( obj );
1595        nameSpaceChanged();
1596
1597    }
1598
1599    /**
1600    */

1601    public void importStatic( Class JavaDoc clas )
1602    {
1603        if ( importedStatic == null )
1604            importedStatic = new Vector();
1605
1606        // If it exists, remove it and add it at the end (avoid memory leak)
1607
if ( importedStatic.contains( clas ) )
1608            importedStatic.remove( clas );
1609
1610        importedStatic.addElement( clas );
1611        nameSpaceChanged();
1612    }
1613
1614    /**
1615        Set the package name for classes defined in this namespace.
1616        Subsequent sets override the package.
1617    */

1618    void setPackage( String JavaDoc packageName )
1619    {
1620        this.packageName = packageName;
1621    }
1622
1623    String JavaDoc getPackage()
1624    {
1625        if ( packageName != null )
1626            return packageName;
1627
1628        if ( parent != null )
1629            return parent.getPackage();
1630
1631        return null;
1632    }
1633
1634    // {{{ jEdit addition
1635
public void setVariable(String JavaDoc name, Object JavaDoc value) throws UtilEvalError
1636        {
1637                setVariable(name,value,false);
1638        }
1639
1640    /**
1641        Adds a URL to the command path.
1642    */

1643    public void addCommandPath(String JavaDoc path, Class JavaDoc clas)
1644    {
1645        if(importedCommands == null)
1646            importedCommands = new Vector();
1647
1648        if(!path.endsWith("/"))
1649            path += '/';
1650        importedCommands.addElement(new CommandPathEntry(path,clas));
1651    }
1652
1653    /**
1654        Remove a URLfrom the command path.
1655    */

1656    public void removeCommandPath(String JavaDoc path, Class JavaDoc clas)
1657    {
1658        if(importedCommands == null)
1659            return;
1660
1661        for(int i = 0; i < importedCommands.size(); i++)
1662        {
1663            CommandPathEntry entry = (CommandPathEntry)importedCommands
1664                .elementAt(i);
1665            if(entry.path.equals(path) && entry.clas == clas)
1666            {
1667                importedCommands.removeElementAt(i);
1668                return;
1669            }
1670        }
1671    }
1672
1673    /**
1674        Looks up a command.
1675    */

1676    public InputStream JavaDoc getCommand(String JavaDoc name)
1677    {
1678        if(importedCommands != null)
1679        {
1680            String JavaDoc extName = name + ".bsh";
1681            for(int i = importedCommands.size() - 1; i >= 0; i--)
1682            {
1683                CommandPathEntry entry = (CommandPathEntry)importedCommands
1684                    .elementAt(i);
1685                InputStream JavaDoc in = entry.clas.getResourceAsStream(entry.path + extName);
1686                if(in != null)
1687                    return in;
1688            }
1689        }
1690
1691        if(parent == null)
1692            return null;
1693        else
1694            return parent.getCommand(name);
1695    }
1696
1697    static class CommandPathEntry
1698    {
1699        final String JavaDoc path;
1700        final Class JavaDoc clas;
1701
1702        CommandPathEntry(String JavaDoc path, Class JavaDoc clas)
1703        {
1704            this.path = path;
1705            this.clas = clas;
1706        }
1707    }
1708
1709    // }}}
1710
}
1711
1712
Popular Tags