001 /* 002 $Id: CompilationUnit.java,v 1.24 2005/06/27 17:34:03 fraz Exp $ 003 004 005 Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved. 006 007 008 Redistribution and use of this software and associated documentation 009 ("Software"), with or without modification, are permitted provided 010 that the following conditions are met: 011 012 1. Redistributions of source code must retain copyright 013 statements and notices. Redistributions must also contain a 014 copy of this document. 015 016 017 2. Redistributions in binary form must reproduce the 018 above copyright notice, this list of conditions and the 019 following disclaimer in the documentation and/or other 020 materials provided with the distribution. 021 022 023 3. The name "groovy" must not be used to endorse or promote 024 products derived from this Software without prior written 025 permission of The Codehaus. For written permission, 026 please contact info@codehaus.org. 027 028 029 4. Products derived from this Software may not be called "groovy" 030 nor may "groovy" appear in their names without prior written 031 permission of The Codehaus. "groovy" is a registered 032 trademark of The Codehaus. 033 034 035 5. Due credit should be given to The Codehaus - 036 http://groovy.codehaus.org/ 037 038 039 THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS 040 ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT 041 NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 042 FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 043 THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 044 INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 045 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 046 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 047 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 048 STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 049 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 050 OF THE POSSIBILITY OF SUCH DAMAGE. 051 */ 052 053 054 package org.codehaus.groovy.control; 055 056 import java.io.File; 057 import java.io.FileOutputStream; 058 import java.io.IOException; 059 import java.io.InputStream; 060 import java.net.URL; 061 import java.security.CodeSource; 062 import java.util.ArrayList; 063 import java.util.HashMap; 064 import java.util.Iterator; 065 import java.util.LinkedList; 066 import java.util.List; 067 068 import org.codehaus.groovy.GroovyBugError; 069 import org.codehaus.groovy.ast.ASTNode; 070 import org.codehaus.groovy.ast.ClassNode; 071 import org.codehaus.groovy.ast.CompileUnit; 072 import org.codehaus.groovy.ast.ModuleNode; 073 import org.codehaus.groovy.classgen.AsmClassGenerator; 074 import org.codehaus.groovy.classgen.ClassCompletionVerifier; 075 import org.codehaus.groovy.classgen.ClassGenerator; 076 import org.codehaus.groovy.classgen.GeneratorContext; 077 import org.codehaus.groovy.classgen.JSRVariableScopeCodeVisitor; 078 import org.codehaus.groovy.classgen.Verifier; 079 import org.codehaus.groovy.control.io.InputStreamReaderSource; 080 import org.codehaus.groovy.control.io.ReaderSource; 081 import org.codehaus.groovy.control.messages.ExceptionMessage; 082 import org.codehaus.groovy.control.messages.Message; 083 import org.codehaus.groovy.syntax.SyntaxException; 084 import org.codehaus.groovy.tools.GroovyClass; 085 import org.objectweb.asm.ClassVisitor; 086 import org.objectweb.asm.ClassWriter; 087 088 import groovy.lang.GroovyClassLoader; 089 import groovy.lang.GroovyRuntimeException; 090 091 /** 092 * Collects all compilation data as it is generated by the compiler system. 093 * Allows additional source units to be added and compilation run again (to 094 * affect only the deltas). 095 * 096 * @author <a href="mailto:cpoirier@dreaming.org">Chris Poirier</a> 097 * @version $Id: CompilationUnit.java,v 1.24 2005/06/27 17:34:03 fraz Exp $ 098 */ 099 100 public class CompilationUnit extends ProcessingUnit { 101 102 103 //--------------------------------------------------------------------------- 104 // CONSTRUCTION AND SUCH 105 106 107 protected HashMap sources; // The SourceUnits from which this unit is built 108 protected ArrayList names; // Names for each SourceUnit in sources. 109 110 111 protected CompileUnit ast; // The overall AST for this CompilationUnit. 112 protected ArrayList classes; // The classes generated during classgen. 113 114 115 protected Verifier verifier; // For use by verify(). 116 117 118 protected ClassCompletionVerifier completionVerifier; // for use by checkClassCompletion 119 120 121 protected boolean debug; // Controls behaviour of classgen() and other routines. 122 protected boolean configured; // Set true after the first configure() operation 123 124 125 protected ClassgenCallback classgenCallback; // A callback for use during classgen() 126 protected ProgressCallback progressCallback; // A callback for use during compile() 127 128 129 130 /** 131 * Initializes the CompilationUnit with defaults. 132 */ 133 public CompilationUnit() { 134 this(null, null, null); 135 } 136 137 138 139 /** 140 * Initializes the CompilationUnit with defaults except for class loader. 141 */ 142 public CompilationUnit(ClassLoader loader) { 143 this(null, null, loader); 144 } 145 146 147 148 /** 149 * Initializes the CompilationUnit with no security considerations. 150 */ 151 public CompilationUnit(CompilerConfiguration configuration) { 152 this(configuration, null, null); 153 } 154 155 /** 156 * Initializes the CompilationUnit with a CodeSource for controlling 157 * security stuff and a class loader for loading classes. 158 */ 159 public CompilationUnit(CompilerConfiguration configuration, CodeSource security, ClassLoader loader) { 160 super(configuration, loader, null); 161 162 this.names = new ArrayList(); 163 this.sources = new HashMap(); 164 165 166 this.ast = new CompileUnit(this.classLoader, security, this.configuration); 167 this.classes = new ArrayList(); 168 169 170 this.verifier = new Verifier(); 171 this.completionVerifier = new ClassCompletionVerifier(); 172 173 174 this.classgenCallback = null; 175 } 176 177 /** 178 * Configures its debugging mode and classloader classpath from a given compiler configuration. 179 * This cannot be done more than once due to limitations in {@link java.net.URLClassLoader URLClassLoader}. 180 */ 181 public void configure(CompilerConfiguration configuration) { 182 super.configure(configuration); 183 this.debug = configuration.getDebug(); 184 185 if (!this.configured && this.classLoader instanceof GroovyClassLoader) { 186 appendCompilerConfigurationClasspathToClassLoader(configuration, (GroovyClassLoader) this.classLoader); 187 } 188 189 this.configured = true; 190 } 191 192 private void appendCompilerConfigurationClasspathToClassLoader(CompilerConfiguration configuration, GroovyClassLoader classLoader) { 193 for (Iterator iterator = configuration.getClasspath().iterator(); iterator.hasNext(); ) { 194 classLoader.addClasspath((String) iterator.next()); 195 } 196 } 197 198 /** 199 * Returns the CompileUnit that roots our AST. 200 */ 201 public CompileUnit getAST() { 202 return this.ast; 203 } 204 205 206 /** 207 * Get the GroovyClasses generated by compile(). 208 */ 209 210 211 public List getClasses() { 212 return classes; 213 } 214 215 216 /** 217 * Convenience routine to get the first ClassNode, for 218 * when you are sure there is only one. 219 */ 220 public ClassNode getFirstClassNode() { 221 return (ClassNode) ((ModuleNode) this.ast.getModules().get(0)).getClasses().get(0); 222 } 223 224 225 /** 226 * Convenience routine to get the named ClassNode. 227 */ 228 public ClassNode getClassNode(final String name) { 229 final ClassNode[] result = new ClassNode[]{null}; 230 LoopBodyForPrimaryClassNodeOperations handler = new LoopBodyForPrimaryClassNodeOperations() { 231 232 233 public void call(SourceUnit source, GeneratorContext context, ClassNode classNode) { 234 235 236 if (classNode.getName().equals(name)) { 237 238 239 result[0] = classNode; 240 241 242 } 243 244 245 } 246 247 248 }; 249 250 251 try { 252 applyToPrimaryClassNodes(handler); 253 } catch (CompilationFailedException e) { 254 if (debug) e.printStackTrace(); 255 } 256 return result[0]; 257 } 258 259 260 261 262 263 //--------------------------------------------------------------------------- 264 // SOURCE CREATION 265 266 267 /** 268 * Adds a set of file paths to the unit. 269 */ 270 public void addSources(String[] paths) { 271 for (int i = 0; i < paths.length; i++) { 272 File file = new File(paths[i]); 273 addSource(file); 274 } 275 } 276 277 278 /** 279 * Adds a set of source files to the unit. 280 */ 281 public void addSources(File[] files) { 282 for (int i = 0; i < files.length; i++) { 283 addSource(files[i]); 284 } 285 } 286 287 288 /** 289 * Adds a source file to the unit. 290 */ 291 public SourceUnit addSource(File file) { 292 return addSource(new SourceUnit(file, configuration, classLoader, getErrorCollector())); 293 } 294 295 296 /** 297 * Adds a source file to the unit. 298 */ 299 public SourceUnit addSource(URL url) { 300 return addSource(new SourceUnit(url, configuration, classLoader,getErrorCollector())); 301 } 302 303 304 /** 305 * Adds a InputStream source to the unit. 306 */ 307 public SourceUnit addSource(String name, InputStream stream) { 308 ReaderSource source = new InputStreamReaderSource(stream, configuration); 309 return addSource(new SourceUnit(name, source, configuration, classLoader, getErrorCollector())); 310 } 311 312 313 /** 314 * Adds a SourceUnit to the unit. 315 */ 316 public SourceUnit addSource(SourceUnit source) { 317 String name = source.getName(); 318 319 320 source.setClassLoader(this.classLoader); 321 322 323 names.add(name); 324 sources.put(name, source); 325 326 327 return source; 328 } 329 330 331 /** 332 * Returns an iterator on the unit's SourceUnits. 333 */ 334 public Iterator iterator() { 335 return new Iterator() { 336 Iterator nameIterator = names.iterator(); 337 338 339 public boolean hasNext() { 340 return nameIterator.hasNext(); 341 } 342 343 344 public Object next() { 345 String name = (String) nameIterator.next(); 346 return sources.get(name); 347 } 348 349 350 public void remove() { 351 throw new UnsupportedOperationException(); 352 } 353 }; 354 } 355 356 357 /** 358 * Adds a ClassNode directly to the unit (ie. without source). 359 * Used primarily for testing support. 360 */ 361 public void addClassNode(ClassNode node) { 362 ModuleNode module = new ModuleNode(this.ast); 363 this.ast.addModule(module); 364 module.addClass(node); 365 } 366 367 368 369 370 371 //--------------------------------------------------------------------------- 372 // EXTERNAL CALLBACKS 373 374 375 /** 376 * A callback interface you can use to "accompany" the classgen() 377 * code as it traverses the ClassNode tree. You will be called-back 378 * for each primary and inner class. Use setClassgenCallback() before 379 * running compile() to set your callback. 380 */ 381 public static abstract class ClassgenCallback { 382 public abstract void call(ClassVisitor writer, ClassNode node) throws CompilationFailedException; 383 } 384 385 386 /** 387 * Sets a ClassgenCallback. You can have only one, and setting 388 * it to null removes any existing setting. 389 */ 390 public void setClassgenCallback(ClassgenCallback visitor) { 391 this.classgenCallback = visitor; 392 } 393 394 395 /** 396 * A callback interface you can use to get a callback after every 397 * unit of the compile process. You will be called-back with a 398 * ProcessingUnit and a phase indicator. Use setProgressCallback() 399 * before running compile() to set your callback. 400 */ 401 public static abstract class ProgressCallback { 402 403 public abstract void call(ProcessingUnit context, int phase) throws CompilationFailedException; 404 } 405 406 /** 407 * Sets a ProgressCallback. You can have only one, and setting 408 * it to null removes any existing setting. 409 */ 410 public void setProgressCallback(ProgressCallback callback) { 411 this.progressCallback = callback; 412 } 413 414 415 //--------------------------------------------------------------------------- 416 // ACTIONS 417 418 419 /** 420 * Synonym for compile(Phases.ALL). 421 */ 422 public void compile() throws CompilationFailedException { 423 compile(Phases.ALL); 424 } 425 426 427 /** 428 * Compiles the compilation unit from sources. 429 */ 430 public void compile(int throughPhase) throws CompilationFailedException { 431 // 432 // To support delta compilations, we always restart 433 // the compiler. The individual passes are responsible 434 // for not reprocessing old code. 435 gotoPhase(Phases.INITIALIZATION); 436 437 438 do { 439 if (throughPhase < Phases.PARSING) { 440 break; 441 } 442 gotoPhase(Phases.PARSING); 443 parse(); 444 445 446 if (throughPhase < Phases.CONVERSION) { 447 break; 448 } 449 450 451 gotoPhase(Phases.CONVERSION); 452 convert(); 453 454 455 if (throughPhase < Phases.CLASS_GENERATION) { 456 break; 457 } 458 459 460 gotoPhase(Phases.CLASS_GENERATION); 461 classgen(); 462 463 464 if (throughPhase < Phases.OUTPUT) { 465 break; 466 } 467 468 469 gotoPhase(Phases.OUTPUT); 470 output(); 471 472 473 if (throughPhase < Phases.FINALIZATION) { 474 break; 475 } 476 477 478 gotoPhase(Phases.FINALIZATION); 479 } while (false); 480 } 481 482 483 484 /** 485 * Parses all sources. 486 */ 487 public void parse() throws CompilationFailedException { 488 if (this.phase != Phases.PARSING) { 489 throw new GroovyBugError("CompilationUnit not read for parse()"); 490 } 491 492 493 applyToSourceUnits(parse); 494 completePhase(); 495 applyToSourceUnits(mark); 496 } 497 498 499 /** 500 * Runs parse() on a single SourceUnit. 501 */ 502 private LoopBodyForSourceUnitOperations parse = new LoopBodyForSourceUnitOperations() { 503 public void call(SourceUnit source) throws CompilationFailedException { 504 source.parse(); 505 506 507 if (CompilationUnit.this.progressCallback != null) { 508 CompilationUnit.this.progressCallback.call(source, CompilationUnit.this.phase); 509 } 510 } 511 }; 512 513 514 /** 515 * Builds ASTs for all parsed sources. 516 */ 517 public void convert() throws CompilationFailedException { 518 if (this.phase != Phases.CONVERSION) { 519 throw new GroovyBugError("CompilationUnit not ready for convert()"); 520 } 521 522 523 applyToSourceUnits(convert); 524 525 526 completePhase(); 527 applyToSourceUnits(mark); 528 } 529 530 531 /** 532 * Runs convert() on a single SourceUnit. 533 */ 534 private LoopBodyForSourceUnitOperations convert = new LoopBodyForSourceUnitOperations() { 535 public void call(SourceUnit source) throws CompilationFailedException { 536 source.convert(); 537 CompilationUnit.this.ast.addModule(source.getAST()); 538 539 540 if (CompilationUnit.this.progressCallback != null) { 541 CompilationUnit.this.progressCallback.call(source, CompilationUnit.this.phase); 542 } 543 } 544 }; 545 546 547 /** 548 * Expands and canonicalizes the ASTs generated during 549 * parsing and conversion, then generates classes. 550 */ 551 public void classgen() throws CompilationFailedException { 552 if (this.phase != Phases.CLASS_GENERATION) { 553 throw new GroovyBugError("CompilationUnit not ready for classgen()"); 554 } 555 556 applyToPrimaryClassNodes(classgen); 557 558 completePhase(); 559 applyToSourceUnits(mark); 560 561 // 562 // Callback progress, if necessary 563 564 565 if (this.progressCallback != null) { 566 this.progressCallback.call(this, CompilationUnit.this.phase); 567 } 568 } 569 570 /** 571 * Runs classgen() on a single ClassNode. 572 */ 573 private LoopBodyForPrimaryClassNodeOperations classgen = new LoopBodyForPrimaryClassNodeOperations() { 574 public void call(SourceUnit source, GeneratorContext context, ClassNode classNode) throws CompilationFailedException { 575 // 576 // Run the Verifier on the outer class 577 // 578 try { 579 verifier.visitClass(classNode); 580 } catch (GroovyRuntimeException rpe) { 581 ASTNode node = rpe.getNode(); 582 getErrorCollector().addError( 583 new SyntaxException(rpe.getMessage(),null,node.getLineNumber(),node.getColumnNumber()), 584 source 585 ); 586 } 587 588 // 589 // do scoping 590 // 591 if (source!=null && (!classNode.isSynthetic()) && (!"false".equals(System.getProperty("groovy.jsr.check")))) { 592 JSRVariableScopeCodeVisitor scopeVisitor = new JSRVariableScopeCodeVisitor(null ,source); 593 scopeVisitor.visitClass(classNode); 594 source.getErrorCollector().failIfErrors(); 595 } 596 597 // 598 // Prep the generator machinery 599 // 600 ClassVisitor visitor = createClassVisitor(); 601 602 603 String sourceName = (source == null ? classNode.getModule().getDescription() : source.getName()); 604 ClassGenerator generator = new AsmClassGenerator(context, visitor, classLoader, sourceName); 605 606 607 // 608 // Run the generation and create the class (if required) 609 // 610 generator.visitClass(classNode); 611 completionVerifier.visitClass(classNode); 612 613 614 if (!debug) { 615 byte[] bytes = ((ClassWriter) visitor).toByteArray(); 616 /* this. */classes.add(new GroovyClass(classNode.getName(), bytes)); 617 } 618 619 620 // 621 // Handle any callback that's been set 622 623 624 if (CompilationUnit.this.classgenCallback != null) { 625 classgenCallback.call(visitor, classNode); 626 } 627 628 629 // 630 // Recurse for inner classes 631 632 LinkedList innerClasses = generator.getInnerClasses(); 633 while (!innerClasses.isEmpty()) { 634 classgen.call(source, context, (ClassNode) innerClasses.removeFirst()); 635 } 636 } 637 }; 638 639 640 protected ClassVisitor createClassVisitor() { 641 /** avoid runtime dependency on asm util 642 ClassVisitor visitor; 643 if( debug ) 644 { 645 visitor = new DumpClassVisitor(output); 646 } 647 else 648 { 649 visitor = new ClassWriter(true); 650 } 651 return visitor; 652 */ 653 return new ClassWriter(true); 654 } 655 656 657 /** 658 * Outputs the generated class files to permanent storage. 659 */ 660 public void output() throws CompilationFailedException { 661 if (this.phase != Phases.OUTPUT && !(this.phase == Phases.CLASS_GENERATION && this.phaseComplete)) { 662 throw new GroovyBugError("CompilationUnit not ready for output()"); 663 } 664 665 666 boolean failures = false; 667 668 669 Iterator iterator = this.classes.iterator(); 670 while (iterator.hasNext()) { 671 // 672 // Get the class and calculate its filesystem name 673 674 675 GroovyClass gclass = (GroovyClass) iterator.next(); 676 String name = gclass.getName().replace('.', File.separatorChar) + ".class"; 677 File path = new File(configuration.getTargetDirectory(), name); 678 679 680 // 681 // Ensure the path is ready for the file 682 683 684 File directory = path.getParentFile(); 685 if (directory != null && !directory.exists()) { 686 directory.mkdirs(); 687 } 688 689 690 // 691 // Create the file and write out the data 692 693 byte[] bytes = gclass.getBytes(); 694 695 696 FileOutputStream stream = null; 697 try { 698 stream = new FileOutputStream(path); 699 stream.write(bytes, 0, bytes.length); 700 } catch (IOException e) { 701 getErrorCollector().addError(Message.create(e.getMessage(),this)); 702 failures = true; 703 } finally { 704 if (stream != null) { 705 try { 706 stream.close(); 707 } catch (Exception e) { 708 } 709 } 710 } 711 } 712 713 714 getErrorCollector().failIfErrors(); 715 716 717 completePhase(); 718 applyToSourceUnits(mark); 719 720 721 // 722 // Callback progress, if necessary 723 724 725 if (CompilationUnit.this.progressCallback != null) { 726 CompilationUnit.this.progressCallback.call(this, this.phase); 727 } 728 } 729 730 //--------------------------------------------------------------------------- 731 // PHASE HANDLING 732 733 734 /** 735 * Updates the phase marker on all sources. 736 */ 737 protected void mark() throws CompilationFailedException { 738 applyToSourceUnits(mark); 739 } 740 741 742 /** 743 * Marks a single SourceUnit with the current phase, 744 * if it isn't already there yet. 745 */ 746 private LoopBodyForSourceUnitOperations mark = new LoopBodyForSourceUnitOperations() { 747 public void call(SourceUnit source) throws CompilationFailedException { 748 if (source.phase < phase) { 749 source.gotoPhase(phase); 750 } 751 752 753 if (source.phase == phase && phaseComplete && !source.phaseComplete) { 754 source.completePhase(); 755 } 756 } 757 }; 758 759 760 761 762 763 //--------------------------------------------------------------------------- 764 // LOOP SIMPLIFICATION FOR SourceUnit OPERATIONS 765 766 767 /** 768 * An callback interface for use in the applyToSourceUnits loop driver. 769 */ 770 public abstract class LoopBodyForSourceUnitOperations { 771 public abstract void call(SourceUnit source) throws CompilationFailedException; 772 } 773 774 775 776 777 /** 778 * A loop driver for applying operations to all SourceUnits. 779 * Automatically skips units that have already been processed 780 * through the current phase. 781 */ 782 public void applyToSourceUnits(LoopBodyForSourceUnitOperations body) throws CompilationFailedException { 783 boolean failures = false; 784 785 786 Iterator keys = names.iterator(); 787 while (keys.hasNext()) { 788 String name = (String) keys.next(); 789 SourceUnit source = (SourceUnit) sources.get(name); 790 if (source.phase <= phase) { 791 try { 792 body.call(source); 793 } catch (CompilationFailedException e) { 794 throw e; 795 } catch (Exception e) { 796 throw new GroovyBugError(e); 797 } 798 } 799 } 800 801 802 getErrorCollector().failIfErrors(); 803 } 804 805 806 //--------------------------------------------------------------------------- 807 // LOOP SIMPLIFICATION FOR PRIMARY ClassNode OPERATIONS 808 809 810 811 /** 812 * An callback interface for use in the applyToSourceUnits loop driver. 813 */ 814 public abstract class LoopBodyForPrimaryClassNodeOperations { 815 public abstract void call(SourceUnit source, GeneratorContext context, ClassNode classNode) throws CompilationFailedException; 816 } 817 818 819 820 /** 821 * A loop driver for applying operations to all primary ClassNodes in 822 * our AST. Automatically skips units that have already been processed 823 * through the current phase. 824 */ 825 public void applyToPrimaryClassNodes(LoopBodyForPrimaryClassNodeOperations body) throws CompilationFailedException { 826 boolean failures = false; 827 828 829 Iterator modules = this.ast.getModules().iterator(); 830 while (modules.hasNext()) { 831 ModuleNode module = (ModuleNode) modules.next(); 832 833 834 try { 835 Iterator classNodes = module.getClasses().iterator(); 836 while (classNodes.hasNext()) { 837 ClassNode classNode = (ClassNode) classNodes.next(); 838 SourceUnit context = module.getContext(); 839 if (context == null || context.phase <= phase) { 840 body.call(module.getContext(), new GeneratorContext(this.ast), classNode); 841 } 842 } 843 } catch (CompilationFailedException e) { 844 // fall thorugh, getErrorREporter().failIfErrors() will triger 845 } catch (Exception e) { 846 failures = true; 847 // String msg = e.getMessage(); 848 // if (e instanceof RuntimeParserException) { 849 // RuntimeParserException rpe = (RuntimeParserException) e; 850 // ASTNode node = rpe.getNode(); 851 // msg += ". The probable error location: [" + node.getLineNumber() + ":" + node.getColumnNumber() + "]"; 852 // } 853 854 // check the exception for a nested compilation exception 855 ErrorCollector nestedCollector = null; 856 for (Throwable next = e.getCause(); next!=e && next!=null; next=next.getCause()) { 857 if (!(next instanceof MultipleCompilationErrorsException)) continue; 858 MultipleCompilationErrorsException mcee = (MultipleCompilationErrorsException) next; 859 nestedCollector = mcee.collector; 860 break; 861 } 862 863 if (nestedCollector!=null) { 864 getErrorCollector().addCollectorContents(nestedCollector); 865 } else { 866 getErrorCollector().addError(new ExceptionMessage(e,configuration.getDebug(),this)); 867 } 868 } 869 } 870 871 getErrorCollector().failIfErrors(); 872 } 873 874 875 //--------------------------------------------------------------------------- 876 // OUTPUT 877 878 879 /** 880 * Writes error messages to the specified PrintWriter. 881 */ 882 /*public void write(PrintWriter writer, Janitor janitor) { 883 super.write(writer, janitor); 884 885 Iterator keys = names.iterator(); 886 while (keys.hasNext()) { 887 String name = (String) keys.next(); 888 SourceUnit source = (SourceUnit) sources.get(name); 889 890 if (source.hasErrors()) { 891 source.write(writer, janitor); 892 } 893 } 894 }*/ 895 896 897 }