blob: 7186253975dd9b43eecf2bac12f672f5fe905dd7 [file] [log] [blame]
/**
* 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.
*/
// Package
///////////////
package org.apache.jena.tools.schemagen;
// Imports
///////////////
import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import jena.schemagen;
import jena.schemagen.SchemagenOptions.OPT;
import org.apache.jena.rdf.model.Resource ;
import org.apache.jena.rdf.model.ResourceFactory ;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.plugins.annotations.LifecyclePhase;
import org.apache.maven.plugins.annotations.Mojo;
import org.apache.maven.plugins.annotations.Parameter;
import org.codehaus.plexus.util.DirectoryScanner;
/**
* <p>Maven plugin to execute Jena schemagen as part of a Jena-based
* project build cycle
* </p>
*/
@Mojo(name="translate", defaultPhase=LifecyclePhase.GENERATE_SOURCES)
public class SchemagenMojo
extends AbstractMojo
{
/***********************************/
/* Constants */
/***********************************/
/** Default output location */
public static final String GENERATED_SOURCES = File.separator + "generated-sources";
/** Default pattern for includes */
/** Name of default options element */
public static final String DEFAULT_OPTIONS_ELEM = "default";
/***********************************/
/* Static variables */
/***********************************/
/***********************************/
/* Instance variables */
/***********************************/
/**
* @parameter property="project.build.directory"
*/
@Parameter(property="project.build.directory")
private String projectBuildDir;
/**
* Array of file patterns to include in processing
*/
@Parameter
private String[] includes = new String[0];
/**
* Array of file patterns to exclude from processing
*/
@Parameter
private String[] excludes = new String[0];
/**
* Options for individual files
*/
@Parameter
private List<Source> fileOptions;
/**
* The current base directory of the project
*/
@Parameter(property="basedir")
private File baseDir;
/** The default options object, if any */
private SchemagenOptions defaultOptions;
/** Map of source options, indexed by name */
private Map<String, SchemagenOptions> optIndex = new HashMap<>();
/***********************************/
/* Constructors */
/***********************************/
/***********************************/
/* External signature methods */
/***********************************/
@Override
public void execute() throws MojoExecutionException, MojoFailureException {
try {
// set the default defaults
defaultOptions = new SchemagenOptions(getDefaultOutputDir());
getLog().info( "Starting schemagen execute() ...");
// next process the various options specs
if( fileOptions != null ){
for (Source s: fileOptions) {
if (s.isDefaultOptions()) {
handleDefaultOptions( s );
}
else {
handleOption( s );
}
}
}
if( defaultOptions == null ){
handleDefaultOptions( new Source() );
}
// then the files themselves
for (String fileName: matchFileNames()) {
processFile( fileName );
}
} catch (SchemagenOptionsConfigurationException e) {
throw new MojoExecutionException(
"Error during default schemagen options creation", e);
}
}
/**
* Return a list of the file names to be processed by schemagen. These are
* determined by processing the Ant style paths given in the <code>includes</code>
* and <code>excludes</code> parameters.
*
* @return Non-null but possibly empty list of files to process, sorted into lexical order
*/
protected List<String> matchFileNames() {
DirectoryScanner ds = new DirectoryScanner();
ds.setExcludes( excludes );
ds.setIncludes( includes );
ds.setBasedir( getBaseDir() );
ds.scan();
List<String> files = new ArrayList<>( Arrays.asList( ds.getIncludedFiles() ) );
Collections.sort( files );
//add http includes
for( String include : includes ){
if( include.startsWith("http:") || include.startsWith("https:")){
files.add( include );
}
}
return files;
}
/**
* Return the default options structure, or null
* @return The default options
*/
protected SchemagenOptions getDefaultOptions() {
return defaultOptions;
}
/** Return the value of <code>${project.build.directory}</code> */
public String getProjectBuildDir() {
return projectBuildDir;
}
/**
* Handle the default options by creating a default options object and assigning
* the options values from the given source object.
* @param defOptionsSource The source object containing the default options
* @throws SchemagenOptionsConfigurationException
*/
protected void handleDefaultOptions( Source defOptionsSource )
throws SchemagenOptionsConfigurationException {
SchemagenOptions defSo = new SchemagenOptions(getDefaultOutputDir(),
defOptionsSource);
if (defaultOptions != null) {
defSo.setParent( defaultOptions );
}
defaultOptions = defSo;
}
/**
* Process the given options specification for one of the input files
* by attaching the default options and indexing.
*
* @param optionSpec Specification of the options for a given file
* @throws SchemagenOptionsConfigurationException
*/
protected void handleOption( Source optionSpec ) throws SchemagenOptionsConfigurationException {
SchemagenOptions so = new SchemagenOptions(getDefaultOutputDir(), optionSpec);
if (optionSpec.getInput() != null && !optionSpec.getInput().isEmpty()) {
so.setParent( getDefaultOptions() );
optIndex.put( optionSpec.getInput(), so );
}
else {
getLog().info( "ignoring <source> element because the fileName is not specified" );
}
}
/**
* Delegate the processing of the given file to schemagen itself
* @param fileName
* @throws SchemagenOptionsConfigurationException
*/
protected void processFile( String fileName )
throws MojoExecutionException, SchemagenOptionsConfigurationException
{
//fix windows paths
if( File.separator.equals("\\") ){
fileName = fileName.replaceAll( "\\\\", "/" );
}
getLog().info( "processFile with " + fileName );
getLog().info( optIndex.keySet().toString() );
SchemagenOptions so = optIndex.get( fileName );
getLog().info( "so = " + so );
// if we have no options carrier for this file, we create one to contain
// the name of the input file, and link it to the defaults
String soFileName;
if (so == null) {
so = new SchemagenOptions(getDefaultOptions().getOutputOption());
soFileName = fileName;
so.setParent( getDefaultOptions() );
} else {
soFileName = so.getOption( OPT.INPUT ).asLiteral().getString();
}
getLog().info( "input before adjustment: " + soFileName );
boolean relative = !(soFileName.startsWith( "http:" ) || soFileName.startsWith( "https:" )
|| soFileName.startsWith( "file:" ));
getLog().info( "relative = " + relative );
getLog().info( "baseDir = " + baseDir );
getLog().info( "getBaseDir() = " + getBaseDir() );
soFileName = relative ? "file:" + baseDir + File.separator + soFileName : soFileName;
getLog().info( "input after adjustment: " + soFileName );
Resource input = ResourceFactory.createResource( soFileName );
so.setOption( OPT.INPUT, input );
getLog().info( "about to call run(): " );
ensureTargetDirectory( so );
new SchemagenAdapter().run( so );
}
/***********************************/
/* Internal implementation methods */
/***********************************/
public void setExcludes( String[] excludes ) {
this.excludes = excludes;
}
public void setIncludes( String[] includes ) {
this.includes = includes;
}
/**
* Append the given string to the array of included file patterns
* @param incl File pattern string to append to <code>this.includes</code>
*/
public void addIncludes( String incl ) {
String[] incls = new String[this.includes.length + 1];
int i = 0;
for (String s: this.includes) {
incls[i++] = s;
}
incls[i] = incl;
this.includes = incls;
}
/**
* Append the given string to the array of excluded file patterns
* @param excl File pattern string to append to <code>this.excludes</code>
*/
public void addExcludes( String excl ) {
String[] excls = new String[this.excludes.length + 1];
int i = 0;
for (String s: this.excludes) {
excls[i++] = s;
}
excls[i] = excl;
this.excludes = excls;
}
/**
* Return the base directory for the plugin, which should be supplied
* by plexus, but if not we default to the current working directory.
*
* @return The base directory as a file
*/
protected File getBaseDir() {
return (baseDir == null) ? new File(".").getAbsoluteFile() : baseDir;
}
/**
* Ensure that the output directory exists
*/
protected void ensureTargetDirectory( SchemagenOptions so )
throws MojoExecutionException
{
File gs = new File( so.getOutputOption() );
if (!gs.exists()) {
gs.mkdirs();
}
else if (!gs.isDirectory()) {
getLog().error( "The output location is not a directory: " + gs.getPath() );
throw new MojoExecutionException( "Already exists as file: " + gs.getPath() );
}
else if (!gs.canWrite()) {
getLog().error( "Output directory exists but is not writable: " + gs.getPath() );
throw new MojoExecutionException( "Not writable: " + gs.getPath() );
}
}
protected String getDefaultOutputDir(){
return projectBuildDir + GENERATED_SOURCES;
}
/***********************************/
/* Inner classes */
/***********************************/
/**
* Adapter class to invoke the schemagen tool with a given set of options
*/
protected class SchemagenAdapter
extends schemagen
{
public void run( SchemagenOptions options ) {
go( options );
}
}
}