View Javadoc

1   /*
2    * $Id: CompileUnit.java,v 1.11 2005/06/13 10:23:23 blackdrag Exp $
3    * 
4    * Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
5    * 
6    * Redistribution and use of this software and associated documentation
7    * ("Software"), with or without modification, are permitted provided that the
8    * following conditions are met:
9    *  1. Redistributions of source code must retain copyright statements and
10   * notices. Redistributions must also contain a copy of this document.
11   *  2. Redistributions in binary form must reproduce the above copyright
12   * notice, this list of conditions and the following disclaimer in the
13   * documentation and/or other materials provided with the distribution.
14   *  3. The name "groovy" must not be used to endorse or promote products
15   * derived from this Software without prior written permission of The Codehaus.
16   * For written permission, please contact info@codehaus.org.
17   *  4. Products derived from this Software may not be called "groovy" nor may
18   * "groovy" appear in their names without prior written permission of The
19   * Codehaus. "groovy" is a registered trademark of The Codehaus.
20   *  5. Due credit should be given to The Codehaus - http://groovy.codehaus.org/
21   * 
22   * THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS ``AS IS'' AND ANY
23   * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
24   * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
25   * DISCLAIMED. IN NO EVENT SHALL THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR
26   * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27   * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
28   * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29   * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30   * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31   * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
32   * DAMAGE.
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            // 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 }