001/**
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.xbean.maven;
018
019import java.beans.PropertyEditorManager;
020import java.io.File;
021import java.net.MalformedURLException;
022import java.net.URL;
023import java.net.URLClassLoader;
024import java.util.ArrayList;
025import java.util.Arrays;
026import java.util.Collections;
027import java.util.HashSet;
028import java.util.Iterator;
029import java.util.LinkedList;
030import java.util.List;
031import java.util.Set;
032import java.util.StringTokenizer;
033
034import org.apache.maven.artifact.Artifact;
035import org.apache.maven.model.Resource;
036import org.apache.maven.plugin.AbstractMojo;
037import org.apache.maven.plugin.MojoExecutionException;
038import org.apache.maven.plugin.MojoFailureException;
039import org.apache.maven.project.MavenProject;
040import org.apache.maven.project.MavenProjectHelper;
041import org.apache.tools.ant.BuildException;
042import org.apache.xbean.spring.generator.DocumentationGenerator;
043import org.apache.xbean.spring.generator.GeneratorPlugin;
044import org.apache.xbean.spring.generator.LogFacade;
045import org.apache.xbean.spring.generator.MappingLoader;
046import org.apache.xbean.spring.generator.NamespaceMapping;
047import org.apache.xbean.spring.generator.QdoxMappingLoader;
048import org.apache.xbean.spring.generator.WikiDocumentationGenerator;
049import org.apache.xbean.spring.generator.XmlMetadataGenerator;
050import org.apache.xbean.spring.generator.XsdGenerator;
051
052/**
053 * @author <a href="gnodet@apache.org">Guillaume Nodet</a>
054 * @version $Id: GenerateApplicationXmlMojo.java 314956 2005-10-12 16:27:15Z brett $
055 * @goal mapping
056 * @description Creates xbean mapping file
057 * @phase generate-sources
058 * @requiresDependencyResolution compile
059 */
060public class XBeanMojo extends AbstractMojo implements LogFacade {
061
062    /**
063     * @parameter expression="${project}"
064     * @required
065     */
066    private MavenProject project;
067
068    /**
069     * Maven ProjectHelper
070     *
071     * @component
072     */
073    protected MavenProjectHelper projectHelper;
074
075    /**
076     * @parameter
077     * @required
078     */
079    private String namespace;
080
081    /**
082     * @parameter expression="${basedir}/src/main/java"
083     * @required
084     */
085    private File srcDir;
086
087    /**
088     * @parameter
089     */
090    private List<String> includes;
091
092    /**
093     * @parameter
094     */
095    private List<String> classPathIncludes;
096
097    /**
098     * @parameter
099     */
100    private String excludedClasses;
101
102    /**
103     * @parameter expression="${basedir}/target/xbean/"
104     * @required
105     */
106    private File outputDir;
107
108    /**
109     * @parameter
110     */
111    private File schema;
112
113    /**
114     * @parameter expression="org.apache.xbean.spring.context.impl"
115     */
116    private String propertyEditorPaths;
117
118    /**
119     * @parameter schemaAsArtifact
120     */
121    private boolean schemaAsArtifact = true;
122    
123    /**
124     * @parameter 
125     */
126    private boolean generateSpringSchemasFile = true;
127
128    /**
129     * @parameter 
130     */
131    private boolean generateSpringHandlersFile = true;
132
133    /**
134     * @parameter
135     */
136    private boolean strictXsdOrder = true;
137
138    /**
139     * A list of additional GeneratorPlugins that should get used executed
140     * when generating output.
141     *
142     * @parameter
143     */
144    private List<GeneratorPlugin> generatorPlugins = Collections.emptyList();
145
146    public void execute() throws MojoExecutionException, MojoFailureException {
147        getLog().debug( " ======= XBeanMojo settings =======" );
148        getLog().debug( "namespace[" + namespace + "]" );
149        getLog().debug( "srcDir[" + srcDir + "]" );
150        getLog().debug( "schema[" + schema + "]" );
151        getLog().debug( "excludedClasses[" + excludedClasses + "]");
152        getLog().debug( "outputDir[" + outputDir + "]" );
153        getLog().debug( "propertyEditorPaths[" + propertyEditorPaths + "]" );
154        getLog().debug( "schemaAsArtifact[" + schemaAsArtifact + "]");
155        getLog().debug( "generateSpringSchemasFile[" + generateSpringSchemasFile + "]");
156        getLog().debug( "generateSpringHandlersFile[" + generateSpringHandlersFile + "]");
157        
158        if (schema == null) {
159            schema = new File(outputDir, project.getArtifactId() + ".xsd");
160        }
161
162        if (propertyEditorPaths != null) {
163            List<String> editorSearchPath = new LinkedList<String>(Arrays.asList(PropertyEditorManager.getEditorSearchPath()));
164            for (StringTokenizer paths = new StringTokenizer(propertyEditorPaths, " ,"); paths.hasMoreElements(); ) {
165                //StringTokenizer implements Enumeration<Object>, not Enumeration<String> !!
166                editorSearchPath.add((String) paths.nextElement());
167            }
168            PropertyEditorManager.setEditorSearchPath( editorSearchPath.toArray(new String[editorSearchPath.size()]));
169        }
170
171        ClassLoader oldCL = Thread.currentThread().getContextClassLoader();
172        Thread.currentThread().setContextClassLoader(getClass().getClassLoader());
173        try {
174            schema.getParentFile().mkdirs();
175
176            String[] excludedClasses = null;
177            if (this.excludedClasses != null) {
178                excludedClasses = this.excludedClasses.split(" *, *");
179            }
180            Set<Artifact> dependencies = project.getDependencyArtifacts();
181            List<File> sourceJars = new ArrayList<File>();
182            sourceJars.add(srcDir);
183            if( includes !=null ) {
184                for (String src : includes) {
185                    sourceJars.add(new File(src));
186                }
187            }
188            for (Artifact dependency : dependencies) {
189                if ("sources".equals(dependency.getClassifier())) {
190                    File file = dependency.getFile();
191                    sourceJars.add(file);
192                }
193            }
194            File[] srcJars = sourceJars.toArray(new File[sourceJars.size()]);
195            MappingLoader mappingLoader = new QdoxMappingLoader(namespace, srcJars, excludedClasses);
196            GeneratorPlugin[] plugins = new GeneratorPlugin[]{
197                new XmlMetadataGenerator(outputDir.getAbsolutePath(), schema, generateSpringSchemasFile, generateSpringHandlersFile),
198                new DocumentationGenerator(schema),
199                new XsdGenerator(schema, strictXsdOrder),
200                new WikiDocumentationGenerator(schema),
201            };
202
203            // load the mappings
204            Thread.currentThread().setContextClassLoader(getClassLoader());
205            Set<NamespaceMapping> namespaces = mappingLoader.loadNamespaces();
206            if (namespaces.isEmpty()) {
207                System.out.println("Warning: no namespaces found!");
208            }
209
210            // generate the files
211            for (NamespaceMapping namespaceMapping : namespaces) {
212                for (GeneratorPlugin plugin : plugins) {
213                    plugin.setLog(this);
214                    plugin.generate(namespaceMapping);
215                }
216                for (GeneratorPlugin plugin : generatorPlugins) {
217                    plugin.setLog(this);
218                    plugin.generate(namespaceMapping);
219                }
220            }
221
222            // Attach them as artifacts
223            if (schemaAsArtifact) {
224                projectHelper.attachArtifact(project, "xsd", null, schema);
225                projectHelper.attachArtifact(project, "html", "schema", new File(schema.getAbsolutePath() + ".html"));
226            }
227
228            Resource res = new Resource();
229            res.setDirectory(outputDir.toString());
230            project.addResource(res);
231
232            log("...done.");
233        } catch (Exception e) {
234            throw new BuildException(e);
235        } finally {
236            Thread.currentThread().setContextClassLoader(oldCL);
237        }
238    }
239
240    public void log(String message) {
241        getLog().info(message);
242    }
243
244    public void log(String message, int level) {
245        getLog().info(message);
246    }
247
248    protected URLClassLoader getClassLoader() throws MojoExecutionException {
249        try {
250            Set<URL> urls = new HashSet<URL>();
251
252            URL mainClasses = new File(project.getBuild().getOutputDirectory())
253                    .toURI().toURL();
254            getLog().debug("Adding to classpath : " + mainClasses);
255            urls.add(mainClasses);
256
257            URL testClasses = new File(project.getBuild()
258                    .getTestOutputDirectory()).toURI().toURL();
259            getLog().debug("Adding to classpath : " + testClasses);
260            urls.add(testClasses);
261
262            Set<Artifact> dependencies = project.getArtifacts();
263            for (Artifact classPathElement : dependencies) {
264                getLog().debug(
265                        "Adding artifact: " + classPathElement.getFile()
266                                + " to classpath");
267                urls.add(classPathElement.getFile().toURI().toURL());
268            }
269
270            if( classPathIncludes!=null ) {
271                for (String include : classPathIncludes) {
272                    final URL url = new File(include).toURI().toURL();
273                    getLog().debug("Adding to classpath : " + url);
274                    urls.add(url);
275                }
276            }
277
278            return new URLClassLoader(urls.toArray(new URL[urls.size()]),
279                    this.getClass().getClassLoader());
280        } catch (MalformedURLException e) {
281            throw new MojoExecutionException(
282                    "Error during setting up classpath", e);
283        }
284    }
285
286}