KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > caucho > loader > CompilingLoader


1 /*
2  * Copyright (c) 1998-2006 Caucho Technology -- all rights reserved
3  *
4  * This file is part of Resin(R) Open Source
5  *
6  * Each copy or derived work must preserve the copyright notice and this
7  * notice unmodified.
8  *
9  * Resin Open Source is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * Resin Open Source is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty
17  * of NON-INFRINGEMENT. See the GNU General Public License for more
18  * details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with Resin Open Source; if not, write to the
22  * Free SoftwareFoundation, Inc.
23  * 59 Temple Place, Suite 330
24  * Boston, MA 02111-1307 USA
25  *
26  * @author Scott Ferguson
27  */

28
29 package com.caucho.loader;
30
31 import com.caucho.config.ConfigException;
32 import com.caucho.java.CompileClassNotFound;
33 import com.caucho.java.JavaCompiler;
34 import com.caucho.log.Log;
35 import com.caucho.make.AlwaysModified;
36 import com.caucho.make.Make;
37 import com.caucho.server.util.CauchoSystem;
38 import com.caucho.util.CharBuffer;
39 import com.caucho.util.L10N;
40 import com.caucho.vfs.Depend;
41 import com.caucho.vfs.Path;
42
43 import javax.annotation.PostConstruct;
44 import java.io.IOException JavaDoc;
45 import java.net.URL JavaDoc;
46 import java.security.CodeSource JavaDoc;
47 import java.security.cert.Certificate JavaDoc;
48 import java.util.ArrayList JavaDoc;
49 import java.util.HashSet JavaDoc;
50 import java.util.logging.Level JavaDoc;
51 import java.util.logging.Logger JavaDoc;
52
53 /**
54  * A class loader that automatically compiles Java.
55  */

56 public class CompilingLoader extends Loader implements Make {
57   private static final Logger JavaDoc log = Log.open(CompilingLoader.class);
58   private static final L10N L = new L10N(CompilingLoader.class);
59
60   private static final char []INNER_CLASS_SEPARATORS =
61     new char[] {'$', '+', '-'};
62   
63   // classpath
64
private String JavaDoc _classPath;
65
66   private String JavaDoc _compiler;
67   private String JavaDoc _sourceExt = ".java";
68   
69   // source directory
70
private Path _sourceDir;
71   // directory where classes are stored
72
private Path _classDir;
73
74   private CodeSource JavaDoc _codeSource;
75   
76   private ArrayList JavaDoc<String JavaDoc> _args;
77   private String JavaDoc _encoding;
78   private boolean _requireSource;
79
80   private HashSet JavaDoc<String JavaDoc> _excludedDirectories = new HashSet JavaDoc<String JavaDoc>();
81
82   private boolean _isBatch = true;
83
84   public CompilingLoader()
85   {
86     _excludedDirectories.add("CVS");
87   }
88   
89   /**
90    * Creates a new compiling class loader
91    *
92    * @param classDir generated class directory root
93    */

94   public CompilingLoader(Path classDir)
95   {
96     this(classDir, classDir, null, null);
97   }
98
99   /**
100    * Creates a new compiling class loader
101    *
102    * @param classDir generated class directory root
103    * @param sourceDir Java source directory root
104    * @param args Javac arguments
105    * @param encoding javac encoding
106    */

107   public CompilingLoader(Path classDir, Path sourceDir,
108                          String JavaDoc args, String JavaDoc encoding)
109   {
110     if (classDir.getScheme().equals("http") ||
111         classDir.getScheme().equals("https"))
112       throw new RuntimeException JavaDoc("compiling class loader can't be http. Use compile=false.");
113
114     _sourceDir = sourceDir;
115     _classDir = classDir;
116
117     _encoding = encoding;
118
119     // loader.addCodeBasePath(classDir.getFullPath());
120

121       /*
122     try {
123       if (args != null)
124         _args = new Regexp("[\\s,]+").split(args);
125     } catch (Exception e) {
126       log.log(Level.FINER, e.toString(), e);
127     }
128       */

129   }
130
131   /**
132    * Create a class loader based on the compiling loader
133    *
134    * @param path traditional classpath
135    *
136    * @return the new ClassLoader
137    */

138   public static DynamicClassLoader create(Path path)
139   {
140     DynamicClassLoader loader = new DynamicClassLoader(null);
141
142     CompilingLoader compilingLoader = new CompilingLoader(path);
143
144     loader.addLoader(compilingLoader);
145
146     loader.init();
147
148     return loader;
149   }
150
151   /**
152    * Sets the class path.
153    */

154   public void setPath(Path path)
155   {
156     _classDir = path;
157     
158     if (_sourceDir == null)
159       _sourceDir = path;
160   }
161
162   /**
163    * Gets the class path.
164    */

165   public Path getPath()
166   {
167     return _classDir;
168   }
169
170   /**
171    * Sets the source path.
172    */

173   public void setSource(Path path)
174   {
175     _sourceDir = path;
176   }
177
178   /**
179    * Sets the source extension.
180    */

181   public void setSourceExtension(String JavaDoc ext)
182     throws ConfigException
183   {
184     if (! ext.startsWith("."))
185       throw new ConfigException(L.l("source-extension '{0}' must begin with '.'",
186                     ext));
187     
188     _sourceExt = ext;
189   }
190
191   /**
192    * Sets the compiler.
193    */

194   public void setCompiler(String JavaDoc compiler)
195     throws ConfigException
196   {
197     _compiler = compiler;
198   }
199
200   /**
201    * Sets the source path.
202    */

203   public Path getSource()
204   {
205     return _sourceDir;
206   }
207
208   /**
209    * Sets the arguments.
210    */

211   public void setArgs(String JavaDoc arg)
212   {
213     int i = 0;
214     int len = arg.length();
215
216     CharBuffer cb = new CharBuffer();
217     
218     while (i < len) {
219       char ch;
220       for (; i < len && Character.isWhitespace(ch = arg.charAt(i)); i++) {
221       }
222
223       if (len <= i)
224         return;
225
226       cb.clear();
227
228       for (; i < len && ! Character.isWhitespace(ch = arg.charAt(i)); i++)
229         cb.append(ch);
230
231       addArg(cb.toString());
232     }
233   }
234
235   /**
236    * Adds an argument.
237    */

238   public void addArg(String JavaDoc arg)
239   {
240     if (_args == null)
241       _args = new ArrayList JavaDoc<String JavaDoc>();
242     
243     _args.add(arg);
244   }
245
246   /**
247    * Sets the encoding.
248    */

249   public void setEncoding(String JavaDoc encoding)
250   {
251     _encoding = encoding;
252   }
253
254   /**
255    * Sets true if source is required.
256    */

257   public void setRequireSource(boolean requireSource)
258   {
259     _requireSource = requireSource;
260   }
261
262   /**
263    * Sets true if compilation should batch as many files as possible.
264    */

265   public void setBatch(boolean isBatch)
266   {
267     _isBatch = isBatch;
268   }
269
270   /**
271    * Initialize.
272    */

273   @PostConstruct
274   public void init()
275     throws ConfigException
276   {
277     if (_classDir == null)
278       throw new ConfigException(L.l("`path' is a required attribute <compiling-loader>."));
279
280     try {
281       _classDir.mkdirs();
282     } catch (IOException JavaDoc e) {
283       log.log(Level.FINE, e.toString(), e);
284     }
285     
286     try {
287       _codeSource = new CodeSource JavaDoc(new URL JavaDoc(_classDir.getURL()), (Certificate JavaDoc []) null);
288     } catch (Exception JavaDoc e) {
289       String JavaDoc scheme = _classDir.getScheme();
290       
291       if (scheme != null && ! scheme.equals("memory"))
292     log.log(Level.FINE, e.toString(), e);
293     }
294   }
295
296   /**
297    * Creates a new compiling class loader
298    *
299    * @param classDir generated class directory root
300    * @param sourceDir Java source directory root
301    * @param args Javac arguments
302    * @param encoding javac encoding
303    */

304   public static DynamicClassLoader create(ClassLoader JavaDoc parent,
305                                           Path classDir, Path sourceDir,
306                                           String JavaDoc args, String JavaDoc encoding)
307   {
308     DynamicClassLoader loader = new DynamicClassLoader(parent);
309     loader.addLoader(new CompilingLoader(classDir, sourceDir, args, encoding));
310
311     loader.init();
312     
313     return loader;
314   }
315
316   /**
317    * Sets the owning class loader.
318    */

319   public void setLoader(DynamicClassLoader loader)
320   {
321     super.setLoader(loader);
322
323     loader.addURL(_classDir);
324   }
325
326   public String JavaDoc getClassPath()
327   {
328     if (_classPath == null)
329       _classPath = getLoader().getClassPath();
330
331     return _classPath;
332   }
333
334   /**
335    * Compiles all changed files in the class directory.
336    */

337   public void make()
338     throws IOException JavaDoc, ClassNotFoundException JavaDoc
339   {
340     if (_sourceDir.isDirectory() && ! _classDir.isDirectory())
341       _classDir.mkdirs();
342
343     String JavaDoc sourcePath = prefixClassPath(getClassPath());
344
345     if (_isBatch) {
346       ArrayList JavaDoc<String JavaDoc> files = new ArrayList JavaDoc<String JavaDoc>();
347       findAllModifiedClasses("", _sourceDir, _classDir, sourcePath, files);
348
349       if (files.size() > 0) {
350     String JavaDoc []paths = files.toArray(new String JavaDoc[files.size()]);
351
352     compileBatch(paths, true);
353       }
354     }
355     else
356       makeAllSequential("", _sourceDir, _classDir, sourcePath);
357   }
358
359   private void makeAllSequential(String JavaDoc name, Path sourceDir, Path classDir,
360                  String JavaDoc sourcePath)
361     throws IOException JavaDoc, ClassNotFoundException JavaDoc
362   {
363     String JavaDoc []list;
364
365     try {
366       list = sourceDir.list();
367     } catch (IOException JavaDoc e) {
368       return;
369     }
370
371     for (int i = 0; list != null && i < list.length; i++) {
372       if (list[i].startsWith("."))
373         continue;
374
375       if (_excludedDirectories.contains(list[i]))
376         continue;
377       
378       Path subSource = sourceDir.lookup(list[i]);
379
380       if (subSource.isDirectory()) {
381     makeAllSequential(name + list[i] + "/", subSource,
382               classDir.lookup(list[i]), sourcePath);
383       }
384       else if (list[i].endsWith(_sourceExt)) {
385     int tail = list[i].length() - _sourceExt.length();
386     String JavaDoc prefix = list[i].substring(0, tail);
387     Path subClass = classDir.lookup(prefix + ".class");
388
389     if (subSource.getLastModified() <= subClass.getLastModified())
390       continue;
391
392     compileClass(subSource, subClass, sourcePath, true);
393       }
394     }
395
396     if (! _requireSource)
397       return;
398     
399     try {
400       list = classDir.list();
401     } catch (IOException JavaDoc e) {
402       return;
403     }
404
405     for (int i = 0; list != null && i < list.length; i++) {
406       if (list[i].startsWith("."))
407         continue;
408
409       if (_excludedDirectories.contains(list[i]))
410         continue;
411       
412       Path subClass = classDir.lookup(list[i]);
413
414       if (list[i].endsWith(".class")) {
415     String JavaDoc prefix = list[i].substring(0, list[i].length() - 6);
416     Path subSource = sourceDir.lookup(prefix + _sourceExt);
417
418     if (! subSource.exists()) {
419       String JavaDoc tail = subSource.getTail();
420       boolean doRemove = true;
421
422       if (tail.indexOf('$') > 0) {
423         String JavaDoc subTail = tail.substring(0, tail.indexOf('$')) + _sourceExt;
424         Path subJava = subSource.getParent().lookup(subTail);
425
426         if (subJava.exists())
427           doRemove = false;
428       }
429
430       if (doRemove) {
431         log.finer(L.l("removing obsolete class `{0}'.", subClass.getPath()));
432
433         subClass.remove();
434       }
435     }
436       }
437     }
438   }
439
440   /**
441    * Returns the classes which need compilation.
442    */

443   private void findAllModifiedClasses(String JavaDoc name,
444                       Path sourceDir,
445                       Path classDir,
446                       String JavaDoc sourcePath,
447                       ArrayList JavaDoc<String JavaDoc> sources)
448     throws IOException JavaDoc, ClassNotFoundException JavaDoc
449   {
450     String JavaDoc []list;
451
452     try {
453       list = sourceDir.list();
454     } catch (IOException JavaDoc e) {
455       return;
456     }
457
458     for (int i = 0; list != null && i < list.length; i++) {
459       if (list[i].startsWith("."))
460         continue;
461
462       if (_excludedDirectories.contains(list[i]))
463         continue;
464       
465       Path subSource = sourceDir.lookup(list[i]);
466
467       if (subSource.isDirectory()) {
468     findAllModifiedClasses(name + list[i] + "/", subSource,
469                    classDir.lookup(list[i]), sourcePath, sources);
470       }
471       else if (list[i].endsWith(_sourceExt)) {
472     int tail = list[i].length() - _sourceExt.length();
473     String JavaDoc prefix = list[i].substring(0, tail);
474     Path subClass = classDir.lookup(prefix + ".class");
475
476     if (subClass.getLastModified() < subSource.getLastModified()) {
477       sources.add(name + list[i]);
478     }
479       }
480     }
481
482     if (! _requireSource)
483       return;
484     
485     try {
486       list = classDir.list();
487     } catch (IOException JavaDoc e) {
488       return;
489     }
490
491     for (int i = 0; list != null && i < list.length; i++) {
492       if (list[i].startsWith("."))
493         continue;
494
495       if (_excludedDirectories.contains(list[i]))
496         continue;
497       
498       Path subClass = classDir.lookup(list[i]);
499
500       if (list[i].endsWith(".class")) {
501     String JavaDoc prefix = list[i].substring(0, list[i].length() - 6);
502     Path subSource = sourceDir.lookup(prefix + _sourceExt);
503
504     if (! subSource.exists()) {
505       String JavaDoc tail = subSource.getTail();
506       boolean doRemove = true;
507
508       if (tail.indexOf('$') > 0) {
509         String JavaDoc subTail = tail.substring(0, tail.indexOf('$')) + _sourceExt;
510         Path subJava = subSource.getParent().lookup(subTail);
511
512         if (subJava.exists())
513           doRemove = false;
514       }
515
516       if (doRemove) {
517         log.finer(L.l("removing obsolete class `{0}'.", subClass.getPath()));
518
519         subClass.remove();
520       }
521     }
522       }
523     }
524   }
525
526   /**
527    * Loads the specified class, compiling if necessary.
528    */

529   protected ClassEntry getClassEntry(String JavaDoc name)
530     throws ClassNotFoundException JavaDoc
531   {
532     Path classFile = _classDir.lookup(name.replace('.', '/') + ".class");
533     String JavaDoc javaName = name.replace('.', '/') + _sourceExt;
534     Path javaFile = _sourceDir.lookup(javaName);
535
536     String JavaDoc tail = javaFile.getTail();
537
538     for (int i = 0; i < INNER_CLASS_SEPARATORS.length; i++) {
539       char sep = INNER_CLASS_SEPARATORS[i];
540       if (name.indexOf(sep) > 0) {
541     String JavaDoc subName = name.substring(0, name.indexOf(sep));
542     String JavaDoc subJavaName = subName.replace('.', '/') + _sourceExt;
543     Path subJava = _sourceDir.lookup(subJavaName);
544
545     if (subJava.exists()) {
546       javaFile = subJava;
547     }
548       }
549     }
550
551     if (_requireSource && ! javaFile.exists()) {
552       boolean doRemove = true;
553
554       if (doRemove) {
555     log.finer(L.l("removing obsolete class `{0}'.", classFile.getPath()));
556
557     try {
558       classFile.remove();
559     } catch (IOException JavaDoc e) {
560       log.log(Level.WARNING, e.toString(), e);
561     }
562
563     return null;
564       }
565     }
566
567     if (! classFile.canRead() && ! javaFile.canRead())
568       return null;
569
570     return new CompilingClassEntry(this, getLoader(),
571                    name, javaFile,
572                    classFile,
573                    getCodeSource(classFile));
574   }
575
576   /**
577    * Returns the code source for the directory.
578    */

579   protected CodeSource JavaDoc getCodeSource(Path path)
580   {
581     return _codeSource;
582   }
583
584   /**
585    * Checks that the case is okay for the source.
586    */

587   boolean checkSource(Path sourceDir, String JavaDoc javaName)
588   {
589     try {
590       while (javaName != null && ! javaName.equals("")) {
591         int p = javaName.indexOf('/');
592         String JavaDoc head;
593       
594         if (p >= 0) {
595           head = javaName.substring(0, p);
596           javaName = javaName.substring(p + 1);
597         }
598         else {
599           head = javaName;
600           javaName = null;
601         }
602
603         String JavaDoc []names = sourceDir.list();
604         int i;
605         for (i = 0; i < names.length; i++) {
606           if (names[i].equals(head))
607             break;
608         }
609
610         if (i == names.length)
611           return false;
612
613         sourceDir = sourceDir.lookup(head);
614       }
615     } catch (IOException JavaDoc e) {
616       log.log(Level.FINE, e.toString(), e);
617       
618       return false;
619     }
620
621     return true;
622   }
623
624   /**
625    * Loads the class from the class file.
626    *
627    * @param className the name of the class to load
628    * @param javaFile the path to the java source
629    * @param classFile the path to the class file
630    *
631    * @return a class entry or null on failure
632    */

633   private ClassEntry loadClass(String JavaDoc className, Path javaFile, Path classFile)
634   {
635     long length = classFile.getLength();
636
637     ClassEntry entry = new CompilingClassEntry(this, getLoader(),
638                            className, javaFile,
639                            classFile,
640                            getCodeSource(classFile));
641
642     Class JavaDoc cl = null;
643
644     try {
645       cl = getLoader().loadClass(entry);
646     } catch (Exception JavaDoc e) {
647       try {
648         if (javaFile.canRead())
649           classFile.remove();
650       } catch (IOException JavaDoc e1) {
651       }
652     }
653
654     if (cl != null)
655       return entry;
656     else
657       return null;
658   }
659
660   /**
661    * Compile the Java source. Compile errors are encapsulated in a
662    * ClassNotFound wrapper.
663    *
664    * @param javaSource path to the Java source
665    */

666   void compileClass(Path javaSource, Path javaClass,
667             String JavaDoc sourcePath, boolean isMake)
668     throws ClassNotFoundException JavaDoc
669   {
670     try {
671       JavaCompiler compiler = JavaCompiler.create(getLoader());
672       compiler.setClassDir(_classDir);
673       compiler.setSourceDir(_sourceDir);
674       if (_encoding != null)
675         compiler.setEncoding(_encoding);
676       compiler.setArgs(_args);
677       compiler.setCompileParent(! isMake);
678       compiler.setSourceExtension(_sourceExt);
679       if (_compiler != null)
680     compiler.setCompiler(_compiler);
681
682       //LineMap lineMap = new LineMap(javaFile.getNativePath());
683
// The context path is obvious from the browser url
684
//lineMap.add(name.replace('.', '/') + _sourceExt, 1, 1);
685

686       // Force this into a relative path so different compilers will work
687
String JavaDoc prefix = _sourceDir.getPath();
688       String JavaDoc full = javaSource.getPath();
689
690       String JavaDoc source;
691       if (full.startsWith(prefix)) {
692         source = full.substring(prefix.length());
693         if (source.startsWith("/"))
694           source = source.substring(1);
695       }
696       else
697         source = javaSource.getPath();
698
699       /*
700       if (javaSource.canRead() && javaClass.exists())
701         javaClass.remove();
702       */

703           
704       compiler.compileIfModified(source, null);
705     } catch (Exception JavaDoc e) {
706       getLoader().addDependency(new Depend(javaSource));
707       
708       // Compile errors are wrapped in a special ClassNotFound class
709
// so the server can give a nice error message
710
throw new CompileClassNotFound(e);
711     }
712   }
713
714   /**
715    * Compile the Java source. Compile errors are encapsulated in a
716    * ClassNotFound wrapper.
717    *
718    * @param javaSource path to the Java source
719    */

720   void compileBatch(String JavaDoc []files, boolean isMake)
721     throws ClassNotFoundException JavaDoc
722   {
723     try {
724       JavaCompiler compiler = JavaCompiler.create(getLoader());
725       compiler.setClassDir(_classDir);
726       compiler.setSourceDir(_sourceDir);
727       if (_encoding != null)
728         compiler.setEncoding(_encoding);
729       compiler.setArgs(_args);
730       compiler.setCompileParent(! isMake);
731       compiler.setSourceExtension(_sourceExt);
732       if (_compiler != null)
733     compiler.setCompiler(_compiler);
734
735       //LineMap lineMap = new LineMap(javaFile.getNativePath());
736
// The context path is obvious from the browser url
737
//lineMap.add(name.replace('.', '/') + _sourceExt, 1, 1);
738

739       compiler.compileBatch(files);
740     } catch (Exception JavaDoc e) {
741       getLoader().addDependency(AlwaysModified.create());
742
743       // Compile errors are wrapped in a special ClassNotFound class
744
// so the server can give a nice error message
745
throw new CompileClassNotFound(e);
746     }
747   }
748
749   /**
750    * Returns the path for the given name.
751    *
752    * @param name the name of the class
753    */

754   public Path getPath(String JavaDoc name)
755   {
756     Path path = _classDir.lookup(name);
757
758     if (path != null && path.exists())
759       return path;
760
761     path = _sourceDir.lookup(name);
762
763     if (path != null && path.exists())
764       return path;
765
766     return null;
767   }
768
769   /**
770    * Adds the classpath we're responsible for to the classpath
771    *
772    * @param head the overriding classpath
773    * @return the new classpath
774    */

775   protected String JavaDoc getClassPath(String JavaDoc head)
776   {
777     CharBuffer cb = new CharBuffer();
778
779     if (! _classDir.getScheme().equals("file"))
780       return head;
781
782     try {
783       if (! _classDir.isDirectory() && _sourceDir.isDirectory()) {
784         try {
785           _classDir.mkdirs();
786         } catch (IOException JavaDoc e) {
787         }
788       }
789
790       cb.append(head);
791
792       if (_classDir.isDirectory()) {
793         if (cb.length() > 0)
794           cb.append(CauchoSystem.getPathSeparatorChar());
795         cb.append(_classDir.getNativePath());
796       }
797     
798       if (! _classDir.equals(_sourceDir)) {
799         if (cb.length() > 0)
800           cb.append(CauchoSystem.getPathSeparatorChar());
801         cb.append(_sourceDir.getNativePath());
802       }
803
804       return cb.close();
805     } catch (java.security.AccessControlException JavaDoc e) {
806       log.log(Level.WARNING, e.toString(), e);
807       
808       return head;
809     }
810   }
811
812   protected String JavaDoc prefixClassPath(String JavaDoc tail)
813   {
814     CharBuffer cb = new CharBuffer();
815
816     if (! _classDir.isDirectory() && _sourceDir.isDirectory()) {
817       try {
818         _classDir.mkdirs();
819       } catch (IOException JavaDoc e) {
820       }
821     }
822
823     if (_classDir.isDirectory()) {
824       if (cb.length() > 0)
825         cb.append(CauchoSystem.getPathSeparatorChar());
826       cb.append(_classDir.getNativePath());
827     }
828     
829     if (! _classDir.equals(_sourceDir)) {
830       if (cb.length() > 0)
831         cb.append(CauchoSystem.getPathSeparatorChar());
832       cb.append(_sourceDir.getNativePath());
833     }
834
835     if (cb.length() > 0)
836       cb.append(CauchoSystem.getPathSeparatorChar());
837     cb.append(tail);
838
839     return cb.close();
840   }
841
842   protected String JavaDoc getSourcePath(String JavaDoc head)
843   {
844     return getClassPath(head);
845
846     /* XXX: getClassPath already includes the source path
847     if (! sourceDir.getScheme().equals("file"))
848       return head;
849         
850     if (sourceDir.isDirectory() && ! sourceDir.equals(classDir)) {
851       CharBuffer cb = new CharBuffer();
852
853       if (! head.equals("")) {
854         cb.append(head);
855         cb.append(CauchoSystem.getPathSeparatorChar());
856       }
857       cb.append(classDir.getNativePath());
858
859       return cb.close();
860     }
861     else
862       return head;
863     */

864   }
865
866   public String JavaDoc toString()
867   {
868     if (_classDir == null)
869       return "CompilingLoader[]";
870     else if (_classDir.equals(_sourceDir))
871       return "CompilingLoader[src:" + _sourceDir + "]";
872     else
873       return ("CompilingLoader[src:" + _sourceDir +
874               ",class:" + _classDir + "]");
875   }
876 }
877
Popular Tags