001    /*
002     * Copyright (C) 2006-2007 the original author or authors.
003     *
004     * Licensed under the Apache License, Version 2.0 (the "License");
005     * you may not use this file except in compliance with the License.
006     * You may obtain a copy of the License at
007     *
008     *     http://www.apache.org/licenses/LICENSE-2.0
009     *
010     * Unless required by applicable law or agreed to in writing, software
011     * distributed under the License is distributed on an "AS IS" BASIS,
012     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013     * See the License for the specific language governing permissions and
014     * limitations under the License.
015     */
016    
017    package org.codehaus.gmaven.runtime.v1_5;
018    
019    import groovy.lang.GroovyClassLoader;
020    import org.codehaus.gmaven.feature.Component;
021    import org.codehaus.gmaven.feature.support.FeatureSupport;
022    import org.codehaus.gmaven.runtime.ClassCompiler;
023    import org.codehaus.gmaven.runtime.support.CompilerSupport;
024    import org.codehaus.groovy.control.CompilationUnit;
025    import org.codehaus.groovy.control.CompilerConfiguration;
026    import org.codehaus.groovy.tools.GroovyClass;
027    
028    import java.net.URL;
029    import java.security.CodeSource;
030    import java.util.Iterator;
031    import java.util.List;
032    
033    /**
034     * Provides the class compilation feature.
035     *
036     * @version $Id: ClassCompilerFeature.java 91 2010-07-05 21:06:12Z user57 $
037     * @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
038     */
039    public class ClassCompilerFeature
040        extends FeatureSupport
041    {
042        public ClassCompilerFeature() {
043            super(ClassCompiler.KEY);
044        }
045    
046        protected Component doCreate() throws Exception {
047            return new ClassCompilerImpl();
048        }
049    
050        //
051        // ClassCompilerImpl
052        //
053        
054        private class ClassCompilerImpl
055            extends CompilerSupport
056            implements ClassCompiler, ClassCompiler.Keys
057        {
058            private final CompilerConfiguration cc = new CompilerConfiguration();
059    
060            private URL[] classPath;
061    
062            private ClassCompilerImpl() throws Exception {
063                super(ClassCompilerFeature.this);
064            }
065    
066            private void configure() {
067                cc.setVerbose(config.get(VERBOSE, false));
068    
069                cc.setDebug(config.get(DEBUG, false));
070    
071                if (config.contains(TOLERANCE)) {
072                    cc.setTolerance(config.get(TOLERANCE, 0));
073                }
074                
075                if (config.contains(TARGET_BYTECODE)) {
076                    cc.setTargetBytecode(config.get(TARGET_BYTECODE, (String)null));
077                }
078    
079                if (config.contains(SCRIPT_BASE_CLASSNAME)) {
080                    cc.setScriptBaseClass(config.get(SCRIPT_BASE_CLASSNAME, (String)null));
081                }
082    
083                if (config.contains(DEFAULT_SCRIPT_EXTENSION)) {
084                    cc.setDefaultScriptExtension(config.get(DEFAULT_SCRIPT_EXTENSION, (String)null));
085                }
086                
087                if (config.contains(WARNING_LEVEL)) {
088                    cc.setTolerance(config.get(WARNING_LEVEL, 0));
089                }
090                
091                if (config.contains(SOURCE_ENCODING)) {
092                    cc.setSourceEncoding(config.get(SOURCE_ENCODING, (String)null));
093                }
094            }
095    
096            public void setClassPath(final URL[] urls) {
097                assert urls != null && urls.length > 0;
098    
099                this.classPath = urls;
100            }
101    
102            public URL[] getClassPath() {
103                if (classPath == null || classPath.length == 0) {
104                    throw new IllegalStateException("Classpath not bound, or is empty");
105                }
106                
107                return classPath;
108            }
109    
110            public int compile() throws Exception {
111                if (sources.isEmpty()) {
112                    log.debug("No sources added to compile; skipping");
113    
114                    return 0;
115                }
116    
117                configure();
118                cc.setTargetDirectory(getTargetDirectory().getCanonicalPath());
119    
120                //
121                // NOTE: Do not use the CL from this class or it will mess up resolution
122                //       when using classes from groovy* which depend on other artifacts,
123                //       also don't really want to pollute the classpath with our dependencies.
124                //
125    
126                ClassLoader parent = ClassLoader.getSystemClassLoader();
127    
128                GroovyClassLoader gcl = new GroovyClassLoader(parent, cc);
129    
130                log.debug("Classpath:");
131    
132                // Append each URL to the GCL
133                URL[] classpath = getClassPath();
134                
135                for (int i=0; i<classpath.length; i++) {
136                    gcl.addURL(classpath[i]);
137    
138                    log.debug("    {}", classpath[i]);
139                }
140    
141                //
142                // TODO: See if we should set the CodeSource to something?
143                //
144                
145                CodeSource security = null;
146                
147                CompilationUnit cu = new CompilationUnit(cc, security, gcl);
148    
149                log.debug("Compiling {} sources", String.valueOf(sources.size()));
150    
151                for (Iterator iter = sources.iterator(); iter.hasNext();) {
152                    URL url = (URL) iter.next();
153                    log.debug("    {}", url);
154    
155                    cu.addSource(url);
156                }
157    
158                cu.compile();
159    
160                List classes = cu.getClasses();
161    
162                if (log.isDebugEnabled()) {
163                    log.debug("Compiled {} classes:", String.valueOf(classes.size()));
164    
165                    for (Iterator iter = classes.iterator(); iter.hasNext();) {
166                        log.debug("    {}", ((GroovyClass)iter.next()).getName());
167                    }
168                }
169    
170                return classes.size();
171            }
172        }
173    }