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 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        protected Component doCreate() throws Exception {
049            return new ClassFactoryImpl();
050        }
051    
052        //
053        // ClassFactoryImpl
054        //
055    
056        private class ClassFactoryImpl
057            extends ComponentSupport
058            implements ClassFactory
059        {
060            private ClassFactoryImpl() {
061                super(ClassFactoryFeature.this);
062            }
063    
064            public Class create(final ClassSource classSource, final ClassLoader classLoader, final ResourceLoader resourceLoader) throws Exception {
065                assert classSource != null;
066                assert classLoader != null;
067                // resourceLoader can be null
068    
069                GroovyClassLoader groovyClassLoader = createGroovyClassLoader(classLoader, resourceLoader);
070    
071                GroovyCodeSource codeSource = createGroovyCodeSource(classSource);
072    
073                return groovyClassLoader.parseClass(codeSource);
074            }
075    
076            public Class create(final ClassSource classSource, final ClassLoader classLoader) throws Exception {
077                return create(classSource, classLoader, null);
078            }
079    
080            public Class create(final String className, final ClassLoader classLoader, ResourceLoader resourceLoader) throws Exception {
081                assert className != null;
082                assert classLoader != null;
083                // resourceLoader can be null
084    
085                if (resourceLoader == null) {
086                    resourceLoader = new ResourceLoaderImpl(classLoader);
087                }
088    
089                URL source = resourceLoader.loadResource(className);
090    
091                if (source == null) {
092                    throw new ComponentException("Missing source for: " + className);
093                }
094                
095                return create(new ClassSource(source), classLoader, resourceLoader);
096            }
097    
098            public Class create(final String className, final ClassLoader classLoader) throws Exception {
099                return create(className, classLoader, null);
100            }
101            
102            private GroovyClassLoader createGroovyClassLoader(final ClassLoader classLoader, final ResourceLoader resourceLoader) {
103                assert classLoader != null;
104                // resourceLoader can be null
105    
106                GroovyClassLoader groovyClassLoader = new GroovyClassLoader(classLoader);
107    
108                groovyClassLoader.setResourceLoader(createGroovyResourceLoader(classLoader, resourceLoader));
109    
110                return groovyClassLoader;
111            }
112    
113            private GroovyResourceLoader createGroovyResourceLoader(final ClassLoader classLoader, ResourceLoader resourceLoader) {
114                assert classLoader != null;
115                // resourceLoader can be null
116    
117                if (resourceLoader == null) {
118                    resourceLoader = new ResourceLoaderImpl(classLoader);
119                }
120    
121                return new GroovyResourceLoaderAdapter(resourceLoader);
122            }
123    
124            private GroovyCodeSource createGroovyCodeSource(final ClassSource source) throws IOException {
125                assert source != null;
126    
127                int count = 0;
128    
129                if (source.url != null) {
130                    count++;
131                }
132    
133                if (source.file != null) {
134                    count++;
135                }
136    
137                if (source.body != null) {
138                    count++;
139                }
140    
141                if (count == 0) {
142                    throw new ComponentException("Invalid class source; must define a URL, File or Body: " + source);
143                }
144    
145                if (count != 1) {
146                    throw new ComponentException("Invalid class source; only one of URL, File or Body is allowed: " + source);
147                }
148    
149                if (source.url != null) {
150                    return new GroovyCodeSource(source.url);
151                }
152    
153                if (source.file != null) {
154                    return new GroovyCodeSource(source.file);
155                }
156    
157                if (source.body != null) {
158                    return new GroovyCodeSource(source.body.input, source.body.name, source.body.codeBase);
159                }
160    
161                throw new InternalError();
162            }
163        }
164    
165        //
166        // GroovyResourceLoaderAdapter
167        //
168    
169        private class GroovyResourceLoaderAdapter
170            implements GroovyResourceLoader
171        {
172            private final ResourceLoader loader;
173    
174            public GroovyResourceLoaderAdapter(final ResourceLoader loader) {
175                assert loader != null;
176    
177                this.loader = loader;
178            }
179    
180            public URL loadGroovySource(final String name) throws MalformedURLException {
181                return loader.loadResource(name);
182            }
183        }
184    }