org.jomc.mojo.JomcResourceTransformer Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of maven-jomc-plugin Show documentation
Show all versions of maven-jomc-plugin Show documentation
Object management and configuration tools for Apache Maven.
/*
* Copyright (C) Christian Schulte, 2005-206
* 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: JomcResourceTransformer.java 4987 2014-11-15 19:51:47Z schulte $
*
*/
package org.jomc.mojo;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.MalformedURLException;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.jar.JarEntry;
import java.util.jar.JarOutputStream;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import javax.xml.bind.util.JAXBResult;
import javax.xml.bind.util.JAXBSource;
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.maven.plugins.shade.resource.ResourceTransformer;
import org.codehaus.plexus.logging.AbstractLogEnabled;
import org.codehaus.plexus.util.StringUtils;
import org.jomc.model.ModelObject;
import org.jomc.model.Module;
import org.jomc.model.Modules;
import org.jomc.model.modlet.DefaultModelProvider;
import org.jomc.modlet.DefaultModelContext;
import org.jomc.modlet.DefaultModletProvider;
import org.jomc.modlet.ModelContext;
import org.jomc.modlet.ModelContextFactory;
import org.jomc.modlet.ModelException;
import org.jomc.modlet.Modlet;
import org.jomc.modlet.ModletObject;
import org.jomc.modlet.Modlets;
/**
* Maven Shade Plugin {@code ResourceTransformer} implementation for shading JOMC resources.
*
* Maven Shade Plugin Usage
* <transformer implementation="org.jomc.mojo.JomcResourceTransformer">
* <model>http://jomc.org/model</model>
* <modelContextFactoryClassName>class name</modelContextFactoryClassName>
* <modelContextAttributes>
* <modelContextAttribute>
* <key>The name of the attribute</key>
* <value>The name of the attribute</value>
* <type>The name of the class of the object.</type>
* </modelContextAttribute>
* </modelContextAttributes/>
* <moduleEncoding>${project.build.sourceEncoding}</moduleEncoding>
* <moduleName>${project.name}</moduleName>
* <moduleVersion>${project.version}</moduleVersion>
* <moduleVendor>${project.organization.name}</moduleVendor>
* <moduleResource>META-INF/custom-jomc.xml</moduleResource>
* <moduleResources>
* <moduleResource>META-INF/jomc.xml</moduleResource>
* </moduleResources>
* <moduleIncludes>
* <moduleInclude>module name</moduleInclude>
* </moduleIncludes>
* <moduleExcludes>
* <moduleExclude>module name</moduleExclude>
* </moduleExcludes>
* <modletEncoding>${project.build.sourceEncoding}</modletEncoding>
* <modletName>${project.name}</modletName>
* <modletVersion>${project.version}</modletVersion>
* <modletVendor>${project.organization.name}</modletVendor>
* <modletResource>META-INF/custom-jomc-modlet.xml</modletResource>
* <modletResources>
* <modletResource>META-INF/jomc-modlet.xml</modletResource>
* </modletResources>
* <modletIncludes>
* <modletInclude>modlet name</modletInclude>
* </modletIncludes>
* <modletExcludes>
* <modletExclude>modlet name</modletExclude>
* </modletExcludes>
* <modelObjectStylesheet>Location of a XSLT document to use for transforming the merged model document.</modelObjectStylesheet>
* <modletObjectStylesheet>Location of a XSLT document to use for transforming the merged modlet document.</modletObjectStylesheet>
* <providerLocation>META-INF/custom-services</providerLocation>
* <platformProviderLocation>${java.home}/jre/lib/custom-jomc.properties</platformProviderLocation>
* <modletLocation>META-INF/custom-jomc-modlet.xml</modletLocation>
* <modletSchemaSystemId>http://custom.host.tld/custom/path/jomc-modlet-1.8.xsd</modletSchemaSystemId>
* </transformer>
*
*
* @author Christian Schulte
* @version $JOMC: JomcResourceTransformer.java 4987 2014-11-15 19:51:47Z schulte $
* @plexus.component role="org.apache.maven.plugins.shade.resource.ResourceTransformer"
* role-hint="JOMC"
*/
public class JomcResourceTransformer extends AbstractLogEnabled implements ResourceTransformer
{
/** Type of a resource. */
private enum ResourceType
{
/** Model object resource. */
MODEL_OBJECT_RESOURCE,
/** Modlet object resource. */
MODLET_OBJECT_RESOURCE
}
/** Prefix prepended to log messages. */
private static final String LOG_PREFIX = "[JOMC] ";
/** The identifier of the model to process. */
private String model = ModelObject.MODEL_PUBLIC_ID;
/** The encoding of the assembled module. */
private String moduleEncoding;
/** The name of the assembled module. */
private String moduleName;
/** The version of the assembled module. */
private String moduleVersion;
/** The vendor of the assembled module. */
private String moduleVendor;
/** The resource name of the assembled module. */
private String moduleResource = DefaultModelProvider.getDefaultModuleLocation();
/** Names of resources to process. */
private String[] moduleResources =
{
DefaultModelProvider.getDefaultModuleLocation()
};
/** Included modules. */
private List moduleIncludes;
/** Excluded modules. */
private List moduleExcludes;
/** The encoding of the assembled modlet. */
private String modletEncoding;
/** The name of the assembled modlet. */
private String modletName;
/** The version of the assembled modlet. */
private String modletVersion;
/** The vendor of the assembled modlet. */
private String modletVendor;
/** The resource name of the assembled modlet resources. */
private String modletResource = DefaultModletProvider.getDefaultModletLocation();
/** Names of modlet resources to process. */
private String[] modletResources =
{
DefaultModletProvider.getDefaultModletLocation()
};
/** Included modlets. */
private List modletIncludes;
/** Excluded modlets. */
private List modletExcludes;
/** Location of a XSLT document to use for transforming the merged model document. */
private String modelObjectStylesheet;
/** Location of a XSLT document to use for transforming the merged modlet document. */
private String modletObjectStylesheet;
/** The location to search for providers. */
private String providerLocation;
/** The location to search for platform providers. */
private String platformProviderLocation;
/** The system id of the modlet schema. */
private String modletSchemaSystemId;
/** The location to search for modlets. */
private String modletLocation;
/**
* Name of the {@code ModelContext} implementation class.
* @since 1.2
*/
private String modelContextFactoryClassName;
/**
* {@code ModelContext} attributes to apply.
* @since 1.2
*/
private List modelContextAttributes;
/** Modlet resources. */
private Modlets modlets = new Modlets();
/** Model resources. */
private Modules modules = new Modules();
/** Type of the currently processed resource or {@code null}. */
private ResourceType currentResourceType;
/** The JOMC JAXB marshaller of the instance. */
private Marshaller jomcMarshaller;
/** The JOMC JAXB unmarshaller of the instance. */
private Unmarshaller jomcUnmarshaller;
/** The modlet JAXB marshaller of the instance. */
private Marshaller modletMarshaller;
/** The modlet JAXB unmarshaller of the instance. */
private Unmarshaller modletUnmarshaller;
/** Creates a new {@code JomcResourceTransformer} instance. */
public JomcResourceTransformer()
{
super();
}
public boolean canTransformResource( final String arg )
{
boolean transformable = false;
this.currentResourceType = null;
final String name = normalizeResourceName( arg );
if ( name != null )
{
if ( this.moduleResources != null )
{
for ( String r : this.moduleResources )
{
if ( name.equals( normalizeResourceName( r ) ) )
{
this.currentResourceType = ResourceType.MODEL_OBJECT_RESOURCE;
if ( this.getLogger() != null && this.getLogger().isDebugEnabled() )
{
this.getLogger().debug( LOG_PREFIX + Messages.getMessage(
"processingModuleResource", arg ) );
}
transformable = true;
break;
}
}
}
if ( !transformable && this.modletResources != null )
{
for ( String r : this.modletResources )
{
if ( name.equals( normalizeResourceName( r ) ) )
{
this.currentResourceType = ResourceType.MODLET_OBJECT_RESOURCE;
if ( this.getLogger() != null && this.getLogger().isDebugEnabled() )
{
this.getLogger().debug( LOG_PREFIX + Messages.getMessage(
"processingModletResource", arg ) );
}
transformable = true;
break;
}
}
}
if ( !transformable && ( name.equals( normalizeResourceName( this.modletResource ) )
|| name.equals( normalizeResourceName( this.moduleResource ) ) ) )
{
if ( this.getLogger() != null && this.getLogger().isWarnEnabled() )
{
this.getLogger().warn( LOG_PREFIX + Messages.getMessage( "overridingResource", arg ) );
}
transformable = true;
this.currentResourceType = null;
}
}
return transformable;
}
public void processResource( final InputStream in ) throws IOException
{
try
{
if ( in != null && this.currentResourceType != null )
{
switch ( this.currentResourceType )
{
case MODEL_OBJECT_RESOURCE:
Object modelObject = this.unmarshalModelObject( in );
if ( modelObject instanceof JAXBElement> )
{
modelObject = ( (JAXBElement>) modelObject ).getValue();
}
if ( modelObject instanceof Modules )
{
this.modules.getModule().addAll( ( (Modules) modelObject ).getModule() );
}
if ( modelObject instanceof Module )
{
this.modules.getModule().add( (Module) modelObject );
}
break;
case MODLET_OBJECT_RESOURCE:
Object modletObject = this.unmarshalModletObject( in );
if ( modletObject instanceof JAXBElement> )
{
modletObject = ( (JAXBElement>) modletObject ).getValue();
}
if ( modletObject instanceof Modlets )
{
this.modlets.getModlet().addAll( ( (Modlets) modletObject ).getModlet() );
}
if ( modletObject instanceof Modlet )
{
this.modlets.getModlet().add( (Modlet) modletObject );
}
break;
default:
throw new AssertionError( this.currentResourceType );
}
}
}
catch ( final InstantiationException e )
{
// JDK: As of JDK 6, "new IOException( message, cause )".
throw (IOException) new IOException( Messages.getMessage( e ) ).initCause( e );
}
catch ( final JAXBException e )
{
String message = Messages.getMessage( e );
if ( message == null && e.getLinkedException() != null )
{
message = Messages.getMessage( e.getLinkedException() );
}
// JDK: As of JDK 6, "new IOException( message, cause )".
throw (IOException) new IOException( message ).initCause( e );
}
catch ( final ModelException e )
{
// JDK: As of JDK 6, "new IOException( message, cause )".
throw (IOException) new IOException( Messages.getMessage( e ) ).initCause( e );
}
}
public void processResource( final String name, final InputStream in, final List relocators ) throws IOException
{
this.processResource( in );
}
public boolean hasTransformedResource()
{
return !( this.modules.getModule().isEmpty() && this.modlets.getModlet().isEmpty() );
}
public void modifyOutputStream( final JarOutputStream out ) throws IOException
{
if ( StringUtils.isEmpty( this.model ) )
{
throw new IOException( Messages.getMessage( "mandatoryParameter", "model" ) );
}
if ( StringUtils.isEmpty( this.modletName ) )
{
throw new IOException( Messages.getMessage( "mandatoryParameter", "modletName" ) );
}
if ( StringUtils.isEmpty( this.modletResource ) )
{
throw new IOException( Messages.getMessage( "mandatoryParameter", "modletResource" ) );
}
if ( StringUtils.isEmpty( this.moduleName ) )
{
throw new IOException( Messages.getMessage( "mandatoryParameter", "moduleName" ) );
}
if ( StringUtils.isEmpty( this.moduleResource ) )
{
throw new IOException( Messages.getMessage( "mandatoryParameter", "moduleResource" ) );
}
try
{
if ( !this.modules.getModule().isEmpty() )
{
if ( this.moduleIncludes != null )
{
for ( final Iterator it = this.modules.getModule().iterator(); it.hasNext(); )
{
final Module m = it.next();
if ( !this.moduleIncludes.contains( m.getName() ) )
{
it.remove();
if ( this.getLogger() != null && this.getLogger().isInfoEnabled() )
{
this.getLogger().info( LOG_PREFIX + Messages.getMessage(
"excludingModule", m.getName() ) );
}
}
}
}
if ( this.moduleExcludes != null )
{
for ( String exclude : this.moduleExcludes )
{
final Module excluded = this.modules.getModule( exclude );
if ( excluded != null )
{
this.modules.getModule().remove( excluded );
if ( this.getLogger() != null && this.getLogger().isInfoEnabled() )
{
this.getLogger().info( LOG_PREFIX + Messages.getMessage(
"excludingModule", excluded.getName() ) );
}
}
}
}
if ( this.getLogger() != null && this.getLogger().isInfoEnabled() )
{
for ( Module m : this.modules.getModule() )
{
this.getLogger().info( LOG_PREFIX + Messages.getMessage( "includingModule", m.getName() ) );
}
}
final Module mergedModule = this.modules.getMergedModule( this.moduleName );
mergedModule.setVersion( this.moduleVersion );
mergedModule.setVendor( this.moduleVendor );
final JAXBElement transformedModule = this.transformModelObject(
new org.jomc.model.ObjectFactory().createModule( mergedModule ), Module.class );
out.putNextEntry( new JarEntry( normalizeResourceName( this.moduleResource ) ) );
this.marshalModelObject( transformedModule, out );
}
if ( !this.modlets.getModlet().isEmpty() )
{
if ( this.modletIncludes != null )
{
for ( final Iterator it = this.modlets.getModlet().iterator(); it.hasNext(); )
{
final Modlet m = it.next();
if ( !this.modletIncludes.contains( m.getName() ) )
{
it.remove();
if ( this.getLogger() != null && this.getLogger().isInfoEnabled() )
{
this.getLogger().info( LOG_PREFIX + Messages.getMessage(
"excludingModlet", m.getName() ) );
}
}
}
}
if ( this.modletExcludes != null )
{
for ( String exclude : this.modletExcludes )
{
final Modlet excluded = this.modlets.getModlet( exclude );
if ( excluded != null )
{
this.modlets.getModlet().remove( excluded );
if ( this.getLogger() != null && this.getLogger().isInfoEnabled() )
{
this.getLogger().info( LOG_PREFIX + Messages.getMessage(
"excludingModlet", excluded.getName() ) );
}
}
}
}
if ( this.getLogger() != null && this.getLogger().isInfoEnabled() )
{
for ( Modlet m : this.modlets.getModlet() )
{
this.getLogger().info( LOG_PREFIX + Messages.getMessage( "includingModlet", m.getName() ) );
}
}
final Modlet mergedModlet = this.modlets.getMergedModlet( this.modletName, this.model );
mergedModlet.setVendor( this.modletVendor );
mergedModlet.setVersion( this.modletVersion );
final JAXBElement transformedModlet = this.transformModletObject(
new org.jomc.modlet.ObjectFactory().createModlet( mergedModlet ), Modlet.class );
out.putNextEntry( new JarEntry( normalizeResourceName( this.modletResource ) ) );
this.marshalModletObject( transformedModlet, out );
}
}
catch ( final InstantiationException e )
{
// JDK: As of JDK 6, "new IOException( message, cause )".
throw (IOException) new IOException( Messages.getMessage( e ) ).initCause( e );
}
catch ( final TransformerConfigurationException e )
{
String message = Messages.getMessage( e );
if ( message == null && e.getException() != null )
{
message = Messages.getMessage( e.getException() );
}
// JDK: As of JDK 6, "new IOException( message, cause )".
throw (IOException) new IOException( message ).initCause( e );
}
catch ( final TransformerException e )
{
String message = Messages.getMessage( e );
if ( message == null && e.getException() != null )
{
message = Messages.getMessage( e.getException() );
}
// JDK: As of JDK 6, "new IOException( message, cause )".
throw (IOException) new IOException( message ).initCause( e );
}
catch ( final JAXBException e )
{
String message = Messages.getMessage( e );
if ( message == null && e.getLinkedException() != null )
{
message = Messages.getMessage( e.getLinkedException() );
}
// JDK: As of JDK 6, "new IOException( message, cause )".
throw (IOException) new IOException( message ).initCause( e );
}
catch ( final ModelException e )
{
// JDK: As of JDK 6, "new IOException( message, cause )".
throw (IOException) new IOException( Messages.getMessage( e ) ).initCause( e );
}
catch ( final URISyntaxException e )
{
// JDK: As of JDK 6, "new IOException( message, cause )".
throw (IOException) new IOException( Messages.getMessage( e ) ).initCause( e );
}
finally
{
this.modlets = new Modlets();
this.modules = new Modules();
this.jomcMarshaller = null;
this.jomcUnmarshaller = null;
this.modletMarshaller = null;
this.modletUnmarshaller = null;
}
}
/**
* Creates an {@code URL} for a given resource location.
* This method first searches the class loader of the class 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. If that file is found, the URL of that file is returned. Otherwise an
* {@code IOException} is thrown.
*
* @param location The location to create an {@code URL} from.
*
* @return An {@code URL} for {@code location}.
*
* @throws NullPointerException if {@code location} is {@code null}.
* @throws IOException if creating an URL fails.
*
* @since 1.2
*/
protected URL getResource( final String location ) throws IOException
{
if ( location == null )
{
throw new NullPointerException( "location" );
}
try
{
String absolute = location;
if ( !absolute.startsWith( "/" ) )
{
absolute = "/" + location;
}
URL resource = this.getClass().getResource( absolute );
if ( resource == null )
{
try
{
resource = new URL( location );
}
catch ( final MalformedURLException e )
{
if ( this.getLogger() != null && this.getLogger().isDebugEnabled() )
{
this.getLogger().debug( Messages.getMessage( e ), e );
}
resource = null;
}
}
if ( resource == null )
{
final File f = new File( location );
if ( f.isFile() )
{
resource = f.toURI().toURL();
}
}
if ( resource == null )
{
throw new IOException( Messages.getMessage( "resourceNotFound", location ) );
}
return resource;
}
catch ( final MalformedURLException e )
{
String m = Messages.getMessage( e );
m = m == null ? "" : " " + m;
// JDK: As of JDK 6, "new IOException( message, cause )".
throw (IOException) new IOException( Messages.getMessage(
"malformedLocation", location, m ) ).initCause( e );
}
}
private Object unmarshalModelObject( final InputStream in )
throws ModelException, JAXBException, InstantiationException
{
if ( in == null )
{
throw new NullPointerException( "in" );
}
if ( this.jomcUnmarshaller == null )
{
this.jomcUnmarshaller = this.createModelContext().createUnmarshaller( this.model );
}
return this.jomcUnmarshaller.unmarshal( in );
}
private void marshalModelObject( final JAXBElement extends ModelObject> element, final OutputStream out )
throws ModelException, JAXBException, InstantiationException
{
if ( element == null )
{
throw new NullPointerException( "element" );
}
if ( out == null )
{
throw new NullPointerException( "out" );
}
if ( this.jomcMarshaller == null )
{
final ModelContext modelContext = this.createModelContext();
this.jomcMarshaller = modelContext.createMarshaller( this.model );
this.jomcMarshaller.setSchema( modelContext.createSchema( this.model ) );
this.jomcMarshaller.setProperty( Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE );
if ( this.moduleEncoding != null )
{
this.jomcMarshaller.setProperty( Marshaller.JAXB_ENCODING, this.moduleEncoding );
}
}
this.jomcMarshaller.marshal( element, out );
}
private JAXBElement transformModelObject( final JAXBElement extends ModelObject> element,
final Class boundType )
throws ModelException, TransformerException, JAXBException, IOException, URISyntaxException,
InstantiationException
{
if ( element == null )
{
throw new NullPointerException( "element" );
}
if ( !boundType.isInstance( element.getValue() ) )
{
throw new IllegalArgumentException( element.toString() );
}
@SuppressWarnings( "unchecked" )
JAXBElement transformed = (JAXBElement) element;
if ( this.modelObjectStylesheet != null )
{
final Transformer transformer = TransformerFactory.newInstance().newTransformer(
new StreamSource( this.getResource( this.modelObjectStylesheet ).toURI().toASCIIString() ) );
final ModelContext modelContext = this.createModelContext();
final Marshaller marshaller = modelContext.createMarshaller( this.model );
final Unmarshaller unmarshaller = modelContext.createUnmarshaller( this.model );
final JAXBSource source = new JAXBSource( marshaller, element );
final JAXBResult result = new JAXBResult( unmarshaller );
for ( Map.Entry
© 2015 - 2025 Weber Informatics LLC | Privacy Policy