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    }