View Javadoc

1   /*
2    * $Id: CompileUnit.java,v 1.9 2004/07/10 03:31:38 bran 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.control.CompilerConfiguration;
45  
46  /***
47   * Represents the entire contents of a compilation step which consists of one
48   * or more {@link ModuleNode}instances
49   * 
50   * @author <a href="mailto:james@coredevelopers.net">James Strachan </a>
51   * @version $Revision: 1.9 $
52   */
53  public class CompileUnit {
54  
55      private List modules = new ArrayList();
56      private Map classes = new HashMap();
57      private CompilerConfiguration config;
58      private ClassLoader classLoader;
59      private CodeSource codeSource;
60      private Map cachedClasses = new HashMap();
61      
62      public static final Object NO_CLASS = new Object();
63      
64  
65      public CompileUnit(ClassLoader classLoader, CompilerConfiguration config) {
66      	this(classLoader, null, config);
67      }
68      
69      public CompileUnit(ClassLoader classLoader, CodeSource codeSource, CompilerConfiguration config) {
70          this.classLoader = classLoader;
71          this.config = config;
72          this.codeSource = codeSource;
73      }
74  
75      public List getModules() {
76          return modules;
77      }
78  
79      public void addModule(ModuleNode node) {
80          modules.add(node);
81          node.setUnit(this);
82          addClasses(node.classes);
83      }
84  
85      /***
86       * @return the ClassNode for the given qualified name or returns null if
87       *         the name does not exist in the current compilation unit
88       *         (ignoring the .class files on the classpath)
89       */
90      public ClassNode getClass(String name) {
91          return (ClassNode) classes.get(name);
92      }
93  
94      /***
95       * @return a list of all the classes in each module in the compilation unit
96       */
97      public List getClasses() {
98          List answer = new ArrayList();
99          for (Iterator iter = modules.iterator(); iter.hasNext();) {
100             ModuleNode module = (ModuleNode) iter.next();
101             answer.addAll(module.getClasses());
102         }
103         return answer;
104     }
105 
106     public CompilerConfiguration getConfig() {
107         return config;
108     }
109 
110     public ClassLoader getClassLoader() {
111         return classLoader;
112     }
113     
114     public CodeSource getCodeSource() {
115     	return codeSource;
116     }
117 
118     
119     /***
120      * Loads a class on the compile classpath so that it can be introspected
121      * 
122      * @param type
123      * @return @throws
124      *         ClassNotFoundException
125      */
126     public Class loadClass(String type) throws ClassNotFoundException {
127     	Object obj = cachedClasses.get(type);
128     	if ( obj == NO_CLASS ) {
129     		throw new ClassNotFoundException(type);
130     	}
131     	if ( obj != null) {
132     		return (Class)obj;
133     	}
134     	
135     	Class answer = null;
136     	ClassLoader lastLoader  = getClassLoader();
137     	try {
138     		answer = lastLoader.loadClass(type);
139     	} catch (ClassNotFoundException e) {
140     		// fall through
141     	}
142     	
143         try {
144             ClassLoader loader = Thread.currentThread().getContextClassLoader();
145         	if ( answer == null && loader != lastLoader /*&& loader != null*/) {
146                 lastLoader = loader;
147         		answer = loader.loadClass(type);
148         	}
149         }
150         catch (ClassNotFoundException e1) {
151             // fall through
152         }
153         
154         // lets try our class loader
155         try {
156             ClassLoader loader = getClass().getClassLoader();
157         	if ( answer == null && loader != lastLoader) {
158                 lastLoader = loader;
159         		answer = loader.loadClass(type);
160         	}
161         }
162         catch (ClassNotFoundException e2) {
163             // fall through
164         }
165         
166         try {
167         	if (answer == null ) {
168         		answer = Class.forName(type);
169         	}
170         }
171         catch (ClassNotFoundException e2) {
172             // fall through
173         }
174 
175         if ( answer == null ) {
176         	cachedClasses.put(type,NO_CLASS);
177         	throw new ClassNotFoundException(type);
178         } else {
179             if (!type.equals(answer.getName())) { // br case sensitive match
180                 cachedClasses.put(type,NO_CLASS);
181                 System.out.println("Mismatch: answer.getName() = " + answer.getName() + ", type = " + type);
182                 throw new ClassNotFoundException(type);
183             }
184             cachedClasses.put(type,answer);
185         }
186         
187         return answer;
188     }
189 
190 
191     /***
192      * Appends all of the fully qualified class names in this
193      * module into the given map
194      */
195     void addClasses(List classList) {
196         for (Iterator iter = classList.iterator(); iter.hasNext();) {
197             addClass((ClassNode) iter.next());
198         }
199     }
200     
201     /***
202      *  Adds a class to the unit.
203      */
204     public void addClass(ClassNode node) {
205         String name = node.getName();
206         if (classes.containsKey(name)) {
207             throw new RuntimeException(
208                 "Error: duplicate class declaration for name: " + name + " and class: " + node);
209         }
210         classes.put(name, node);
211     }
212 
213 }