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_6;
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        @Override
047        protected Component doCreate() throws Exception {
048            return new ClassCompilerImpl();
049        }
050    
051        //
052        // ClassCompilerImpl
053        //
054        
055        private class ClassCompilerImpl
056            extends CompilerSupport
057            implements ClassCompiler, ClassCompiler.Keys
058        {
059            private final CompilerConfiguration cc = new CompilerConfiguration();
060    
061            private URL[] classPath;
062    
063            private ClassCompilerImpl() throws Exception {
064                super(ClassCompilerFeature.this);
065    
066            }
067    
068            private void configure() {
069                cc.setVerbose(config.get(VERBOSE, false));
070    
071                cc.setDebug(config.get(DEBUG, false));
072    
073                if (config.contains(TOLERANCE)) {
074                    cc.setTolerance(config.get(TOLERANCE, 0));
075                }
076                
077                if (config.contains(TARGET_BYTECODE)) {
078                    cc.setTargetBytecode(config.get(TARGET_BYTECODE, (String)null));
079                }
080    
081                if (config.contains(SCRIPT_BASE_CLASSNAME)) {
082                    cc.setScriptBaseClass(config.get(SCRIPT_BASE_CLASSNAME, (String)null));
083                }
084    
085                if (config.contains(DEFAULT_SCRIPT_EXTENSION)) {
086                    cc.setDefaultScriptExtension(config.get(DEFAULT_SCRIPT_EXTENSION, (String)null));
087                }
088                
089                if (config.contains(WARNING_LEVEL)) {
090                    cc.setTolerance(config.get(WARNING_LEVEL, 0));
091                }
092                
093                if (config.contains(SOURCE_ENCODING)) {
094                    cc.setSourceEncoding(config.get(SOURCE_ENCODING, (String)null));
095                }
096            }
097    
098            public void setClassPath(final URL[] urls) {
099                assert urls != null && urls.length > 0;
100    
101                this.classPath = urls;
102            }
103    
104            public URL[] getClassPath() {
105                if (classPath == null || classPath.length == 0) {
106                    throw new IllegalStateException("Classpath not bound, or is empty");
107                }
108                
109                return classPath;
110            }
111    
112            public int compile() throws Exception {
113                if (sources.isEmpty()) {
114                    log.debug("No sources added to compile; skipping");
115    
116                    return 0;
117                }
118    
119                configure();
120                cc.setTargetDirectory(getTargetDirectory().getCanonicalPath());
121    
122                //
123                // NOTE: Do not use the CL from this class or it will mess up resolution
124                //       when using classes from groovy* which depend on other artifacts,
125                //       also don't really want to pollute the classpath with our dependencies.
126                //
127    
128                ClassLoader parent = ClassLoader.getSystemClassLoader();
129    
130                GroovyClassLoader gcl = new GroovyClassLoader(parent, cc);
131    
132                log.debug("Classpath:");
133    
134                // Append each URL to the GCL
135                URL[] classpath = getClassPath();
136                
137                for (int i=0; i<classpath.length; i++) {
138                    gcl.addURL(classpath[i]);
139    
140                    log.debug("    {}", classpath[i]);
141                }
142    
143                //
144                // TODO: See if we should set the CodeSource to something?
145                //
146                
147                CodeSource security = null;
148                GroovyClassLoader transformLoader = new GroovyClassLoader(getClass().getClassLoader());
149                for (int i=0; i<classpath.length; i++) {
150                    transformLoader.addURL(classpath[i]);
151                }
152              
153                CompilationUnit cu = new CompilationUnit(cc, security, gcl, transformLoader);
154                log.debug("Compiling {} sources", String.valueOf(sources.size()));
155    
156                for (Iterator iter = sources.iterator(); iter.hasNext();) {
157                    URL url = (URL) iter.next();
158                    log.debug("    {}", url);
159    
160                    cu.addSource(url);
161                }
162    
163                cu.compile();
164    
165                List classes = cu.getClasses();
166    
167                if (log.isDebugEnabled()) {
168                    log.debug("Compiled {} classes:", String.valueOf(classes.size()));
169    
170                    for (Iterator iter = classes.iterator(); iter.hasNext();) {
171                        log.debug("    {}", ((GroovyClass)iter.next()).getName());
172                    }
173                }
174    
175                return classes.size();
176            }
177        }
178    }