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 groovy.lang.GroovyCodeSource;
021    import groovy.lang.GroovyResourceLoader;
022    import org.codehaus.gmaven.feature.Component;
023    import org.codehaus.gmaven.feature.ComponentException;
024    import org.codehaus.gmaven.feature.support.ComponentSupport;
025    import org.codehaus.gmaven.feature.support.FeatureSupport;
026    import org.codehaus.gmaven.runtime.ClassFactory;
027    import org.codehaus.gmaven.runtime.support.util.ResourceLoaderImpl;
028    import org.codehaus.gmaven.runtime.util.ClassSource;
029    import org.codehaus.gmaven.runtime.util.ResourceLoader;
030    
031    import java.io.IOException;
032    import java.net.MalformedURLException;
033    import java.net.URL;
034    
035    /**
036     * Provides the class factory feature.
037     *
038     * @version $Id: ClassFactoryFeature.java 52 2009-11-22 10:32:14Z user57 $
039     * @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
040     */
041    public class ClassFactoryFeature
042        extends FeatureSupport
043    {
044        public ClassFactoryFeature() {
045            super(ClassFactory.KEY);
046        }
047    
048        @Override
049        protected Component doCreate() throws Exception {
050            return new ClassFactoryImpl();
051        }
052    
053        //
054        // ClassFactoryImpl
055        //
056    
057        private class ClassFactoryImpl
058            extends ComponentSupport
059            implements ClassFactory
060        {
061            private ClassFactoryImpl() {
062                super(ClassFactoryFeature.this);
063            }
064    
065            public Class create(final ClassSource classSource, final ClassLoader classLoader, final ResourceLoader resourceLoader) throws Exception {
066                assert classSource != null;
067                assert classLoader != null;
068                // resourceLoader can be null
069    
070                GroovyClassLoader groovyClassLoader = createGroovyClassLoader(classLoader, resourceLoader);
071    
072                GroovyCodeSource codeSource = createGroovyCodeSource(classSource);
073    
074                return groovyClassLoader.parseClass(codeSource);
075            }
076    
077            public Class create(final ClassSource classSource, final ClassLoader classLoader) throws Exception {
078                return create(classSource, classLoader, null);
079            }
080    
081            public Class create(final String className, final ClassLoader classLoader, ResourceLoader resourceLoader) throws Exception {
082                assert className != null;
083                assert classLoader != null;
084                // resourceLoader can be null
085    
086                if (resourceLoader == null) {
087                    resourceLoader = new ResourceLoaderImpl(classLoader);
088                }
089    
090                URL source = resourceLoader.loadResource(className);
091    
092                if (source == null) {
093                    throw new ComponentException("Missing source for: " + className);
094                }
095                
096                return create(new ClassSource(source), classLoader, resourceLoader);
097            }
098    
099            public Class create(final String className, final ClassLoader classLoader) throws Exception {
100                return create(className, classLoader, null);
101            }
102            
103            private GroovyClassLoader createGroovyClassLoader(final ClassLoader classLoader, final ResourceLoader resourceLoader) {
104                assert classLoader != null;
105                // resourceLoader can be null
106    
107                GroovyClassLoader groovyClassLoader = new GroovyClassLoader(classLoader);
108    
109                groovyClassLoader.setResourceLoader(createGroovyResourceLoader(classLoader, resourceLoader));
110    
111                return groovyClassLoader;
112            }
113    
114            private GroovyResourceLoader createGroovyResourceLoader(final ClassLoader classLoader, ResourceLoader resourceLoader) {
115                assert classLoader != null;
116                // resourceLoader can be null
117    
118                if (resourceLoader == null) {
119                    resourceLoader = new ResourceLoaderImpl(classLoader);
120                }
121    
122                return new GroovyResourceLoaderAdapter(resourceLoader);
123            }
124    
125            private GroovyCodeSource createGroovyCodeSource(final ClassSource source) throws IOException {
126                assert source != null;
127    
128                int count = 0;
129    
130                if (source.url != null) {
131                    count++;
132                }
133    
134                if (source.file != null) {
135                    count++;
136                }
137    
138                if (source.body != null) {
139                    count++;
140                }
141    
142                if (count == 0) {
143                    throw new ComponentException("Invalid class source; must define a URL, File or Body: " + source);
144                }
145    
146                if (count != 1) {
147                    throw new ComponentException("Invalid class source; only one of URL, File or Body is allowed: " + source);
148                }
149    
150                if (source.url != null) {
151                    return new GroovyCodeSource(source.url);
152                }
153    
154                if (source.file != null) {
155                    return new GroovyCodeSource(source.file);
156                }
157    
158                if (source.body != null) {
159                    return new GroovyCodeSource(source.body.input, source.body.name, source.body.codeBase);
160                }
161    
162                throw new InternalError();
163            }
164        }
165    
166        //
167        // GroovyResourceLoaderAdapter
168        //
169    
170        private class GroovyResourceLoaderAdapter
171            implements GroovyResourceLoader
172        {
173            private final ResourceLoader loader;
174    
175            public GroovyResourceLoaderAdapter(final ResourceLoader loader) {
176                assert loader != null;
177    
178                this.loader = loader;
179            }
180    
181            public URL loadGroovySource(final String name) throws MalformedURLException {
182                return loader.loadResource(name);
183            }
184        }
185    }