JomcTask.java
- /*
- * Copyright (C) 2005 Christian Schulte <cs@schulte.it>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * o Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * o Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
- * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
- * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * $JOMC: JomcTask.java 5301 2016-08-30 02:04:33Z schulte $
- *
- */
- package org.jomc.ant;
- import java.io.BufferedReader;
- import java.io.File;
- import java.io.IOException;
- import java.io.InputStream;
- import java.io.StringReader;
- import java.io.StringWriter;
- import java.net.HttpURLConnection;
- import java.net.MalformedURLException;
- import java.net.SocketTimeoutException;
- import java.net.URI;
- import java.net.URISyntaxException;
- import java.net.URL;
- import java.net.URLConnection;
- import java.util.ArrayList;
- import java.util.Collection;
- import java.util.Enumeration;
- import java.util.HashSet;
- import java.util.Iterator;
- import java.util.LinkedList;
- import java.util.List;
- import java.util.Locale;
- import java.util.Map;
- import java.util.Properties;
- import java.util.Set;
- import java.util.concurrent.ExecutorService;
- import java.util.concurrent.Executors;
- import java.util.concurrent.ThreadFactory;
- import java.util.concurrent.atomic.AtomicInteger;
- import java.util.logging.Level;
- import javax.xml.bind.JAXBException;
- import javax.xml.bind.Marshaller;
- import javax.xml.transform.ErrorListener;
- import javax.xml.transform.Transformer;
- import javax.xml.transform.TransformerConfigurationException;
- import javax.xml.transform.TransformerException;
- import javax.xml.transform.TransformerFactory;
- import javax.xml.transform.stream.StreamSource;
- import org.apache.tools.ant.BuildException;
- import org.apache.tools.ant.Project;
- import org.apache.tools.ant.PropertyHelper;
- import org.apache.tools.ant.Task;
- import org.apache.tools.ant.types.Path;
- import org.apache.tools.ant.types.Reference;
- import org.jomc.ant.types.KeyValueType;
- import org.jomc.ant.types.NameType;
- import org.jomc.ant.types.PropertiesFormatType;
- import org.jomc.ant.types.PropertiesResourceType;
- import org.jomc.ant.types.ResourceType;
- import org.jomc.ant.types.TransformerResourceType;
- import org.jomc.model.ModelObject;
- import org.jomc.modlet.DefaultModelContext;
- import org.jomc.modlet.DefaultModletProvider;
- import org.jomc.modlet.Model;
- import org.jomc.modlet.ModelContext;
- import org.jomc.modlet.ModelContextFactory;
- import org.jomc.modlet.ModelException;
- import org.jomc.modlet.ModelValidationReport;
- import org.jomc.modlet.ModletProcessor;
- import org.jomc.modlet.ModletProvider;
- import org.jomc.modlet.ModletValidator;
- import org.jomc.modlet.ServiceFactory;
- /**
- * Base class for executing tasks.
- *
- * @author <a href="mailto:cs@schulte.it">Christian Schulte</a>
- * @version $JOMC: JomcTask.java 5301 2016-08-30 02:04:33Z schulte $
- * @see #execute()
- */
- public class JomcTask extends Task
- {
- /**
- * The class path to process.
- */
- private Path classpath;
- /**
- * The identifier of the model to process.
- */
- private String model;
- /**
- * {@code ModelContext} attributes to apply.
- */
- private List<KeyValueType> modelContextAttributes;
- /**
- * The name of the {@code ModelContextFactory} implementation class backing the task.
- */
- private String modelContextFactoryClassName;
- /**
- * Controls processing of models.
- */
- private boolean modelProcessingEnabled = true;
- /**
- * The location to search for modlets.
- */
- private String modletLocation;
- /**
- * The {@code http://jomc.org/modlet} namespace schema system id of the context backing the task.
- */
- private String modletSchemaSystemId;
- /**
- * The location to search for providers.
- */
- private String providerLocation;
- /**
- * The location to search for platform providers.
- */
- private String platformProviderLocation;
- /**
- * The global transformation parameters to apply.
- */
- private List<KeyValueType> transformationParameters;
- /**
- * The global transformation parameter resources to apply.
- */
- private List<PropertiesResourceType> transformationParameterResources;
- /**
- * The global transformation output properties to apply.
- */
- private List<KeyValueType> transformationOutputProperties;
- /**
- * The flag indicating JAXP schema validation of modlet resources is enabled.
- */
- private boolean modletResourceValidationEnabled = true;
- /**
- * Property controlling the execution of the task.
- */
- private Object _if;
- /**
- * Property controlling the execution of the task.
- */
- private Object unless;
- /**
- * Formula used to calculate the maximum number of threads to create for running tasks in parallel.
- *
- * @since 1.10
- */
- private String threads = "1.0C";
- /**
- * The {@code ExecutorService} of the task.
- *
- * @since 1.10
- */
- private ExecutorService executorService;
- /**
- * Creates a new {@code JomcTask} instance.
- */
- public JomcTask()
- {
- super();
- }
- /**
- * Gets an object controlling the execution of the task.
- *
- * @return An object controlling the execution of the task or {@code null}.
- *
- * @see #setIf(java.lang.Object)
- */
- public final Object getIf()
- {
- return this._if;
- }
- /**
- * Sets an object controlling the execution of the task.
- *
- * @param value The new object controlling the execution of the task or {@code null}.
- *
- * @see #getIf()
- */
- public final void setIf( final Object value )
- {
- this._if = value;
- }
- /**
- * Gets an object controlling the execution of the task.
- *
- * @return An object controlling the execution of the task or {@code null}.
- *
- * @see #setUnless(java.lang.Object)
- */
- public final Object getUnless()
- {
- if ( this.unless == null )
- {
- this.unless = Boolean.TRUE;
- }
- return this.unless;
- }
- /**
- * Sets an object controlling the execution of the task.
- *
- * @param value The new object controlling the execution of the task or {@code null}.
- *
- * @see #getUnless()
- */
- public final void setUnless( final Object value )
- {
- this.unless = value;
- }
- /**
- * Creates a new {@code classpath} element instance.
- *
- * @return A new {@code classpath} element instance.
- */
- public final Path createClasspath()
- {
- return this.getClasspath().createPath();
- }
- /**
- * Gets the class path to process.
- *
- * @return The class path to process.
- *
- * @see #setClasspath(org.apache.tools.ant.types.Path)
- */
- public final Path getClasspath()
- {
- if ( this.classpath == null )
- {
- this.classpath = new Path( this.getProject() );
- }
- return this.classpath;
- }
- /**
- * Adds to the class path to process.
- *
- * @param value The path to add to the list of class path elements.
- *
- * @see #getClasspath()
- */
- public final void setClasspath( final Path value )
- {
- this.getClasspath().add( value );
- }
- /**
- * Adds a reference to a class path defined elsewhere.
- *
- * @param value A reference to a class path.
- *
- * @see #getClasspath()
- */
- public final void setClasspathRef( final Reference value )
- {
- this.getClasspath().setRefid( value );
- }
- /**
- * Gets the identifier of the model to process.
- *
- * @return The identifier of the model to process.
- *
- * @see #setModel(java.lang.String)
- */
- public final String getModel()
- {
- if ( this.model == null )
- {
- this.model = ModelObject.MODEL_PUBLIC_ID;
- }
- return this.model;
- }
- /**
- * Sets the identifier of the model to process.
- *
- * @param value The new identifier of the model to process or {@code null}.
- *
- * @see #getModel()
- */
- public final void setModel( final String value )
- {
- this.model = value;
- }
- /**
- * Gets the {@code ModelContext} attributes to apply.
- * <p>
- * This accessor method returns a reference to the live list, not a snapshot. Therefore any modification you make
- * to the returned list will be present inside the object. This is why there is no {@code set} method for the
- * model context attributes property.
- * </p>
- *
- * @return The {@code ModelContext} attributes to apply.
- *
- * @see #createModelContextAttribute()
- * @see #newModelContext(java.lang.ClassLoader)
- */
- public final List<KeyValueType> getModelContextAttributes()
- {
- if ( this.modelContextAttributes == null )
- {
- this.modelContextAttributes = new LinkedList<KeyValueType>();
- }
- return this.modelContextAttributes;
- }
- /**
- * Creates a new {@code modelContextAttribute} element instance.
- *
- * @return A new {@code modelContextAttribute} element instance.
- *
- * @see #getModelContextAttributes()
- */
- public KeyValueType createModelContextAttribute()
- {
- final KeyValueType modelContextAttribute = new KeyValueType();
- this.getModelContextAttributes().add( modelContextAttribute );
- return modelContextAttribute;
- }
- /**
- * Gets the name of the {@code ModelContextFactory} implementation class backing the task.
- *
- * @return The name of the {@code ModelContextFactory} implementation class backing the task or {@code null}.
- *
- * @see #setModelContextFactoryClassName(java.lang.String)
- */
- public final String getModelContextFactoryClassName()
- {
- return this.modelContextFactoryClassName;
- }
- /**
- * Sets the name of the {@code ModelContextFactory} implementation class backing the task.
- *
- * @param value The new name of the {@code ModelContextFactory} implementation class backing the task or
- * {@code null}.
- *
- * @see #getModelContextFactoryClassName()
- */
- public final void setModelContextFactoryClassName( final String value )
- {
- this.modelContextFactoryClassName = value;
- }
- /**
- * Gets a flag indicating the processing of models is enabled.
- *
- * @return {@code true}, if processing of models is enabled; {@code false}, else.
- *
- * @see #setModelProcessingEnabled(boolean)
- */
- public final boolean isModelProcessingEnabled()
- {
- return this.modelProcessingEnabled;
- }
- /**
- * Sets the flag indicating the processing of models is enabled.
- *
- * @param value {@code true}, to enable processing of models; {@code false}, to disable processing of models.
- *
- * @see #isModelProcessingEnabled()
- */
- public final void setModelProcessingEnabled( final boolean value )
- {
- this.modelProcessingEnabled = value;
- }
- /**
- * Gets the location searched for modlets.
- *
- * @return The location searched for modlets or {@code null}.
- *
- * @see #setModletLocation(java.lang.String)
- */
- public final String getModletLocation()
- {
- return this.modletLocation;
- }
- /**
- * Sets the location to search for modlets.
- *
- * @param value The new location to search for modlets or {@code null}.
- *
- * @see #getModletLocation()
- */
- public final void setModletLocation( final String value )
- {
- this.modletLocation = value;
- }
- /**
- * Gets the {@code http://jomc.org/modlet} namespace schema system id of the context backing the task.
- *
- * @return The {@code http://jomc.org/modlet} namespace schema system id of the context backing the task or
- * {@code null}.
- *
- * @see #setModletSchemaSystemId(java.lang.String)
- */
- public final String getModletSchemaSystemId()
- {
- return this.modletSchemaSystemId;
- }
- /**
- * Sets the {@code http://jomc.org/modlet} namespace schema system id of the context backing the task.
- *
- * @param value The new {@code http://jomc.org/modlet} namespace schema system id of the context backing the task or
- * {@code null}.
- *
- * @see #getModletSchemaSystemId()
- */
- public final void setModletSchemaSystemId( final String value )
- {
- this.modletSchemaSystemId = value;
- }
- /**
- * Gets the location searched for providers.
- *
- * @return The location searched for providers or {@code null}.
- *
- * @see #setProviderLocation(java.lang.String)
- */
- public final String getProviderLocation()
- {
- return this.providerLocation;
- }
- /**
- * Sets the location to search for providers.
- *
- * @param value The new location to search for providers or {@code null}.
- *
- * @see #getProviderLocation()
- */
- public final void setProviderLocation( final String value )
- {
- this.providerLocation = value;
- }
- /**
- * Gets the location searched for platform provider resources.
- *
- * @return The location searched for platform provider resources or {@code null}.
- *
- * @see #setPlatformProviderLocation(java.lang.String)
- */
- public final String getPlatformProviderLocation()
- {
- return this.platformProviderLocation;
- }
- /**
- * Sets the location to search for platform provider resources.
- *
- * @param value The new location to search for platform provider resources or {@code null}.
- *
- * @see #getPlatformProviderLocation()
- */
- public final void setPlatformProviderLocation( final String value )
- {
- this.platformProviderLocation = value;
- }
- /**
- * Gets the global transformation parameters to apply.
- * <p>
- * This accessor method returns a reference to the live list, not a snapshot. Therefore any modification you make
- * to the returned list will be present inside the object. This is why there is no {@code set} method for the
- * transformation parameters property.
- * </p>
- *
- * @return The global transformation parameters to apply.
- *
- * @see #createTransformationParameter()
- * @see #getTransformer(org.jomc.ant.types.TransformerResourceType)
- */
- public final List<KeyValueType> getTransformationParameters()
- {
- if ( this.transformationParameters == null )
- {
- this.transformationParameters = new LinkedList<KeyValueType>();
- }
- return this.transformationParameters;
- }
- /**
- * Creates a new {@code transformationParameter} element instance.
- *
- * @return A new {@code transformationParameter} element instance.
- *
- * @see #getTransformationParameters()
- */
- public KeyValueType createTransformationParameter()
- {
- final KeyValueType transformationParameter = new KeyValueType();
- this.getTransformationParameters().add( transformationParameter );
- return transformationParameter;
- }
- /**
- * Gets the global transformation parameter resources to apply.
- * <p>
- * This accessor method returns a reference to the live list, not a snapshot. Therefore any modification you make
- * to the returned list will be present inside the object. This is why there is no {@code set} method for the
- * transformation parameter resources property.
- * </p>
- *
- * @return The global transformation parameter resources to apply.
- *
- * @see #createTransformationParameterResource()
- * @see #getTransformer(org.jomc.ant.types.TransformerResourceType)
- */
- public final List<PropertiesResourceType> getTransformationParameterResources()
- {
- if ( this.transformationParameterResources == null )
- {
- this.transformationParameterResources = new LinkedList<PropertiesResourceType>();
- }
- return this.transformationParameterResources;
- }
- /**
- * Creates a new {@code transformationParameterResource} element instance.
- *
- * @return A new {@code transformationParameterResource} element instance.
- *
- * @see #getTransformationParameterResources()
- */
- public PropertiesResourceType createTransformationParameterResource()
- {
- final PropertiesResourceType transformationParameterResource = new PropertiesResourceType();
- this.getTransformationParameterResources().add( transformationParameterResource );
- return transformationParameterResource;
- }
- /**
- * Gets the global transformation output properties to apply.
- * <p>
- * This accessor method returns a reference to the live list, not a snapshot. Therefore any modification you make
- * to the returned list will be present inside the object. This is why there is no {@code set} method for the
- * transformation output properties property.
- * </p>
- *
- * @return The global transformation output properties to apply.
- *
- * @see #createTransformationOutputProperty()
- */
- public final List<KeyValueType> getTransformationOutputProperties()
- {
- if ( this.transformationOutputProperties == null )
- {
- this.transformationOutputProperties = new LinkedList<KeyValueType>();
- }
- return this.transformationOutputProperties;
- }
- /**
- * Creates a new {@code transformationOutputProperty} element instance.
- *
- * @return A new {@code transformationOutputProperty} element instance.
- *
- * @see #getTransformationOutputProperties()
- */
- public KeyValueType createTransformationOutputProperty()
- {
- final KeyValueType transformationOutputProperty = new KeyValueType();
- this.getTransformationOutputProperties().add( transformationOutputProperty );
- return transformationOutputProperty;
- }
- /**
- * Gets a flag indicating JAXP schema validation of modlet resources is enabled.
- *
- * @return {@code true}, if JAXP schema validation of modlet resources is enabled; {@code false}, else.
- *
- * @see #setModletResourceValidationEnabled(boolean)
- */
- public final boolean isModletResourceValidationEnabled()
- {
- return this.modletResourceValidationEnabled;
- }
- /**
- * Sets the flag indicating JAXP schema validation of modlet resources is enabled.
- *
- * @param value {@code true}, to enable JAXP schema validation of modlet resources; {@code false}, to disable JAXP
- * schema validation of modlet resources.
- *
- * @see #isModletResourceValidationEnabled()
- */
- public final void setModletResourceValidationEnabled( final boolean value )
- {
- this.modletResourceValidationEnabled = value;
- }
- /**
- * Gets a formula used to calculate the maximum number of threads to create for running tasks in parallel. If the
- * formular contains the character {@code C}, the number of threads will be calculated by multiplying the value by
- * the number of available processors. The default number of threads is the number of available processors (1.0C).
- *
- * @return A formula used to calculate the number of threads.
- *
- * @see Runtime#availableProcessors()
- *
- * @since 1.10
- */
- public final String getThreads()
- {
- return this.threads;
- }
- /**
- * Sets the formula to use to calculate the maximum number of threads to create for running tasks in parallel. If
- * the formular contains the character {@code C}, the number of threads will be calculated by multiplying the value
- * by the number of available processors. The default number of threads is the number of available processors
- * (1.0C).
- *
- * @param value The formula to use to calculate the maximum number of threads or {@code null}, to disable any
- * parallelism.
- *
- * @since 1.10
- */
- public final void setThreads( final String value )
- {
- this.threads = value;
- }
- /**
- * Gets the {@code ExecutorService} used to run tasks in parallel.
- *
- * @return The {@code ExecutorService} used to run tasks in parallel or {@code null}, if the maximum number of
- * threads to create for running tasks in parallel is not greater than 1.
- *
- * @since 1.10
- */
- protected final ExecutorService getExecutorService()
- {
- if ( this.executorService == null )
- {
- final Double parallelism =
- this.getThreads().toLowerCase( new Locale( "" ) ).contains( "c" )
- ? Double.valueOf( this.getThreads().toLowerCase( new Locale( "" ) ).replace( "c", "" ) )
- * Runtime.getRuntime().availableProcessors()
- : Double.valueOf( this.getThreads() );
- if ( parallelism.intValue() > 1 )
- {
- this.executorService = Executors.newFixedThreadPool(
- parallelism.intValue(), new ThreadFactory()
- {
- private final ThreadGroup group;
- private final AtomicInteger threadNumber = new AtomicInteger( 1 );
- {
- final SecurityManager s = System.getSecurityManager();
- this.group = s != null
- ? s.getThreadGroup()
- : Thread.currentThread().getThreadGroup();
- }
- @Override
- public Thread newThread( final Runnable r )
- {
- final Thread t =
- new Thread( this.group, r, "jomc-ant-tasks-" + this.threadNumber.getAndIncrement(), 0 );
- if ( t.isDaemon() )
- {
- t.setDaemon( false );
- }
- if ( t.getPriority() != Thread.NORM_PRIORITY )
- {
- t.setPriority( Thread.NORM_PRIORITY );
- }
- return t;
- }
- } );
- }
- }
- return this.executorService;
- }
- /**
- * Called by the project to let the task do its work.
- *
- * @throws BuildException if execution fails.
- *
- * @see #getIf()
- * @see #getUnless()
- * @see #preExecuteTask()
- * @see #executeTask()
- * @see #postExecuteTask()
- */
- @Override
- public final void execute() throws BuildException
- {
- final PropertyHelper propertyHelper = PropertyHelper.getPropertyHelper( this.getProject() );
- if ( propertyHelper.testIfCondition( this.getIf() ) && !propertyHelper.testUnlessCondition( this.getUnless() ) )
- {
- try
- {
- this.preExecuteTask();
- this.executeTask();
- }
- finally
- {
- try
- {
- this.postExecuteTask();
- }
- finally
- {
- if ( this.executorService != null )
- {
- this.executorService.shutdown();
- this.executorService = null;
- }
- }
- }
- }
- }
- /**
- * Called by the {@code execute} method prior to the {@code executeTask} method.
- *
- * @throws BuildException if execution fails.
- *
- * @see #execute()
- */
- public void preExecuteTask() throws BuildException
- {
- this.logSeparator();
- this.log( Messages.getMessage( "title" ) );
- this.logSeparator();
- this.assertNotNull( "model", this.getModel() );
- this.assertKeysNotNull( this.getModelContextAttributes() );
- this.assertKeysNotNull( this.getTransformationParameters() );
- this.assertKeysNotNull( this.getTransformationOutputProperties() );
- this.assertLocationsNotNull( this.getTransformationParameterResources() );
- }
- /**
- * Called by the {@code execute} method prior to the {@code postExecuteTask} method.
- *
- * @throws BuildException if execution fails.
- *
- * @see #execute()
- */
- public void executeTask() throws BuildException
- {
- this.getProject().log( Messages.getMessage( "unimplementedTask", this.getClass().getName(), "executeTask" ),
- Project.MSG_WARN );
- }
- /**
- * Called by the {@code execute} method after the {@code preExecuteTask}/{@code executeTask} methods even if those
- * methods threw an exception.
- *
- * @throws BuildException if execution fails.
- *
- * @see #execute()
- */
- public void postExecuteTask() throws BuildException
- {
- this.logSeparator();
- }
- /**
- * Gets a {@code Model} from a given {@code ModelContext}.
- *
- * @param context The context to get a {@code Model} from.
- *
- * @return The {@code Model} from {@code context}.
- *
- * @throws NullPointerException if {@code contexŧ} is {@code null}.
- * @throws ModelException if getting the model fails.
- *
- * @see #getModel()
- * @see #isModelProcessingEnabled()
- */
- public Model getModel( final ModelContext context ) throws ModelException
- {
- if ( context == null )
- {
- throw new NullPointerException( "context" );
- }
- Model foundModel = context.findModel( this.getModel() );
- if ( foundModel != null && this.isModelProcessingEnabled() )
- {
- foundModel = context.processModel( foundModel );
- }
- return foundModel;
- }
- /**
- * Creates an {@code URL} for a given resource location.
- * <p>
- * This method first searches the class path of the task for a single resource matching {@code location}. If
- * such a resource is found, the URL of that resource is returned. If no such resource is found, an attempt is made
- * to parse the given location to an URL. On successful parsing, that URL is returned. Failing that, the given
- * location is interpreted as a file name relative to the project's base directory. If that file is found, the URL
- * of that file is returned. Otherwise {@code null} is returned.
- * </p>
- *
- * @param location The resource location to create an {@code URL} from.
- *
- * @return An {@code URL} for {@code location} or {@code null}, if parsing {@code location} to an URL fails and
- * {@code location} points to a non-existent resource.
- *
- * @throws NullPointerException if {@code location} is {@code null}.
- * @throws BuildException if creating an URL fails.
- */
- public URL getResource( final String location ) throws BuildException
- {
- if ( location == null )
- {
- throw new NullPointerException( "location" );
- }
- try
- {
- String absolute = location;
- if ( !absolute.startsWith( "/" ) )
- {
- absolute = "/" + absolute;
- }
- URL resource = this.getClass().getResource( absolute );
- if ( resource == null )
- {
- try
- {
- resource = new URL( location );
- }
- catch ( final MalformedURLException e )
- {
- this.log( e, Project.MSG_DEBUG );
- resource = null;
- }
- }
- if ( resource == null )
- {
- final File f = this.getProject().resolveFile( location );
- if ( f.isFile() )
- {
- resource = f.toURI().toURL();
- }
- }
- return resource;
- }
- catch ( final MalformedURLException e )
- {
- String m = Messages.getMessage( e );
- m = m == null ? "" : " " + m;
- throw new BuildException( Messages.getMessage( "malformedLocation", location, m ), e, this.getLocation() );
- }
- }
- /**
- * Creates an array of {@code URL}s for a given resource location.
- * <p>
- * This method first searches the given context for resources matching {@code location}. If such resources are
- * found, an array of URLs of those resources is returned. If no such resources are found, an attempt is made
- * to parse the given location to an URL. On successful parsing, that URL is returned. Failing that, the given
- * location is interpreted as a file name relative to the project's base directory. If that file is found, the URL
- * of that file is returned. Otherwise an empty array is returned.
- * </p>
- *
- * @param context The context to search for resources.
- * @param location The resource location to create an array of {@code URL}s from.
- *
- * @return An array of {@code URL}s for {@code location} or an empty array if parsing {@code location} to an URL
- * fails and {@code location} points to non-existent resources.
- *
- * @throws NullPointerException if {@code context} or {@code location} is {@code null}.
- * @throws BuildException if creating an URL array fails.
- */
- public URL[] getResources( final ModelContext context, final String location ) throws BuildException
- {
- if ( context == null )
- {
- throw new NullPointerException( "context" );
- }
- if ( location == null )
- {
- throw new NullPointerException( "location" );
- }
- final Set<URI> uris = new HashSet<URI>( 128 );
- try
- {
- for ( final Enumeration<URL> e = context.findResources( location ); e.hasMoreElements(); )
- {
- uris.add( e.nextElement().toURI() );
- }
- }
- catch ( final URISyntaxException e )
- {
- this.log( e, Project.MSG_DEBUG );
- }
- catch ( final ModelException e )
- {
- this.log( e, Project.MSG_DEBUG );
- }
- if ( uris.isEmpty() )
- {
- try
- {
- uris.add( new URL( location ).toURI() );
- }
- catch ( final MalformedURLException e )
- {
- this.log( e, Project.MSG_DEBUG );
- }
- catch ( final URISyntaxException e )
- {
- this.log( e, Project.MSG_DEBUG );
- }
- }
- if ( uris.isEmpty() )
- {
- final File f = this.getProject().resolveFile( location );
- if ( f.isFile() )
- {
- uris.add( f.toURI() );
- }
- }
- int i = 0;
- final URL[] urls = new URL[ uris.size() ];
- for ( final URI uri : uris )
- {
- try
- {
- urls[i++] = uri.toURL();
- }
- catch ( final MalformedURLException e )
- {
- String m = Messages.getMessage( e );
- m = m == null ? "" : " " + m;
- throw new BuildException( Messages.getMessage( "malformedLocation", uri.toASCIIString(), m ), e,
- this.getLocation() );
- }
- }
- return urls;
- }
- /**
- * Creates an {@code URL} for a given directory location.
- * <p>
- * This method first attempts to parse the given location to an URL. On successful parsing, that URL is returned.
- * Failing that, the given location is interpreted as a directory name relative to the project's base directory. If
- * that directory is found, the URL of that directory is returned. Otherwise {@code null} is returned.
- * </p>
- *
- * @param location The directory location to create an {@code URL} from.
- *
- * @return An {@code URL} for {@code location} or {@code null}, if parsing {@code location} to an URL fails and
- * {@code location} points to a non-existent directory.
- *
- * @throws NullPointerException if {@code location} is {@code null}.
- * @throws BuildException if creating an URL fails.
- */
- public URL getDirectory( final String location ) throws BuildException
- {
- if ( location == null )
- {
- throw new NullPointerException( "location" );
- }
- try
- {
- URL resource;
- try
- {
- resource = new URL( location );
- }
- catch ( final MalformedURLException e )
- {
- this.log( e, Project.MSG_DEBUG );
- resource = null;
- }
- if ( resource == null )
- {
- final File f = this.getProject().resolveFile( location );
- if ( f.isDirectory() )
- {
- resource = f.toURI().toURL();
- }
- }
- return resource;
- }
- catch ( final MalformedURLException e )
- {
- String m = Messages.getMessage( e );
- m = m == null ? "" : " " + m;
- throw new BuildException( Messages.getMessage( "malformedLocation", location, m ), e, this.getLocation() );
- }
- }
- /**
- * Creates a new {@code Transformer} for a given {@code TransformerResourceType}.
- *
- * @param resource The resource to create a {@code Transformer} of.
- *
- * @return A new {@code Transformer} for {@code resource} or {@code null}, if {@code resource} is not found and
- * flagged optional.
- *
- * @throws TransformerConfigurationException if creating a new {@code Transformer} fails.
- *
- * @see #getTransformationParameterResources()
- * @see #getTransformationParameters()
- * @see #getResource(java.lang.String)
- */
- public Transformer getTransformer( final TransformerResourceType resource ) throws TransformerConfigurationException
- {
- if ( resource == null )
- {
- throw new NullPointerException( "resource" );
- }
- URLConnection con = null;
- InputStream in = null;
- final URL url = this.getResource( resource.getLocation() );
- try
- {
- if ( url != null )
- {
- final ErrorListener errorListener = new ErrorListener()
- {
- public void warning( final TransformerException exception ) throws TransformerException
- {
- if ( getProject() != null )
- {
- getProject().log( Messages.getMessage( exception ), exception, Project.MSG_WARN );
- }
- }
- public void error( final TransformerException exception ) throws TransformerException
- {
- throw exception;
- }
- public void fatalError( final TransformerException exception ) throws TransformerException
- {
- throw exception;
- }
- };
- con = url.openConnection();
- con.setConnectTimeout( resource.getConnectTimeout() );
- con.setReadTimeout( resource.getReadTimeout() );
- con.connect();
- in = con.getInputStream();
- final TransformerFactory f = TransformerFactory.newInstance();
- f.setErrorListener( errorListener );
- final Transformer transformer = f.newTransformer( new StreamSource( in, url.toURI().toASCIIString() ) );
- transformer.setErrorListener( errorListener );
- for ( final Map.Entry<Object, Object> e : System.getProperties().entrySet() )
- {
- transformer.setParameter( e.getKey().toString(), e.getValue() );
- }
- for ( final Iterator<Map.Entry<?, ?>> it = this.getProject().getProperties().entrySet().iterator();
- it.hasNext(); )
- {
- final Map.Entry<?, ?> e = it.next();
- transformer.setParameter( e.getKey().toString(), e.getValue() );
- }
- for ( int i = 0, s0 = this.getTransformationParameterResources().size(); i < s0; i++ )
- {
- for ( final Map.Entry<Object, Object> e
- : this.getProperties( this.getTransformationParameterResources().get( i ) ).entrySet() )
- {
- transformer.setParameter( e.getKey().toString(), e.getValue() );
- }
- }
- for ( int i = 0, s0 = this.getTransformationParameters().size(); i < s0; i++ )
- {
- final KeyValueType p = this.getTransformationParameters().get( i );
- transformer.setParameter( p.getKey(), p.getObject( this.getLocation() ) );
- }
- for ( int i = 0, s0 = this.getTransformationOutputProperties().size(); i < s0; i++ )
- {
- final KeyValueType p = this.getTransformationOutputProperties().get( i );
- transformer.setOutputProperty( p.getKey(), p.getValue() );
- }
- for ( int i = 0, s0 = resource.getTransformationParameterResources().size(); i < s0; i++ )
- {
- for ( final Map.Entry<Object, Object> e
- : this.getProperties( resource.getTransformationParameterResources().get( i ) ).
- entrySet() )
- {
- transformer.setParameter( e.getKey().toString(), e.getValue() );
- }
- }
- for ( int i = 0, s0 = resource.getTransformationParameters().size(); i < s0; i++ )
- {
- final KeyValueType p = resource.getTransformationParameters().get( i );
- transformer.setParameter( p.getKey(), p.getObject( this.getLocation() ) );
- }
- for ( int i = 0, s0 = resource.getTransformationOutputProperties().size(); i < s0; i++ )
- {
- final KeyValueType p = resource.getTransformationOutputProperties().get( i );
- transformer.setOutputProperty( p.getKey(), p.getValue() );
- }
- in.close();
- in = null;
- return transformer;
- }
- else if ( resource.isOptional() )
- {
- this.log( Messages.getMessage( "transformerNotFound", resource.getLocation() ), Project.MSG_WARN );
- }
- else
- {
- throw new BuildException( Messages.getMessage( "transformerNotFound", resource.getLocation() ),
- this.getLocation() );
- }
- }
- catch ( final URISyntaxException e )
- {
- throw new BuildException( Messages.getMessage( e ), e, this.getLocation() );
- }
- catch ( final SocketTimeoutException e )
- {
- final String message = Messages.getMessage( e );
- if ( resource.isOptional() )
- {
- this.getProject().log( Messages.getMessage( "resourceTimeout", message != null ? " " + message : "" ),
- e, Project.MSG_WARN );
- }
- else
- {
- throw new BuildException( Messages.getMessage( "resourceTimeout", message != null ? " " + message : "" ),
- e, this.getLocation() );
- }
- }
- catch ( final IOException e )
- {
- final String message = Messages.getMessage( e );
- if ( resource.isOptional() )
- {
- this.getProject().log( Messages.getMessage( "resourceFailure", message != null ? " " + message : "" ),
- e, Project.MSG_WARN );
- }
- else
- {
- throw new BuildException( Messages.getMessage( "resourceFailure", message != null ? " " + message : "" ),
- e, this.getLocation() );
- }
- }
- finally
- {
- try
- {
- if ( in != null )
- {
- in.close();
- }
- }
- catch ( final IOException e )
- {
- this.logMessage( Level.SEVERE, Messages.getMessage( e ), e );
- }
- finally
- {
- if ( con instanceof HttpURLConnection )
- {
- ( (HttpURLConnection) con ).disconnect();
- }
- }
- }
- return null;
- }
- /**
- * Creates a new {@code Properties} instance from a {@code PropertiesResourceType}.
- *
- * @param propertiesResourceType The {@code PropertiesResourceType} specifying the properties to create.
- *
- * @return The properties for {@code propertiesResourceType}.
- *
- * @throws NullPointerException if {@code propertiesResourceType} is {@code null}.
- * @throws BuildException if loading properties fails.
- */
- public Properties getProperties( final PropertiesResourceType propertiesResourceType ) throws BuildException
- {
- if ( propertiesResourceType == null )
- {
- throw new NullPointerException( "propertiesResourceType" );
- }
- URLConnection con = null;
- InputStream in = null;
- final Properties properties = new Properties();
- final URL url = this.getResource( propertiesResourceType.getLocation() );
- try
- {
- if ( url != null )
- {
- con = url.openConnection();
- con.setConnectTimeout( propertiesResourceType.getConnectTimeout() );
- con.setReadTimeout( propertiesResourceType.getReadTimeout() );
- con.connect();
- in = con.getInputStream();
- if ( propertiesResourceType.getFormat() == PropertiesFormatType.PLAIN )
- {
- properties.load( in );
- }
- else if ( propertiesResourceType.getFormat() == PropertiesFormatType.XML )
- {
- properties.loadFromXML( in );
- }
- in.close();
- in = null;
- }
- else if ( propertiesResourceType.isOptional() )
- {
- this.log( Messages.getMessage( "propertiesNotFound", propertiesResourceType.getLocation() ),
- Project.MSG_WARN );
- }
- else
- {
- throw new BuildException( Messages.getMessage(
- "propertiesNotFound", propertiesResourceType.getLocation() ), this.getLocation() );
- }
- }
- catch ( final SocketTimeoutException e )
- {
- final String message = Messages.getMessage( e );
- if ( propertiesResourceType.isOptional() )
- {
- this.getProject().log( Messages.getMessage( "resourceTimeout", message != null ? " " + message : "" ),
- e, Project.MSG_WARN );
- }
- else
- {
- throw new BuildException( Messages.getMessage( "resourceTimeout", message != null ? " " + message : "" ),
- e, this.getLocation() );
- }
- }
- catch ( final IOException e )
- {
- final String message = Messages.getMessage( e );
- if ( propertiesResourceType.isOptional() )
- {
- this.getProject().log( Messages.getMessage( "resourceFailure", message != null ? " " + message : "" ),
- e, Project.MSG_WARN );
- }
- else
- {
- throw new BuildException( Messages.getMessage( "resourceFailure", message != null ? " " + message : "" ),
- e, this.getLocation() );
- }
- }
- finally
- {
- try
- {
- if ( in != null )
- {
- in.close();
- }
- }
- catch ( final IOException e )
- {
- this.logMessage( Level.SEVERE, Messages.getMessage( e ), e );
- }
- finally
- {
- if ( con instanceof HttpURLConnection )
- {
- ( (HttpURLConnection) con ).disconnect();
- }
- }
- }
- return properties;
- }
- /**
- * Creates a new {@code ProjectClassLoader} instance.
- *
- * @return A new {@code ProjectClassLoader} instance.
- *
- * @throws BuildException if creating a new class loader instance fails.
- */
- public ProjectClassLoader newProjectClassLoader() throws BuildException
- {
- try
- {
- final ProjectClassLoader classLoader = new ProjectClassLoader( this.getProject(), this.getClasspath() );
- // Assumes the default modlet location matches the location of resources of the tasks' dependencies.
- classLoader.getModletResourceLocations().add( DefaultModletProvider.getDefaultModletLocation() );
- classLoader.getModletExcludes().addAll( ProjectClassLoader.getDefaultModletExcludes() );
- classLoader.getSchemaExcludes().addAll( ProjectClassLoader.getDefaultSchemaExcludes() );
- classLoader.getServiceExcludes().addAll( ProjectClassLoader.getDefaultServiceExcludes() );
- // Assumes the default provider location matches the location of resources of the tasks' dependencies.
- final String providerLocationPrefix = DefaultModelContext.getDefaultProviderLocation() + "/";
- classLoader.getProviderResourceLocations().add( providerLocationPrefix + ModletProcessor.class.getName() );
- classLoader.getProviderResourceLocations().add( providerLocationPrefix + ModletProvider.class.getName() );
- classLoader.getProviderResourceLocations().add( providerLocationPrefix + ModletValidator.class.getName() );
- classLoader.getProviderResourceLocations().add( providerLocationPrefix + ServiceFactory.class.getName() );
- classLoader.getProviderExcludes().addAll( ProjectClassLoader.getDefaultProviderExcludes() );
- return classLoader;
- }
- catch ( final IOException e )
- {
- throw new BuildException( Messages.getMessage( e ), e, this.getLocation() );
- }
- }
- /**
- * Creates a new {@code ModelContext} instance using a given class loader.
- *
- * @param classLoader The class loader to create a new {@code ModelContext} instance with.
- *
- * @return A new {@code ModelContext} instance backed by {@code classLoader}.
- *
- * @throws ModelException if creating a new {@code ModelContext} instance fails.
- */
- public ModelContext newModelContext( final ClassLoader classLoader ) throws ModelException
- {
- final ModelContextFactory modelContextFactory =
- this.modelContextFactoryClassName != null
- ? ModelContextFactory.newInstance( this.getModelContextFactoryClassName() )
- : ModelContextFactory.newInstance();
- final ModelContext modelContext = modelContextFactory.newModelContext( classLoader );
- modelContext.setExecutorService( this.getExecutorService() );
- modelContext.setLogLevel( Level.ALL );
- modelContext.setModletSchemaSystemId( this.getModletSchemaSystemId() );
- modelContext.getListeners().add( new ModelContext.Listener()
- {
- @Override
- public void onLog( final Level level, final String message, final Throwable t )
- {
- super.onLog( level, message, t );
- logMessage( level, message, t );
- }
- } );
- if ( this.getProviderLocation() != null )
- {
- modelContext.setAttribute( DefaultModelContext.PROVIDER_LOCATION_ATTRIBUTE_NAME,
- this.getProviderLocation() );
- }
- if ( this.getPlatformProviderLocation() != null )
- {
- modelContext.setAttribute( DefaultModelContext.PLATFORM_PROVIDER_LOCATION_ATTRIBUTE_NAME,
- this.getPlatformProviderLocation() );
- }
- if ( this.getModletLocation() != null )
- {
- modelContext.setAttribute( DefaultModletProvider.MODLET_LOCATION_ATTRIBUTE_NAME, this.getModletLocation() );
- }
- modelContext.setAttribute( DefaultModletProvider.VALIDATING_ATTRIBUTE_NAME,
- this.isModletResourceValidationEnabled() );
- for ( int i = 0, s0 = this.getModelContextAttributes().size(); i < s0; i++ )
- {
- final KeyValueType kv = this.getModelContextAttributes().get( i );
- final Object object = kv.getObject( this.getLocation() );
- if ( object != null )
- {
- modelContext.setAttribute( kv.getKey(), object );
- }
- else
- {
- modelContext.clearAttribute( kv.getKey() );
- }
- }
- return modelContext;
- }
- /**
- * Throws a {@code BuildException} on a given {@code null} value.
- *
- * @param attributeName The name of a mandatory attribute.
- * @param value The value of that attribute.
- *
- * @throws NullPointerException if {@code attributeName} is {@code null}.
- * @throws BuildException if {@code value} is {@code null}.
- */
- public final void assertNotNull( final String attributeName, final Object value ) throws BuildException
- {
- if ( attributeName == null )
- {
- throw new NullPointerException( "attributeName" );
- }
- if ( value == null )
- {
- throw new BuildException( Messages.getMessage( "mandatoryAttribute", attributeName ), this.getLocation() );
- }
- }
- /**
- * Throws a {@code BuildException} on a {@code null} value of a {@code name} property of a given {@code NameType}
- * collection.
- *
- * @param names The collection holding the {@code NameType} instances to test.
- *
- * @throws NullPointerException if {@code names} is {@code null}.
- * @throws BuildException if a {@code name} property of a given {@code NameType} from the {@code names} collection
- * holds a {@code null} value.
- */
- public final void assertNamesNotNull( final Collection<? extends NameType> names ) throws BuildException
- {
- if ( names == null )
- {
- throw new NullPointerException( "names" );
- }
- for ( final NameType n : names )
- {
- this.assertNotNull( "name", n.getName() );
- }
- }
- /**
- * Throws a {@code BuildException} on a {@code null} value of a {@code key} property of a given {@code KeyValueType}
- * collection.
- *
- * @param keys The collection holding the {@code KeyValueType} instances to test.
- *
- * @throws NullPointerException if {@code keys} is {@code null}.
- * @throws BuildException if a {@code key} property of a given {@code KeyValueType} from the {@code keys} collection
- * holds a {@code null} value.
- */
- public final void assertKeysNotNull( final Collection<? extends KeyValueType> keys ) throws BuildException
- {
- if ( keys == null )
- {
- throw new NullPointerException( "keys" );
- }
- for ( final KeyValueType k : keys )
- {
- this.assertNotNull( "key", k.getKey() );
- }
- }
- /**
- * Throws a {@code BuildException} on a {@code null} value of a {@code location} property of a given
- * {@code ResourceType} collection.
- *
- * @param locations The collection holding the {@code ResourceType} instances to test.
- *
- * @throws NullPointerException if {@code locations} is {@code null}.
- * @throws BuildException if a {@code location} property of a given {@code ResourceType} from the {@code locations}
- * collection holds a {@code null} value.
- */
- public final void assertLocationsNotNull( final Collection<? extends ResourceType> locations )
- throws BuildException
- {
- if ( locations == null )
- {
- throw new NullPointerException( "locations" );
- }
- for ( final ResourceType r : locations )
- {
- assertNotNull( "location", r.getLocation() );
- if ( r instanceof TransformerResourceType )
- {
- assertKeysNotNull( ( (TransformerResourceType) r ).getTransformationParameters() );
- assertLocationsNotNull( ( (TransformerResourceType) r ).getTransformationParameterResources() );
- assertKeysNotNull( ( (TransformerResourceType) r ).getTransformationOutputProperties() );
- }
- }
- }
- /**
- * Logs a separator string.
- */
- public final void logSeparator()
- {
- this.log( Messages.getMessage( "separator" ) );
- }
- /**
- * Logs a message at a given level.
- *
- * @param level The level to log at.
- * @param message The message to log.
- *
- * @throws BuildException if logging fails.
- */
- public final void logMessage( final Level level, final String message ) throws BuildException
- {
- BufferedReader reader = null;
- try
- {
- reader = new BufferedReader( new StringReader( message ) );
- for ( String line = reader.readLine(); line != null; line = reader.readLine() )
- {
- if ( level.intValue() >= Level.SEVERE.intValue() )
- {
- log( line, Project.MSG_ERR );
- }
- else if ( level.intValue() >= Level.WARNING.intValue() )
- {
- log( line, Project.MSG_WARN );
- }
- else if ( level.intValue() >= Level.INFO.intValue() )
- {
- log( line, Project.MSG_INFO );
- }
- else
- {
- log( line, Project.MSG_DEBUG );
- }
- }
- reader.close();
- reader = null;
- }
- catch ( final IOException e )
- {
- throw new BuildException( Messages.getMessage( e ), e, this.getLocation() );
- }
- finally
- {
- try
- {
- if ( reader != null )
- {
- reader.close();
- }
- }
- catch ( final IOException e )
- {
- this.log( e, Project.MSG_ERR );
- }
- }
- }
- /**
- * Logs a message at a given level.
- *
- * @param level The level to log at.
- * @param message The message to log.
- * @param throwable The throwable to log.
- *
- * @throws BuildException if logging fails.
- */
- public final void logMessage( final Level level, final String message, final Throwable throwable )
- throws BuildException
- {
- this.logMessage( level, message );
- if ( level.intValue() >= Level.SEVERE.intValue() )
- {
- log( throwable, Project.MSG_ERR );
- }
- else if ( level.intValue() >= Level.WARNING.intValue() )
- {
- log( throwable, Project.MSG_WARN );
- }
- else if ( level.intValue() >= Level.INFO.intValue() )
- {
- log( throwable, Project.MSG_INFO );
- }
- else
- {
- log( throwable, Project.MSG_DEBUG );
- }
- }
- /**
- * Logs a validation report.
- *
- * @param context The context to use for logging the report.
- * @param report The report to log.
- *
- * @throws NullPointerException if {@code context} or {@code report} is {@code null}.
- * @throws BuildException if logging fails.
- */
- public final void logValidationReport( final ModelContext context, final ModelValidationReport report )
- {
- try
- {
- if ( !report.getDetails().isEmpty() )
- {
- this.logSeparator();
- Marshaller marshaller = null;
- for ( final ModelValidationReport.Detail detail : report.getDetails() )
- {
- this.logMessage( detail.getLevel(), "o " + detail.getMessage() );
- if ( detail.getElement() != null )
- {
- if ( marshaller == null )
- {
- marshaller = context.createMarshaller( this.getModel() );
- marshaller.setProperty( Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE );
- }
- final StringWriter stringWriter = new StringWriter();
- marshaller.marshal( detail.getElement(), stringWriter );
- this.logMessage( Level.FINEST, stringWriter.toString() );
- }
- }
- }
- }
- catch ( final ModelException e )
- {
- throw new BuildException( Messages.getMessage( e ), e, this.getLocation() );
- }
- catch ( final JAXBException e )
- {
- String message = Messages.getMessage( e );
- if ( message == null && e.getLinkedException() != null )
- {
- message = Messages.getMessage( e.getLinkedException() );
- }
- throw new BuildException( message, e, this.getLocation() );
- }
- }
- /**
- * Creates and returns a copy of this object.
- *
- * @return A copy of this object.
- */
- @Override
- public JomcTask clone()
- {
- try
- {
- final JomcTask clone = (JomcTask) super.clone();
- clone.executorService = this.executorService;
- clone.classpath = (Path) ( this.classpath != null ? this.classpath.clone() : null );
- if ( this.modelContextAttributes != null )
- {
- clone.modelContextAttributes = new ArrayList<KeyValueType>( this.modelContextAttributes.size() );
- for ( final KeyValueType e : this.modelContextAttributes )
- {
- clone.modelContextAttributes.add( e.clone() );
- }
- }
- if ( this.transformationParameters != null )
- {
- clone.transformationParameters =
- new ArrayList<KeyValueType>( this.transformationParameters.size() );
- for ( final KeyValueType e : this.transformationParameters )
- {
- clone.transformationParameters.add( e.clone() );
- }
- }
- if ( this.transformationParameterResources != null )
- {
- clone.transformationParameterResources =
- new ArrayList<PropertiesResourceType>( this.transformationParameterResources.size() );
- for ( final PropertiesResourceType e : this.transformationParameterResources )
- {
- clone.transformationParameterResources.add( e.clone() );
- }
- }
- if ( this.transformationOutputProperties != null )
- {
- clone.transformationOutputProperties =
- new ArrayList<KeyValueType>( this.transformationOutputProperties.size() );
- for ( final KeyValueType e : this.transformationOutputProperties )
- {
- clone.transformationOutputProperties.add( e.clone() );
- }
- }
- return clone;
- }
- catch ( final CloneNotSupportedException e )
- {
- throw new AssertionError( e );
- }
- }
- }