All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.codehaus.mojo.jaxb2.AbstractSchemagenMojo Maven / Gradle / Ivy

Go to download

Mojo's JAXB-2 Maven plugin is used to create an object graph from XSDs based on the JAXB 2.x implementation and to generate XSDs from JAXB annotated Java classes.

There is a newer version: 3.2.0
Show newest version
package org.codehaus.mojo.jaxb2;

/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.maven.artifact.DependencyResolutionRequiredException;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.project.MavenProject;
import org.codehaus.mojo.jaxb2.helpers.SchemagenHelper;
import org.codehaus.mojo.jaxb2.helpers.SimpleNamespaceResolver;
import org.codehaus.plexus.compiler.util.scan.InclusionScanException;
import org.codehaus.plexus.compiler.util.scan.SourceInclusionScanner;
import org.codehaus.plexus.compiler.util.scan.StaleSourceScanner;
import org.codehaus.plexus.compiler.util.scan.mapping.SingleTargetSourceMapping;
import org.codehaus.plexus.compiler.util.scan.mapping.SourceMapping;
import org.codehaus.plexus.util.FileUtils;
import org.codehaus.plexus.util.Scanner;
import org.codehaus.plexus.util.StringUtils;
import org.sonatype.plexus.build.incremental.BuildContext;
import org.sonatype.plexus.build.incremental.DefaultBuildContext;

import com.sun.tools.jxc.SchemaGenerator;

/**
 * @author rfscholte
 * @since 1.3
 */
public abstract class AbstractSchemagenMojo
    extends AbstractMojo
{
    /**
     * Name of the generated schema file, emitted by the SchemaGenerator. 
* According to the JAXB Schema Generator documentation: * "There is no way to control the name of the generated schema files at this time." */ private static final String SCHEMAGEN_EMITTED_FILENAME = "schema1.xsd"; /** * @component */ private BuildContext buildContext; /** * The default maven project object. * * @parameter expression="${project}" * @required * @readonly */ private MavenProject project; /** * A List holding desired schema mappings, each of which binds a schema namespace URI to its desired prefix * [optional] and the name of the resulting schema file [optional]. All given elements (uri, prefix, file) must be * unique within the configuration; no two elements may have the same values. *

*

*

* The example schema configuration below maps two namespace uris to prefixes and generated file names. This implies * that http://some/namespace will be represented by the prefix some within the generated XML * Schema files; creating namespace definitions on the form xmlns:some="http://some/namespace", and * corresponding uses on the form <xs:element minOccurs="0" * ref="some:anOptionalElementInSomeNamespace"/>. Moreover, the file element defines that the * http://some/namespace definitions will be written to the file some_schema.xsd, and that all * import references will be on the form <xs:import namespace="http://some/namespace" * schemaLocation="some_schema.xsd"/> *

*

*

* The example configuration below also performs identical operations for the namespace uri * http://another/namespace with the prefix another and the file another_schema.xsd. *

*

* *

     * <schemas>
     *   <schema>
     *     <uri>http://some/namespace</uri>
     *     <toPrefix>some</toPrefix>
     *     <toFile>some_schema.xsd</toFile>
     *   <schema>
     *     <uri>http://another/namespace</uri>
     *     <toPrefix>another</toPrefix>
     *     <toFile>another_schema.xsd</toFile>
     *   </schema>
     * </schemas>
     * 
* * @parameter * @since 1.4 */ private List transformSchemas; /** * A list of inclusion filters for the generator. At least one file has to be specified. * * @parameter * @required */ private Set includes = new HashSet(); /** * A list of exclusion filters for the generator. * * @parameter */ private Set excludes = new HashSet(); /** * The granularity in milliseconds of the last modification date for testing whether a source needs recompilation. * * @parameter expression="${lastModGranularityMs}" default-value="0" */ private int staleMillis; public void execute() throws MojoExecutionException, MojoFailureException { if ( getLog().isDebugEnabled() ) { Package jaxbImplPackage = SchemaGenerator.class.getPackage(); getLog().debug( "Using SchemaGen of " + jaxbImplPackage.getImplementationTitle() + " version " + jaxbImplPackage.getImplementationVersion() ); } if ( "pom".equals( project.getPackaging() ) ) { return; } if ( includes.isEmpty() ) { throw new MojoExecutionException( "At least one file has to be included" ); } if ( isOutputStale() ) { String includePaths = StringUtils.join( includes.toArray(), "," ); String excludePaths = StringUtils.join( excludes.toArray(), "," ); Set includedSources = new HashSet(); for ( String path : getCompileSourceRoots() ) { File sourceDir = new File( path ); if ( sourceDir.exists() && sourceDir.isDirectory() ) { try { includedSources.addAll( FileUtils.getFileNames( sourceDir, includePaths, excludePaths, true ) ); } catch ( IOException e ) { throw new MojoExecutionException( "Error retrieving files in: \'" + sourceDir + "\' ", e ); } } else { getLog().info( "Source directory \'" + sourceDir + "\' doesn't exist. Ignoring directory in schema generation." ); } } List args = new ArrayList(); StringBuilder classPath = new StringBuilder(); try { List classpathFiles = getClasspathElements( project ); classPath = new StringBuilder(); for ( String classpathFile : classpathFiles ) { classPath.append( classpathFile ); classPath.append( File.pathSeparatorChar ); } } catch ( DependencyResolutionRequiredException e ) { throw new MojoExecutionException( e.getMessage(), e ); } if ( !getOutputDirectory().exists() && !getOutputDirectory().mkdirs() ) { throw new MojoExecutionException( "Could not create directory " + getOutputDirectory().getAbsolutePath() ); } try { args.add( "-d" ); args.add( getOutputDirectory().getAbsolutePath() ); args.add( "-classpath" ); args.add( classPath.toString() ); args.addAll( includedSources ); if ( getLog().isDebugEnabled() ) { getLog().debug( "Args for SchemaGenerator: " + args ); } SchemaGenerator.run( args.toArray( new String[0] ) ); } catch ( Exception e ) { throw new MojoExecutionException( "Failed to generate schema", e ); } if ( transformSchemas != null ) { // Check configuration - we cannot have duplicate namespace URI, prefix or file. SchemagenHelper.validateSchemasInPluginConfiguration( transformSchemas ); if ( hasRenamingSchemas() ) { try { FileUtils.copyDirectory( getOutputDirectory(), getWorkDirectory() ); } catch ( IOException e ) { throw new MojoExecutionException( e.getMessage() ); } } // Acquire resolvers for all generated files. final Map resolverMap = SchemagenHelper.getFileNameToResolverMap( getOutputDirectory() ); // Transform all namespace prefixes as requested. SchemagenHelper.replaceNamespacePrefixes( resolverMap, transformSchemas, getLog(), getOutputDirectory() ); // Rename all generated schema files as requested. SchemagenHelper.renameGeneratedSchemaFiles( resolverMap, transformSchemas, getLog(), getOutputDirectory() ); } buildContext.refresh( getOutputDirectory() ); } else { getLog().info( "No updated sources found - skipping schema generation." ); } } /** * Checks if there have been any changes to the sources since the last build and therefore the generated files are * not up-to-date and need to be re-generated. */ private boolean isOutputStale() throws MojoExecutionException { if ( buildContext instanceof DefaultBuildContext ) { // Here we can't use the buildContext to determine if everything is up-to-date, as // DefaultBuildContext behaves as if all files were just created. return commandLineStalenessCheck(); } else { return buildContextStalenessCheck(); } } private boolean commandLineStalenessCheck() throws MojoExecutionException { SourceInclusionScanner staleSourceScanner = new StaleSourceScanner( staleMillis, includes, excludes ); SourceMapping mapping = new SingleTargetSourceMapping( ".java", SCHEMAGEN_EMITTED_FILENAME ); staleSourceScanner.addSourceMapping( mapping ); // Look inside every compileSourceRoot for ( String path : getCompileSourceRoots() ) { File sourceDir = new File( path ); try { Set includedSources = staleSourceScanner.getIncludedSources( sourceDir, getOutputDirectory() ); if ( !includedSources.isEmpty() ) { return true; } } catch ( InclusionScanException e ) { throw new MojoExecutionException( "Error scanning source root: \'" + sourceDir + "\' " + "for stale files to recompile.", e ); } } return false; } private boolean buildContextStalenessCheck() { String[] includesArray = this.includes.toArray( new String[0] ); String[] excludesArray = this.excludes.toArray( new String[0] ); // Check for modified files for ( String path : getCompileSourceRoots() ) { File sourceDir = new File( path ); Scanner modifiedScanner = this.buildContext.newScanner( sourceDir ); modifiedScanner.setIncludes( includesArray ); modifiedScanner.setExcludes( excludesArray ); modifiedScanner.scan(); String[] includedFiles = modifiedScanner.getIncludedFiles(); if ( includedFiles.length != 0 ) { return true; } } // Check for deleted files for ( String path : getCompileSourceRoots() ) { File sourceDir = new File( path ); Scanner deletedScanner = this.buildContext.newDeleteScanner( sourceDir ); deletedScanner.setIncludes( includesArray ); deletedScanner.setExcludes( excludesArray ); deletedScanner.scan(); String[] includedFiles = deletedScanner.getIncludedFiles(); if ( includedFiles.length != 0 ) { return true; } } return false; } /** * Check if any schema will be renamed. * * @return {@code true} if a schema will be renamed, otherwise {@code false} */ private boolean hasRenamingSchemas() { if ( transformSchemas != null ) { for ( TransformSchema schema : transformSchemas ) { if ( schema.getToFile() != null ) { return true; } } } return false; } /** * @return The directory where the schema files should be placed. */ protected abstract File getOutputDirectory(); /** * If files will be renamed, keep the original files here. * * @return the work directory */ protected abstract File getWorkDirectory(); protected abstract List getCompileSourceRoots(); protected abstract List getClasspathElements( MavenProject project ) throws DependencyResolutionRequiredException; }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy