001 /* 002 * $Id: CompileUnit.java,v 1.11 2005/06/13 10:23:23 blackdrag Exp $ 003 * 004 * Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved. 005 * 006 * Redistribution and use of this software and associated documentation 007 * ("Software"), with or without modification, are permitted provided that the 008 * following conditions are met: 009 * 1. Redistributions of source code must retain copyright statements and 010 * notices. Redistributions must also contain a copy of this document. 011 * 2. Redistributions in binary form must reproduce the above copyright 012 * notice, this list of conditions and the following disclaimer in the 013 * documentation and/or other materials provided with the distribution. 014 * 3. The name "groovy" must not be used to endorse or promote products 015 * derived from this Software without prior written permission of The Codehaus. 016 * For written permission, please contact info@codehaus.org. 017 * 4. Products derived from this Software may not be called "groovy" nor may 018 * "groovy" appear in their names without prior written permission of The 019 * Codehaus. "groovy" is a registered trademark of The Codehaus. 020 * 5. Due credit should be given to The Codehaus - http://groovy.codehaus.org/ 021 * 022 * THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS ``AS IS'' AND ANY 023 * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 024 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 025 * DISCLAIMED. IN NO EVENT SHALL THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR 026 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 027 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 028 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 029 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 030 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 031 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH 032 * DAMAGE. 033 * 034 */ 035 package org.codehaus.groovy.ast; 036 037 import java.security.CodeSource; 038 import java.util.ArrayList; 039 import java.util.HashMap; 040 import java.util.Iterator; 041 import java.util.List; 042 import java.util.Map; 043 044 import org.codehaus.groovy.classgen.ClassGeneratorException; 045 import org.codehaus.groovy.control.CompilationFailedException; 046 import org.codehaus.groovy.control.CompilerConfiguration; 047 048 /** 049 * Represents the entire contents of a compilation step which consists of one 050 * or more {@link ModuleNode}instances 051 * 052 * @author <a href="mailto:james@coredevelopers.net">James Strachan </a> 053 * @version $Revision: 1.11 $ 054 */ 055 public class CompileUnit { 056 057 private List modules = new ArrayList(); 058 private Map classes = new HashMap(); 059 private CompilerConfiguration config; 060 private ClassLoader classLoader; 061 private CodeSource codeSource; 062 private Map cachedClasses = new HashMap(); 063 064 public static final Object NO_CLASS = new Object(); 065 066 067 public CompileUnit(ClassLoader classLoader, CompilerConfiguration config) { 068 this(classLoader, null, config); 069 } 070 071 public CompileUnit(ClassLoader classLoader, CodeSource codeSource, CompilerConfiguration config) { 072 this.classLoader = classLoader; 073 this.config = config; 074 this.codeSource = codeSource; 075 } 076 077 public List getModules() { 078 return modules; 079 } 080 081 public void addModule(ModuleNode node) { 082 modules.add(node); 083 node.setUnit(this); 084 addClasses(node.classes); 085 } 086 087 /** 088 * @return the ClassNode for the given qualified name or returns null if 089 * the name does not exist in the current compilation unit 090 * (ignoring the .class files on the classpath) 091 */ 092 public ClassNode getClass(String name) { 093 return (ClassNode) classes.get(name); 094 } 095 096 /** 097 * @return a list of all the classes in each module in the compilation unit 098 */ 099 public List getClasses() { 100 List answer = new ArrayList(); 101 for (Iterator iter = modules.iterator(); iter.hasNext();) { 102 ModuleNode module = (ModuleNode) iter.next(); 103 answer.addAll(module.getClasses()); 104 } 105 return answer; 106 } 107 108 public CompilerConfiguration getConfig() { 109 return config; 110 } 111 112 public ClassLoader getClassLoader() { 113 return classLoader; 114 } 115 116 public CodeSource getCodeSource() { 117 return codeSource; 118 } 119 120 121 /** 122 * Loads a class on the compile classpath so that it can be introspected 123 * 124 * @param type 125 * @return @throws 126 * ClassNotFoundException 127 */ 128 public Class loadClass(String type) throws ClassNotFoundException { 129 Object obj = cachedClasses.get(type); 130 if ( obj == NO_CLASS ) { 131 throw new ClassNotFoundException(type); 132 } 133 if ( obj != null) { 134 return (Class)obj; 135 } 136 137 Class answer = null; 138 ClassLoader lastLoader = getClassLoader(); 139 try { 140 answer = lastLoader.loadClass(type); 141 } catch (ClassNotFoundException e) { 142 Throwable cause = e.getCause(); 143 if (cause !=null && cause instanceof CompilationFailedException){ 144 throw new ClassGeneratorException("Error when compiling class: " + type + ". Reason: " + cause, cause); 145 } 146 } catch (NoClassDefFoundError e) { 147 // fall through 148 } 149 150 try { 151 ClassLoader loader = Thread.currentThread().getContextClassLoader(); 152 if ( answer == null && loader != lastLoader /*&& loader != null*/) { 153 lastLoader = loader; 154 answer = loader.loadClass(type); 155 } 156 } 157 catch (ClassNotFoundException e1) { 158 Throwable cause = e1.getCause(); 159 if (cause !=null && cause instanceof CompilationFailedException){ 160 throw new ClassGeneratorException("Error when compiling class: " + type + ". Reason: " + cause, cause); 161 } 162 } catch (NoClassDefFoundError e) { 163 // fall through 164 } 165 166 // lets try our class loader 167 try { 168 ClassLoader loader = getClass().getClassLoader(); 169 if ( answer == null && loader != lastLoader) { 170 lastLoader = loader; 171 answer = loader.loadClass(type); 172 } 173 } 174 catch (ClassNotFoundException e2) { 175 Throwable cause = e2.getCause(); 176 if (cause !=null && cause instanceof CompilationFailedException){ 177 throw new ClassGeneratorException("Error when compiling class: " + type + ". Reason: " + cause, cause); 178 } 179 } 180 catch (NoClassDefFoundError e) { 181 // fall through 182 } 183 184 try { 185 if (answer == null ) { 186 answer = Class.forName(type); 187 } 188 } 189 catch (ClassNotFoundException e2) { 190 Throwable cause = e2.getCause(); 191 if (cause !=null && cause instanceof CompilationFailedException){ 192 throw new ClassGeneratorException("Error when compiling class: " + type + ". Reason: " + cause, cause); 193 } 194 } 195 catch (NoClassDefFoundError e) { 196 // fall through 197 } 198 199 if ( answer == null ) { 200 cachedClasses.put(type,NO_CLASS); 201 throw new ClassNotFoundException(type); 202 } else { 203 if (!type.equals(answer.getName())) { // br case sensitive match 204 cachedClasses.put(type,NO_CLASS); 205 System.out.println("Mismatch: answer.getName() = " + answer.getName() + ", type = " + type); 206 throw new ClassNotFoundException(type); 207 } 208 cachedClasses.put(type,answer); 209 } 210 211 return answer; 212 } 213 214 215 /** 216 * Appends all of the fully qualified class names in this 217 * module into the given map 218 */ 219 void addClasses(List classList) { 220 for (Iterator iter = classList.iterator(); iter.hasNext();) { 221 addClass((ClassNode) iter.next()); 222 } 223 } 224 225 /** 226 * Adds a class to the unit. 227 */ 228 public void addClass(ClassNode node) { 229 String name = node.getName(); 230 if (classes.containsKey(name)) { 231 throw new RuntimeException( 232 "Error: duplicate class declaration for name: " + name + " and class: " + node); 233 } 234 classes.put(name, node); 235 } 236 237 }