KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > bsh > classpath > BshClassPath


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 package bsh.classpath;
35
36 import java.util.*;
37 import java.util.zip.*;
38 import java.io.*;
39 import java.net.*;
40 import java.io.File JavaDoc;
41 import bsh.ConsoleInterface;
42 import bsh.StringUtil;
43 import bsh.ClassPathException;
44 import java.lang.ref.WeakReference JavaDoc;
45 import bsh.NameSource;
46
47 /**
48     A BshClassPath encapsulates knowledge about a class path of URLs.
49     It can maps all classes the path which may include:
50         jar/zip files and base dirs
51
52     A BshClassPath may composite other BshClassPaths as components of its
53     path and will reflect changes in those components through its methods
54     and listener interface.
55
56     Classpath traversal is done lazily when a call is made to
57         getClassesForPackage() or getClassSource()
58     or can be done explicitily through insureInitialized().
59     Feedback on mapping progress is provided through the MappingFeedback
60     interface.
61
62     Design notes:
63     Several times here we traverse ourselves and our component paths to
64     produce a composite view of some thing relating to the path. This would
65     be an opportunity for a visitor pattern.
66 */

67 public class BshClassPath
68     implements ClassPathListener, NameSource
69 {
70     String JavaDoc name;
71
72     /** The URL path components */
73     private List path;
74     /** Ordered list of components BshClassPaths */
75     private List compPaths;
76
77     /** Set of classes in a package mapped by package name */
78     private Map packageMap;
79     /** Map of source (URL or File dir) of every clas */
80     private Map classSource;
81     /** The packageMap and classSource maps have been built. */
82     private boolean mapsInitialized;
83
84     private UnqualifiedNameTable unqNameTable;
85
86     /**
87         This used to be configurable, but now we always include them.
88     */

89     private boolean nameCompletionIncludesUnqNames = true;
90
91     Vector listeners = new Vector();
92
93     // constructors
94

95     public BshClassPath( String JavaDoc name ) {
96         this.name = name;
97         reset();
98     }
99
100     public BshClassPath( String JavaDoc name, URL [] urls ) {
101         this( name );
102         add( urls );
103     }
104
105     // end constructors
106

107     // mutators
108

109     public void setPath( URL[] urls ) {
110         reset();
111         add( urls );
112     }
113
114     /**
115         Add the specified BshClassPath as a component of our path.
116         Changes in the bcp will be reflected through us.
117     */

118     public void addComponent( BshClassPath bcp ) {
119         if ( compPaths == null )
120             compPaths = new ArrayList();
121         compPaths.add( bcp );
122         bcp.addListener( this );
123     }
124
125     public void add( URL [] urls ) {
126         path.addAll( Arrays.asList(urls) );
127         if ( mapsInitialized )
128             map( urls );
129     }
130
131     public void add( URL url ) throws IOException {
132         path.add(url);
133         if ( mapsInitialized )
134             map( url );
135     }
136
137     /**
138         Get the path components including any component paths.
139     */

140     public URL [] getPathComponents() {
141         return (URL[])getFullPath().toArray( new URL[0] );
142     }
143
144     /**
145         Return the set of class names in the specified package
146         including all component paths.
147     */

148     synchronized public Set getClassesForPackage( String JavaDoc pack ) {
149         insureInitialized();
150         Set set = new HashSet();
151         Collection c = (Collection)packageMap.get( pack );
152         if ( c != null )
153             set.addAll( c );
154
155         if ( compPaths != null )
156             for (int i=0; i<compPaths.size(); i++) {
157                 c = ((BshClassPath)compPaths.get(i)).getClassesForPackage(
158                     pack );
159                 if ( c != null )
160                     set.addAll( c );
161             }
162         return set;
163     }
164
165     /**
166         Return the source of the specified class which may lie in component
167         path.
168     */

169     synchronized public ClassSource getClassSource( String JavaDoc className )
170     {
171         // Before triggering classpath mapping (initialization) check for
172
// explicitly set class sources (e.g. generated classes). These would
173
// take priority over any found in the classpath anyway.
174
ClassSource cs = (ClassSource)classSource.get( className );
175         if ( cs != null )
176             return cs;
177
178         insureInitialized(); // trigger possible mapping
179

180         cs = (ClassSource)classSource.get( className );
181         if ( cs == null && compPaths != null )
182             for (int i=0; i<compPaths.size() && cs==null; i++)
183                 cs = ((BshClassPath)compPaths.get(i)).getClassSource(className);
184         return cs;
185     }
186
187     /**
188         Explicitly set a class source. This is used for generated classes, but
189         could potentially be used to allow a user to override which version of
190         a class from the classpath is located.
191     */

192     synchronized public void setClassSource( String JavaDoc className, ClassSource cs )
193     {
194         classSource.put( className, cs );
195     }
196
197     /**
198         If the claspath map is not initialized, do it now.
199         If component maps are not do them as well...
200
201         Random note:
202         Should this be "insure" or "ensure". I know I've seen "ensure" used
203         in the JDK source. Here's what Webster has to say:
204
205             Main Entry:ensure Pronunciation:in-'shur
206             Function:transitive verb Inflected
207             Form(s):ensured; ensuring : to make sure,
208             certain, or safe : GUARANTEE synonyms ENSURE,
209             INSURE, ASSURE, SECURE mean to make a thing or
210             person sure. ENSURE, INSURE, and ASSURE are
211             interchangeable in many contexts where they
212             indicate the making certain or inevitable of an
213             outcome, but INSURE sometimes stresses the
214             taking of necessary measures beforehand, and
215             ASSURE distinctively implies the removal of
216             doubt and suspense from a person's mind. SECURE
217             implies action taken to guard against attack or
218             loss.
219     */

220     public void insureInitialized()
221     {
222         insureInitialized( true );
223     }
224
225     /**
226         @param topPath indicates that this is the top level classpath
227         component and it should send the startClassMapping message
228     */

229     protected synchronized void insureInitialized( boolean topPath )
230     {
231         // If we are the top path and haven't been initialized before
232
// inform the listeners we are going to do expensive map
233
if ( topPath && !mapsInitialized )
234             startClassMapping();
235
236         // initialize components
237
if ( compPaths != null )
238             for (int i=0; i< compPaths.size(); i++)
239                 ((BshClassPath)compPaths.get(i)).insureInitialized( false );
240
241         // initialize ourself
242
if ( !mapsInitialized )
243             map( (URL[])path.toArray( new URL[0] ) );
244
245         if ( topPath && !mapsInitialized )
246             endClassMapping();
247
248         mapsInitialized = true;
249     }
250
251     /**
252         Get the full path including component paths.
253         (component paths listed first, in order)
254         Duplicate path components are removed.
255     */

256     protected List getFullPath()
257     {
258         List list = new ArrayList();
259         if ( compPaths != null ) {
260             for (int i=0; i<compPaths.size(); i++) {
261                 List l = ((BshClassPath)compPaths.get(i)).getFullPath();
262                 // take care to remove dups
263
// wish we had an ordered set collection
264
Iterator it = l.iterator();
265                 while ( it.hasNext() ) {
266                     Object JavaDoc o = it.next();
267                     if ( !list.contains(o) )
268                         list.add( o );
269                 }
270             }
271         }
272         list.addAll( path );
273         return list;
274     }
275
276
277     /**
278         Support for super import "*";
279         Get the full name associated with the unqualified name in this
280         classpath. Returns either the String name or an AmbiguousName object
281         encapsulating the various names.
282     */

283     public String JavaDoc getClassNameByUnqName( String JavaDoc name )
284         throws ClassPathException
285     {
286         insureInitialized();
287         UnqualifiedNameTable unqNameTable = getUnqualifiedNameTable();
288
289         Object JavaDoc obj = unqNameTable.get( name );
290         if ( obj instanceof AmbiguousName )
291             throw new ClassPathException("Ambigous class names: "+
292                 ((AmbiguousName)obj).get() );
293
294         return (String JavaDoc)obj;
295     }
296
297     /*
298         Note: we could probably do away with the unqualified name table
299         in favor of a second name source
300     */

301     private UnqualifiedNameTable getUnqualifiedNameTable() {
302         if ( unqNameTable == null )
303             unqNameTable = buildUnqualifiedNameTable();
304         return unqNameTable;
305     }
306
307     private UnqualifiedNameTable buildUnqualifiedNameTable()
308     {
309         UnqualifiedNameTable unqNameTable = new UnqualifiedNameTable();
310
311         // add component names
312
if ( compPaths != null )
313             for (int i=0; i<compPaths.size(); i++) {
314                 Set s = ((BshClassPath)compPaths.get(i)).classSource.keySet();
315                 Iterator it = s.iterator();
316                 while(it.hasNext())
317                     unqNameTable.add( (String JavaDoc)it.next() );
318             }
319
320         // add ours
321
Iterator it = classSource.keySet().iterator();
322         while(it.hasNext())
323             unqNameTable.add( (String JavaDoc)it.next() );
324         
325         return unqNameTable;
326     }
327
328     public String JavaDoc [] getAllNames()
329     {
330         insureInitialized();
331
332         List names = new ArrayList();
333         Iterator it = getPackagesSet().iterator();
334         while( it.hasNext() ) {
335             String JavaDoc pack = (String JavaDoc)it.next();
336             names.addAll(
337                 removeInnerClassNames( getClassesForPackage( pack ) ) );
338         }
339
340         if ( nameCompletionIncludesUnqNames )
341             names.addAll( getUnqualifiedNameTable().keySet() );
342
343         return (String JavaDoc [])names.toArray(new String JavaDoc[0]);
344     }
345
346     /**
347         call map(url) for each url in the array
348     */

349     synchronized void map( URL [] urls )
350     {
351         for(int i=0; i< urls.length; i++)
352             try{
353                 map( urls[i] );
354             } catch ( IOException e ) {
355                 String JavaDoc s = "Error constructing classpath: " +urls[i]+": "+e;
356                 errorWhileMapping( s );
357             }
358     }
359
360     synchronized void map( URL url )
361         throws IOException
362     {
363         String JavaDoc name = url.getFile();
364         File JavaDoc f = new File JavaDoc( name );
365
366         if ( f.isDirectory() ) {
367             classMapping( "Directory "+ f.toString() );
368             map( traverseDirForClasses( f ), new DirClassSource(f) );
369         } else if ( isArchiveFileName( name ) ) {
370             classMapping("Archive: "+url );
371             map( searchJarForClasses( url ), new JarClassSource(url) );
372         }
373         /*
374         else if ( isClassFileName( name ) )
375             map( looseClass( name ), url );
376         */

377         else {
378             String JavaDoc s = "Not a classpath component: "+ name ;
379             errorWhileMapping( s );
380         }
381     }
382
383     private void map( String JavaDoc [] classes, Object JavaDoc source ) {
384         for(int i=0; i< classes.length; i++) {
385             //System.out.println( classes[i] +": "+ source );
386
mapClass( classes[i], source );
387         }
388     }
389
390     private void mapClass( String JavaDoc className, Object JavaDoc source )
391     {
392         // add to package map
393
String JavaDoc [] sa = splitClassname( className );
394         String JavaDoc pack = sa[0];
395         String JavaDoc clas = sa[1];
396         Set set = (Set)packageMap.get( pack );
397         if ( set == null ) {
398             set = new HashSet();
399             packageMap.put( pack, set );
400         }
401         set.add( className );
402
403         // Add to classSource map
404
Object JavaDoc obj = classSource.get( className );
405         // don't replace previously set (found earlier in classpath or
406
// explicitly set via setClassSource() )
407
if ( obj == null )
408             classSource.put( className, source );
409     }
410
411     /**
412         Clear everything and reset the path to empty.
413     */

414     synchronized private void reset() {
415         path = new ArrayList();
416         compPaths = null;
417         clearCachedStructures();
418     }
419
420     /**
421         Clear anything cached. All will be reconstructed as necessary.
422     */

423     synchronized private void clearCachedStructures() {
424         mapsInitialized = false;
425         packageMap = new HashMap();
426         classSource = new HashMap();
427         unqNameTable = null;
428         nameSpaceChanged();
429     }
430
431     public void classPathChanged() {
432         clearCachedStructures();
433         notifyListeners();
434     }
435
436 /*
437     public void setNameCompletionIncludeUnqNames( boolean b ) {
438         if ( nameCompletionIncludesUnqNames != b ) {
439             nameCompletionIncludesUnqNames = b;
440             nameSpaceChanged();
441         }
442     }
443 */

444
445     // Begin Static stuff
446

447     static String JavaDoc [] traverseDirForClasses( File JavaDoc dir )
448         throws IOException
449     {
450         List list = traverseDirForClassesAux( dir, dir );
451         return (String JavaDoc[])list.toArray( new String JavaDoc[0] );
452     }
453
454     static List traverseDirForClassesAux( File JavaDoc topDir, File JavaDoc dir )
455         throws IOException
456     {
457         List list = new ArrayList();
458         String JavaDoc top = topDir.getAbsolutePath();
459
460         File JavaDoc [] children = dir.listFiles();
461         for (int i=0; i< children.length; i++) {
462             File JavaDoc child = children[i];
463             if ( child.isDirectory() )
464                 list.addAll( traverseDirForClassesAux( topDir, child ) );
465             else {
466                 String JavaDoc name = child.getAbsolutePath();
467                 if ( isClassFileName( name ) ) {
468                     /*
469                         Remove absolute (topdir) portion of path and leave
470                         package-class part
471                     */

472                     if ( name.startsWith( top ) )
473                         name = name.substring( top.length()+1 );
474                     else
475                         throw new IOException( "problem parsing paths" );
476
477                     name = canonicalizeClassName(name);
478                     list.add( name );
479                 }
480             }
481         }
482         
483         
484         return list;
485     }
486
487     /**
488         Get the class file entries from the Jar
489     */

490     static String JavaDoc [] searchJarForClasses( URL jar )
491         throws IOException
492     {
493         Vector v = new Vector();
494         InputStream in = jar.openStream();
495         ZipInputStream zin = new ZipInputStream(in);
496
497         ZipEntry ze;
498         while( (ze= zin.getNextEntry()) != null ) {
499             String JavaDoc name=ze.getName();
500             if ( isClassFileName( name ) )
501                 v.addElement( canonicalizeClassName(name) );
502         }
503         zin.close();
504
505         String JavaDoc [] sa = new String JavaDoc [v.size()];
506         v.copyInto(sa);
507         return sa;
508     }
509
510     public static boolean isClassFileName( String JavaDoc name ){
511         return ( name.toLowerCase().endsWith(".class") );
512             //&& (name.indexOf('$')==-1) );
513
}
514
515     public static boolean isArchiveFileName( String JavaDoc name ){
516         name = name.toLowerCase();
517         return ( name.endsWith(".jar") || name.endsWith(".zip") );
518     }
519
520     /**
521         Create a proper class name from a messy thing.
522         Turn / or \ into ., remove leading class and trailing .class
523
524         Note: this makes lots of strings... could be faster.
525     */

526     public static String JavaDoc canonicalizeClassName( String JavaDoc name )
527     {
528         String JavaDoc classname=name.replace('/', '.');
529         classname=classname.replace('\\', '.');
530         if ( classname.startsWith("class ") )
531             classname=classname.substring(6);
532         if ( classname.endsWith(".class") )
533             classname=classname.substring(0,classname.length()-6);
534         return classname;
535     }
536
537     /**
538         Split class name into package and name
539     */

540     public static String JavaDoc [] splitClassname ( String JavaDoc classname ) {
541         classname = canonicalizeClassName( classname );
542
543         int i=classname.lastIndexOf(".");
544         String JavaDoc classn, packn;
545         if ( i == -1 ) {
546             // top level class
547
classn = classname;
548             packn="<unpackaged>";
549         } else {
550             packn = classname.substring(0,i);
551             classn = classname.substring(i+1);
552         }
553         return new String JavaDoc [] { packn, classn };
554     }
555
556     /**
557         Return a new collection without any inner class names
558     */

559     public static Collection removeInnerClassNames( Collection col ) {
560         List list = new ArrayList();
561         list.addAll(col);
562         Iterator it = list.iterator();
563         while(it.hasNext()) {
564             String JavaDoc name =(String JavaDoc)it.next();
565             if (name.indexOf("$") != -1 )
566                 it.remove();
567         }
568         return list;
569     }
570     
571     /**
572         The user classpath from system property
573             java.class.path
574     */

575
576     static URL [] userClassPathComp;
577     public static URL [] getUserClassPathComponents()
578         throws ClassPathException
579     {
580         if ( userClassPathComp != null )
581             return userClassPathComp;
582
583         String JavaDoc cp=System.getProperty("java.class.path");
584         String JavaDoc [] paths=StringUtil.split(cp, File.pathSeparator);
585
586         URL [] urls = new URL[ paths.length ];
587         try {
588             for ( int i=0; i<paths.length; i++)
589                 // We take care to get the canonical path first.
590
// Java deals with relative paths for it's bootstrap loader
591
// but JARClassLoader doesn't.
592
urls[i] = new File JavaDoc(
593                     new File JavaDoc(paths[i]).getCanonicalPath() ).toURL();
594         } catch ( IOException e ) {
595             throw new ClassPathException("can't parse class path: "+e);
596         }
597
598         userClassPathComp = urls;
599         return urls;
600     }
601
602     /**
603         Get a list of all of the known packages
604     */

605     public Set getPackagesSet()
606     {
607         insureInitialized();
608         Set set = new HashSet();
609         set.addAll( packageMap.keySet() );
610
611         if ( compPaths != null )
612             for (int i=0; i<compPaths.size(); i++)
613                 set.addAll(
614                     ((BshClassPath)compPaths.get(i)).packageMap.keySet() );
615         return set;
616     }
617
618     public void addListener( ClassPathListener l ) {
619         listeners.addElement( new WeakReference JavaDoc(l) );
620     }
621     public void removeListener( ClassPathListener l ) {
622         listeners.removeElement( l );
623     }
624
625     /**
626     */

627     void notifyListeners() {
628         for (Enumeration e = listeners.elements(); e.hasMoreElements(); ) {
629             WeakReference JavaDoc wr = (WeakReference JavaDoc)e.nextElement();
630             ClassPathListener l = (ClassPathListener)wr.get();
631             if ( l == null ) // garbage collected
632
listeners.removeElement( wr );
633             else
634                 l.classPathChanged();
635         }
636     }
637
638     static BshClassPath userClassPath;
639     /**
640         A BshClassPath initialized to the user path
641         from java.class.path
642     */

643     public static BshClassPath getUserClassPath()
644         throws ClassPathException
645     {
646         if ( userClassPath == null )
647             userClassPath = new BshClassPath(
648                 "User Class Path", getUserClassPathComponents() );
649         return userClassPath;
650     }
651
652     static BshClassPath bootClassPath;
653     /**
654         Get the boot path including the lib/rt.jar if possible.
655     */

656     public static BshClassPath getBootClassPath()
657         throws ClassPathException
658     {
659         if ( bootClassPath == null )
660         {
661             try
662             {
663                 //String rtjar = System.getProperty("java.home")+"/lib/rt.jar";
664
String JavaDoc rtjar = getRTJarPath();
665                 URL url = new File JavaDoc( rtjar ).toURL();
666                 bootClassPath = new BshClassPath(
667                     "Boot Class Path", new URL[] { url } );
668             } catch ( MalformedURLException e ) {
669                 throw new ClassPathException(" can't find boot jar: "+e);
670             }
671         }
672         return bootClassPath;
673     }
674
675
676     private static String JavaDoc getRTJarPath()
677     {
678         String JavaDoc urlString =
679             Class JavaDoc.class.getResource("/java/lang/String.class").toExternalForm();
680
681         if ( !urlString.startsWith("jar:file:") )
682             return null;
683
684         int i = urlString.indexOf("!");
685         if ( i == -1 )
686             return null;
687
688         return urlString.substring( "jar:file:".length(), i );
689     }
690
691     public abstract static class ClassSource {
692         Object JavaDoc source;
693         abstract byte [] getCode( String JavaDoc className );
694     }
695
696     public static class JarClassSource extends ClassSource {
697         JarClassSource( URL url ) { source = url; }
698         public URL getURL() { return (URL)source; }
699         /*
700             Note: we should implement this for consistency, however our
701             BshClassLoader can natively load from a JAR because it is a
702             URLClassLoader... so it may be better to allow it to do it.
703         */

704         public byte [] getCode( String JavaDoc className ) {
705             throw new Error JavaDoc("Unimplemented");
706         }
707         public String JavaDoc toString() { return "Jar: "+source; }
708     }
709
710     public static class DirClassSource extends ClassSource
711     {
712         DirClassSource( File JavaDoc dir ) { source = dir; }
713         public File JavaDoc getDir() { return (File JavaDoc)source; }
714         public String JavaDoc toString() { return "Dir: "+source; }
715
716         public byte [] getCode( String JavaDoc className ) {
717             return readBytesFromFile( getDir(), className );
718         }
719
720         public static byte [] readBytesFromFile( File JavaDoc base, String JavaDoc className )
721         {
722             String JavaDoc n = className.replace( '.', File.separatorChar ) + ".class";
723             File JavaDoc file = new File JavaDoc( base, n );
724
725             if ( file == null || !file.exists() )
726                 return null;
727
728             byte [] bytes;
729             try {
730                 FileInputStream fis = new FileInputStream(file);
731                 DataInputStream dis = new DataInputStream( fis );
732          
733                 bytes = new byte [ (int)file.length() ];
734
735                 dis.readFully( bytes );
736                 dis.close();
737             } catch(IOException ie ) {
738                 throw new RuntimeException JavaDoc("Couldn't load file: "+file);
739             }
740
741             return bytes;
742         }
743
744     }
745
746     public static class GeneratedClassSource extends ClassSource
747     {
748         GeneratedClassSource( byte [] bytecode ) { source = bytecode; }
749         public byte [] getCode( String JavaDoc className ) {
750             return (byte [])source;
751         }
752     }
753
754     public static void main( String JavaDoc [] args ) throws Exception JavaDoc {
755         URL [] urls = new URL [ args.length ];
756         for(int i=0; i< args.length; i++)
757             urls[i] = new File JavaDoc(args[i]).toURL();
758         BshClassPath bcp = new BshClassPath( "Test", urls );
759     }
760
761     public String JavaDoc toString() {
762         return "BshClassPath "+name+"("+super.toString()+") path= "+path +"\n"
763             + "compPaths = {" + compPaths +" }";
764     }
765
766
767     /*
768         Note: we could probably do away with the unqualified name table
769         in favor of a second name source
770     */

771     static class UnqualifiedNameTable extends HashMap {
772         void add( String JavaDoc fullname ) {
773             String JavaDoc name = splitClassname( fullname )[1];
774             Object JavaDoc have = super.get( name );
775
776             if ( have == null )
777                 super.put( name, fullname );
778             else
779                 if ( have instanceof AmbiguousName )
780                     ((AmbiguousName)have).add( fullname );
781                 else // String
782
{
783                     AmbiguousName an = new AmbiguousName();
784                     an.add( (String JavaDoc)have );
785                     an.add( fullname );
786                     super.put( name, an );
787                 }
788         }
789     }
790
791     public static class AmbiguousName {
792         List list = new ArrayList();
793         public void add( String JavaDoc name ) {
794             list.add( name );
795         }
796         public List get() {
797             //return (String[])list.toArray(new String[0]);
798
return list;
799         }
800     }
801
802     /**
803         Fire the NameSourceListeners
804     */

805     void nameSpaceChanged()
806     {
807         if ( nameSourceListeners == null )
808             return;
809
810         for(int i=0; i<nameSourceListeners.size(); i++)
811             ((NameSource.Listener)(nameSourceListeners.get(i)))
812                 .nameSourceChanged( this );
813     }
814
815     List nameSourceListeners;
816     /**
817         Implements NameSource
818         Add a listener who is notified upon changes to names in this space.
819     */

820     public void addNameSourceListener( NameSource.Listener listener ) {
821         if ( nameSourceListeners == null )
822             nameSourceListeners = new ArrayList();
823         nameSourceListeners.add( listener );
824     }
825
826     /** only allow one for now */
827     static MappingFeedback mappingFeedbackListener;
828
829     /**
830     */

831     public static void addMappingFeedback( MappingFeedback mf )
832     {
833         if ( mappingFeedbackListener != null )
834             throw new RuntimeException JavaDoc("Unimplemented: already a listener");
835         mappingFeedbackListener = mf;
836     }
837
838     void startClassMapping() {
839         if ( mappingFeedbackListener != null )
840             mappingFeedbackListener.startClassMapping();
841         else
842             System.err.println( "Start ClassPath Mapping" );
843     }
844
845     void classMapping( String JavaDoc msg ) {
846         if ( mappingFeedbackListener != null ) {
847             mappingFeedbackListener.classMapping( msg );
848         } else
849             System.err.println( "Mapping: "+msg );
850     }
851
852     void errorWhileMapping( String JavaDoc s ) {
853         if ( mappingFeedbackListener != null )
854             mappingFeedbackListener.errorWhileMapping( s );
855         else
856             System.err.println( s );
857     }
858
859     void endClassMapping() {
860         if ( mappingFeedbackListener != null )
861             mappingFeedbackListener.endClassMapping();
862         else
863             System.err.println( "End ClassPath Mapping" );
864     }
865     
866     public static interface MappingFeedback
867     {
868         public void startClassMapping();
869
870         /**
871             Provide feedback on the progress of mapping the classpath
872             @param msg is a message about the path component being mapped
873             @perc is an integer in the range 0-100 indicating percentage done
874         public void classMapping( String msg, int perc );
875         */

876
877         /**
878             Provide feedback on the progress of mapping the classpath
879         */

880         public void classMapping( String JavaDoc msg );
881
882         public void errorWhileMapping( String JavaDoc msg );
883
884         public void endClassMapping();
885     }
886
887 }
888
Popular Tags