1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35 package org.codehaus.groovy.ast;
36
37 import java.security.CodeSource;
38 import java.util.ArrayList;
39 import java.util.HashMap;
40 import java.util.Iterator;
41 import java.util.List;
42 import java.util.Map;
43
44 import org.codehaus.groovy.classgen.ClassGeneratorException;
45 import org.codehaus.groovy.control.CompilationFailedException;
46 import org.codehaus.groovy.control.CompilerConfiguration;
47
48 /***
49 * Represents the entire contents of a compilation step which consists of one
50 * or more {@link ModuleNode}instances
51 *
52 * @author <a href="mailto:james@coredevelopers.net">James Strachan </a>
53 * @version $Revision: 1.11 $
54 */
55 public class CompileUnit {
56
57 private List modules = new ArrayList();
58 private Map classes = new HashMap();
59 private CompilerConfiguration config;
60 private ClassLoader classLoader;
61 private CodeSource codeSource;
62 private Map cachedClasses = new HashMap();
63
64 public static final Object NO_CLASS = new Object();
65
66
67 public CompileUnit(ClassLoader classLoader, CompilerConfiguration config) {
68 this(classLoader, null, config);
69 }
70
71 public CompileUnit(ClassLoader classLoader, CodeSource codeSource, CompilerConfiguration config) {
72 this.classLoader = classLoader;
73 this.config = config;
74 this.codeSource = codeSource;
75 }
76
77 public List getModules() {
78 return modules;
79 }
80
81 public void addModule(ModuleNode node) {
82 modules.add(node);
83 node.setUnit(this);
84 addClasses(node.classes);
85 }
86
87 /***
88 * @return the ClassNode for the given qualified name or returns null if
89 * the name does not exist in the current compilation unit
90 * (ignoring the .class files on the classpath)
91 */
92 public ClassNode getClass(String name) {
93 return (ClassNode) classes.get(name);
94 }
95
96 /***
97 * @return a list of all the classes in each module in the compilation unit
98 */
99 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
148 }
149
150 try {
151 ClassLoader loader = Thread.currentThread().getContextClassLoader();
152 if ( answer == null && loader != lastLoader
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
164 }
165
166
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
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
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())) {
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 }