001    /*
002     * $Id: CompileUnit.java,v 1.17 2005/11/21 00:40:00 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 groovy.lang.GroovyClassLoader;
038    
039    import java.security.CodeSource;
040    import java.util.ArrayList;
041    import java.util.HashMap;
042    import java.util.Iterator;
043    import java.util.List;
044    import java.util.Map;
045    
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.17 $
054     */
055    public class CompileUnit {
056    
057        private List modules = new ArrayList();
058        private Map classes = new HashMap();
059        private CompilerConfiguration config;
060        private GroovyClassLoader classLoader;
061        private CodeSource codeSource;
062        private Map classesToCompile = new HashMap();
063        
064        public CompileUnit(GroovyClassLoader classLoader, CompilerConfiguration config) {
065            this(classLoader, null, config);
066        }
067        
068        public CompileUnit(GroovyClassLoader classLoader, CodeSource codeSource, CompilerConfiguration config) {
069            this.classLoader = classLoader;
070            this.config = config;
071            this.codeSource = codeSource;
072        }
073    
074        public List getModules() {
075            return modules;
076        }
077    
078        public void addModule(ModuleNode node) {
079            // node==null means a compilation error prevented
080            // groovy from building an ast
081            if (node==null) return;
082            modules.add(node);
083            node.setUnit(this);
084            addClasses(node.getClasses());
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            ClassNode cn = (ClassNode) classes.get(name);
094            if (cn!=null) return cn;
095            return (ClassNode) classesToCompile.get(name);
096        }
097    
098        /**
099         * @return a list of all the classes in each module in the compilation unit
100         */
101        public List getClasses() {
102            List answer = new ArrayList();
103            for (Iterator iter = modules.iterator(); iter.hasNext();) {
104                ModuleNode module = (ModuleNode) iter.next();
105                answer.addAll(module.getClasses());
106            }
107            return answer;
108        }
109    
110        public CompilerConfiguration getConfig() {
111            return config;
112        }
113    
114        public GroovyClassLoader getClassLoader() {
115            return classLoader;
116        }
117        
118        public CodeSource getCodeSource() {
119            return codeSource;
120        }
121    
122        /**
123         * Appends all of the fully qualified class names in this
124         * module into the given map
125         */
126        void addClasses(List classList) {
127            for (Iterator iter = classList.iterator(); iter.hasNext();) {
128                addClass((ClassNode) iter.next());
129            }
130        }
131        
132        /**
133         *  Adds a class to the unit.
134         */
135        public void addClass(ClassNode node) {
136            node = node.redirect();
137            String name = node.getName();
138            Object stored = classes.get(name);
139            if (stored != null && stored != node) {
140                throw new RuntimeException(
141                    "Error: duplicate class declaration for name: " + name + " and class: " + node);
142            }
143            classes.put(name, node);
144            
145            if (classesToCompile.containsKey(name)) {
146                ClassNode cn = (ClassNode) classesToCompile.get(name);
147                cn.setRedirect(node);
148                classesToCompile.remove(name);
149            }        
150        }
151         
152        /**
153         * this emthod actually does not compile a class. It's only
154         * a marker that this type has to be compiled by the CompilationUnit
155         * at the end of a parse step no node should be be left.
156         */
157        public void addClassNodeToCompile(ClassNode node) {
158            classesToCompile.put(node.getName(),node);
159        }
160    
161        public boolean hasClassNodeToCompile(){
162            return classesToCompile.size()!=0;
163        }
164    }