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_7;
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            private void configure() {
068                cc.setVerbose(config.get(VERBOSE, false));
069    
070                cc.setDebug(config.get(DEBUG, false));
071    
072                if (config.contains(TOLERANCE)) {
073                    cc.setTolerance(config.get(TOLERANCE, 0));
074                }
075                
076                if (config.contains(TARGET_BYTECODE)) {
077                    cc.setTargetBytecode(config.get(TARGET_BYTECODE, (String)null));
078                }
079    
080                if (config.contains(SCRIPT_BASE_CLASSNAME)) {
081                    cc.setScriptBaseClass(config.get(SCRIPT_BASE_CLASSNAME, (String)null));
082                }
083    
084                if (config.contains(DEFAULT_SCRIPT_EXTENSION)) {
085                    cc.setDefaultScriptExtension(config.get(DEFAULT_SCRIPT_EXTENSION, (String)null));
086                }
087                
088                if (config.contains(WARNING_LEVEL)) {
089                    cc.setTolerance(config.get(WARNING_LEVEL, 0));
090                }
091                
092                if (config.contains(SOURCE_ENCODING)) {
093                    cc.setSourceEncoding(config.get(SOURCE_ENCODING, (String)null));
094                }
095            }
096    
097            public int compile() throws Exception {
098                if (sources.isEmpty()) {
099                    log.debug("No sources added to compile; skipping");
100    
101                    return 0;
102                }
103    
104                configure();
105                cc.setTargetDirectory(getTargetDirectory().getCanonicalPath());
106    
107                //
108                // NOTE: Do not use the CL from this class or it will mess up resolution
109                //       when using classes from groovy* which depend on other artifacts,
110                //       also don't really want to pollute the classpath with our dependencies.
111                //
112    
113                ClassLoader parent = ClassLoader.getSystemClassLoader();
114    
115                GroovyClassLoader gcl = new GroovyClassLoader(parent, cc);
116    
117                log.debug("Classpath:");
118    
119                // Append each URL to the GCL
120                URL[] classpath = getClassPath();
121                
122                for (int i=0; i<classpath.length; i++) {
123                    gcl.addURL(classpath[i]);
124    
125                    log.debug("    {}", classpath[i]);
126                }
127    
128                //
129                // TODO: See if we should set the CodeSource to something?
130                //
131                
132                CodeSource security = null;
133                GroovyClassLoader transformLoader = new GroovyClassLoader(getClass().getClassLoader());
134                for (int i=0; i<classpath.length; i++) {
135                    transformLoader.addURL(classpath[i]);
136                }
137              
138                CompilationUnit cu = new CompilationUnit(cc, security, gcl, transformLoader);
139                log.debug("Compiling {} sources", String.valueOf(sources.size()));
140    
141                for (Iterator iter = sources.iterator(); iter.hasNext();) {
142                    URL url = (URL) iter.next();
143                    log.debug("    {}", url);
144    
145                    cu.addSource(url);
146                }
147    
148                cu.compile();
149    
150                List classes = cu.getClasses();
151    
152                if (log.isDebugEnabled()) {
153                    log.debug("Compiled {} classes:", String.valueOf(classes.size()));
154    
155                    for (Iterator iter = classes.iterator(); iter.hasNext();) {
156                        log.debug("    {}", ((GroovyClass)iter.next()).getName());
157                    }
158                }
159    
160                return classes.size();
161            }
162        }
163    }