DefaultModelContext.java
/*
* Copyright (C) Christian Schulte <cs@schulte.it>, 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: DefaultModelContext.java 5051 2015-05-30 17:29:32Z schulte $
*
*/
package org.jomc.modlet;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.ResourceBundle;
import java.util.Set;
import java.util.StringTokenizer;
import java.util.TreeMap;
import java.util.jar.Attributes;
import java.util.jar.Manifest;
import java.util.logging.Level;
import javax.xml.XMLConstants;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import javax.xml.transform.Source;
import javax.xml.transform.sax.SAXSource;
import javax.xml.validation.SchemaFactory;
import javax.xml.validation.Validator;
import org.w3c.dom.ls.LSInput;
import org.w3c.dom.ls.LSResourceResolver;
import org.xml.sax.EntityResolver;
import org.xml.sax.ErrorHandler;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
import org.xml.sax.helpers.DefaultHandler;
/**
* Default {@code ModelContext} implementation.
*
* @author <a href="mailto:cs@schulte.it">Christian Schulte</a>
* @version $JOMC: DefaultModelContext.java 5051 2015-05-30 17:29:32Z schulte $
* @see ModelContextFactory
*/
public class DefaultModelContext extends ModelContext
{
/**
* Constant for the name of the model context attribute backing property {@code providerLocation}.
*
* @see #getProviderLocation()
* @see ModelContext#getAttribute(java.lang.String)
* @since 1.2
*/
public static final String PROVIDER_LOCATION_ATTRIBUTE_NAME =
"org.jomc.modlet.DefaultModelContext.providerLocationAttribute";
/**
* Constant for the name of the model context attribute backing property {@code platformProviderLocation}.
*
* @see #getPlatformProviderLocation()
* @see ModelContext#getAttribute(java.lang.String)
* @since 1.2
*/
public static final String PLATFORM_PROVIDER_LOCATION_ATTRIBUTE_NAME =
"org.jomc.modlet.DefaultModelContext.platformProviderLocationAttribute";
/**
* Supported schema name extensions.
*/
private static final String[] SCHEMA_EXTENSIONS = new String[]
{
"xsd"
};
/**
* Class path location searched for providers by default.
*
* @see #getDefaultProviderLocation()
*/
private static final String DEFAULT_PROVIDER_LOCATION = "META-INF/services";
/**
* Location searched for platform providers by default.
*
* @see #getDefaultPlatformProviderLocation()
*/
private static final String DEFAULT_PLATFORM_PROVIDER_LOCATION =
new StringBuilder( 255 ).append( System.getProperty( "java.home" ) ).append( File.separator ).append( "lib" ).
append( File.separator ).append( "jomc.properties" ).toString();
/**
* Constant for the service identifier of marshaller listener services.
*
* @since 1.2
*/
private static final String MARSHALLER_LISTENER_SERVICE = "javax.xml.bind.Marshaller.Listener";
/**
* Constant for the service identifier of unmarshaller listener services.
*
* @since 1.2
*/
private static final String UNMARSHALLER_LISTENER_SERVICE = "javax.xml.bind.Unmarshaller.Listener";
/**
* Default provider location.
*/
private static volatile String defaultProviderLocation;
/**
* Default platform provider location.
*/
private static volatile String defaultPlatformProviderLocation;
/**
* Provider location of the instance.
*/
private String providerLocation;
/**
* Platform provider location of the instance.
*/
private String platformProviderLocation;
/**
* Creates a new {@code DefaultModelContext} instance.
*
* @since 1.2
*/
public DefaultModelContext()
{
super();
}
/**
* Creates a new {@code DefaultModelContext} instance taking a class loader.
*
* @param classLoader The class loader of the context.
*/
public DefaultModelContext( final ClassLoader classLoader )
{
super( classLoader );
}
/**
* Gets the default location searched for provider resources.
* <p>
* The default provider location is controlled by system property
* {@code org.jomc.modlet.DefaultModelContext.defaultProviderLocation} holding the location to search
* for provider resources by default. If that property is not set, the {@code META-INF/services} default is
* returned.
* </p>
*
* @return The location searched for provider resources by default.
*
* @see #setDefaultProviderLocation(java.lang.String)
*/
public static String getDefaultProviderLocation()
{
if ( defaultProviderLocation == null )
{
defaultProviderLocation = System.getProperty(
"org.jomc.modlet.DefaultModelContext.defaultProviderLocation", DEFAULT_PROVIDER_LOCATION );
}
return defaultProviderLocation;
}
/**
* Sets the default location searched for provider resources.
*
* @param value The new default location to search for provider resources or {@code null}.
*
* @see #getDefaultProviderLocation()
*/
public static void setDefaultProviderLocation( final String value )
{
defaultProviderLocation = value;
}
/**
* Gets the location searched for provider resources.
*
* @return The location searched for provider resources.
*
* @see #getDefaultProviderLocation()
* @see #setProviderLocation(java.lang.String)
* @see #PROVIDER_LOCATION_ATTRIBUTE_NAME
*/
public final String getProviderLocation()
{
if ( this.providerLocation == null )
{
this.providerLocation = getDefaultProviderLocation();
if ( DEFAULT_PROVIDER_LOCATION.equals( this.providerLocation )
&& this.getAttribute( PROVIDER_LOCATION_ATTRIBUTE_NAME ) instanceof String )
{
final String contextProviderLocation = (String) this.getAttribute( PROVIDER_LOCATION_ATTRIBUTE_NAME );
if ( this.isLoggable( Level.CONFIG ) )
{
this.log( Level.CONFIG, getMessage( "contextProviderLocationInfo",
contextProviderLocation ), null );
}
this.providerLocation = null;
return contextProviderLocation;
}
else if ( this.isLoggable( Level.CONFIG ) )
{
this.log( Level.CONFIG, getMessage( "defaultProviderLocationInfo", this.providerLocation ), null );
}
}
return this.providerLocation;
}
/**
* Sets the location searched for provider resources.
*
* @param value The new location to search for provider resources or {@code null}.
*
* @see #getProviderLocation()
*/
public final void setProviderLocation( final String value )
{
this.providerLocation = value;
}
/**
* Gets the default location searched for platform provider resources.
* <p>
* The default platform provider location is controlled by system property
* {@code org.jomc.modlet.DefaultModelContext.defaultPlatformProviderLocation} holding the location to
* search for platform provider resources by default. If that property is not set, the
* {@code <java-home>/lib/jomc.properties} default is returned.
* </p>
*
* @return The location searched for platform provider resources by default.
*
* @see #setDefaultPlatformProviderLocation(java.lang.String)
*/
public static String getDefaultPlatformProviderLocation()
{
if ( defaultPlatformProviderLocation == null )
{
defaultPlatformProviderLocation = System.getProperty(
"org.jomc.modlet.DefaultModelContext.defaultPlatformProviderLocation",
DEFAULT_PLATFORM_PROVIDER_LOCATION );
}
return defaultPlatformProviderLocation;
}
/**
* Sets the default location searched for platform provider resources.
*
* @param value The new default location to search for platform provider resources or {@code null}.
*
* @see #getDefaultPlatformProviderLocation()
*/
public static void setDefaultPlatformProviderLocation( final String value )
{
defaultPlatformProviderLocation = value;
}
/**
* Gets the location searched for platform provider resources.
*
* @return The location searched for platform provider resources.
*
* @see #getDefaultPlatformProviderLocation()
* @see #setPlatformProviderLocation(java.lang.String)
* @see #PLATFORM_PROVIDER_LOCATION_ATTRIBUTE_NAME
*/
public final String getPlatformProviderLocation()
{
if ( this.platformProviderLocation == null )
{
this.platformProviderLocation = getDefaultPlatformProviderLocation();
if ( DEFAULT_PLATFORM_PROVIDER_LOCATION.equals( this.platformProviderLocation )
&& this.getAttribute( PLATFORM_PROVIDER_LOCATION_ATTRIBUTE_NAME ) instanceof String )
{
final String contextPlatformProviderLocation =
(String) this.getAttribute( PLATFORM_PROVIDER_LOCATION_ATTRIBUTE_NAME );
if ( this.isLoggable( Level.CONFIG ) )
{
this.log( Level.CONFIG, getMessage( "contextPlatformProviderLocationInfo",
contextPlatformProviderLocation ), null );
}
this.platformProviderLocation = null;
return contextPlatformProviderLocation;
}
else if ( this.isLoggable( Level.CONFIG ) )
{
this.log( Level.CONFIG,
getMessage( "defaultPlatformProviderLocationInfo", this.platformProviderLocation ), null );
}
}
return this.platformProviderLocation;
}
/**
* Sets the location searched 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;
}
/**
* {@inheritDoc}
* <p>
* This method loads {@code ModletProvider} classes setup via the platform provider configuration file and
* {@code <provider-location>/org.jomc.modlet.ModletProvider} resources to return a list of {@code Modlets}.
* </p>
*
* @see #getProviderLocation()
* @see #getPlatformProviderLocation()
* @see ModletProvider#findModlets(org.jomc.modlet.ModelContext, org.jomc.modlet.Modlets)
* @deprecated As of JOMC 1.6, replaced by {@link #findModlets(org.jomc.modlet.Modlets)}. This method will be
* removed in JOMC 2.0.
*/
@Override
@Deprecated
public Modlets findModlets() throws ModelException
{
return this.findModlets( new Modlets() );
}
/**
* {@inheritDoc}
* <p>
* This method loads {@code ModletProvider} classes setup via the platform provider configuration file and
* {@code <provider-location>/org.jomc.modlet.ModletProvider} resources to return a list of {@code Modlets}.
* </p>
*
* @see #getProviderLocation()
* @see #getPlatformProviderLocation()
* @see ModletProvider#findModlets(org.jomc.modlet.ModelContext, org.jomc.modlet.Modlets)
* @since 1.6
*/
@Override
public Modlets findModlets( final Modlets modlets ) throws ModelException
{
if ( modlets == null )
{
throw new NullPointerException( "modlets" );
}
Modlets found = modlets.clone();
final Collection<ModletProvider> providers = this.loadModletServices( ModletProvider.class );
for ( final ModletProvider provider : providers )
{
if ( this.isLoggable( Level.FINER ) )
{
this.log( Level.FINER, getMessage( "creatingModlets", provider.toString() ), null );
}
final Modlets provided = provider.findModlets( this, found );
if ( provided != null )
{
found = provided;
}
}
if ( this.isLoggable( Level.FINEST ) )
{
for ( final Modlet m : found.getModlet() )
{
this.log( Level.FINEST,
getMessage( "modletInfo", m.getName(), m.getModel(),
m.getVendor() != null
? m.getVendor() : getMessage( "noVendor" ),
m.getVersion() != null
? m.getVersion() : getMessage( "noVersion" ) ), null );
if ( m.getSchemas() != null )
{
for ( final Schema s : m.getSchemas().getSchema() )
{
this.log( Level.FINEST,
getMessage( "modletSchemaInfo", m.getName(), s.getPublicId(), s.getSystemId(),
s.getContextId() != null
? s.getContextId() : getMessage( "noContext" ),
s.getClasspathId() != null
? s.getClasspathId() : getMessage( "noClasspathId" ) ), null );
}
}
if ( m.getServices() != null )
{
for ( final Service s : m.getServices().getService() )
{
this.log( Level.FINEST, getMessage( "modletServiceInfo", m.getName(), s.getOrdinal(),
s.getIdentifier(), s.getClazz() ), null );
}
}
}
}
return found;
}
/**
* {@inheritDoc}
* <p>
* This method loads {@code ModletProcessor} classes setup via the platform provider configuration file and
* {@code <provider-location>/org.jomc.modlet.ModletProcessor} resources to process a list of {@code Modlets}.
* </p>
*
* @see #getProviderLocation()
* @see #getPlatformProviderLocation()
* @see ModletProcessor#processModlets(org.jomc.modlet.ModelContext, org.jomc.modlet.Modlets)
* @since 1.6
*/
@Override
public Modlets processModlets( final Modlets modlets ) throws ModelException
{
if ( modlets == null )
{
throw new NullPointerException( "modlets" );
}
Modlets result = modlets.clone();
final Collection<ModletProcessor> processors = this.loadModletServices( ModletProcessor.class );
for ( final ModletProcessor processor : processors )
{
if ( this.isLoggable( Level.FINER ) )
{
this.log( Level.FINER, getMessage( "processingModlets", processor.toString() ), null );
}
final Modlets processed = processor.processModlets( this, result );
if ( processed != null )
{
result = processed;
}
}
return result;
}
/**
* {@inheritDoc}
* <p>
* This method loads {@code ModletValidator} classes setup via the platform provider configuration file and
* {@code <provider-location>/org.jomc.modlet.ModletValidator} resources to validate a list of {@code Modlets}.
* </p>
*
* @see #getProviderLocation()
* @see #getPlatformProviderLocation()
* @see ModletValidator#validateModlets(org.jomc.modlet.ModelContext, org.jomc.modlet.Modlets)
* @since 1.9
*/
@Override
public ModelValidationReport validateModlets( final Modlets modlets ) throws ModelException
{
if ( modlets == null )
{
throw new NullPointerException( "modlets" );
}
final ModelValidationReport report = new ModelValidationReport();
final Collection<ModletValidator> modletValidators = this.loadModletServices( ModletValidator.class );
for ( final ModletValidator modletValidator : modletValidators )
{
if ( this.isLoggable( Level.FINER ) )
{
this.log( Level.FINER, getMessage( "validatingModlets", modletValidator.toString() ), null );
}
final ModelValidationReport current = modletValidator.validateModlets( this, modlets );
if ( current != null )
{
report.getDetails().addAll( current.getDetails() );
}
}
return report;
}
/**
* {@inheritDoc}
* <p>
* This method creates all {@code ModelProvider} service objects of the model identified by {@code model} to create
* a new {@code Model} instance.
* </p>
*
* @see #findModel(org.jomc.modlet.Model)
* @see #createServiceObjects(java.lang.String, java.lang.String, java.lang.Class) createServiceObjects( model, ModelProvider.class.getName(), ModelProvider.class )
* @see ModelProvider#findModel(org.jomc.modlet.ModelContext, org.jomc.modlet.Model)
*/
@Override
public Model findModel( final String model ) throws ModelException
{
if ( model == null )
{
throw new NullPointerException( "model" );
}
final Model m = new Model();
m.setIdentifier( model );
return this.findModel( m );
}
/**
* {@inheritDoc}
* <p>
* This method creates all {@code ModelProvider} service objects of the given model to populate the given model
* instance.
* </p>
*
* @see #createServiceObjects(java.lang.String, java.lang.String, java.lang.Class) createServiceObjects( model, ModelProvider.class.getName(), ModelProvider.class )
* @see ModelProvider#findModel(org.jomc.modlet.ModelContext, org.jomc.modlet.Model)
*
* @since 1.2
*/
@Override
public Model findModel( final Model model ) throws ModelException
{
if ( model == null )
{
throw new NullPointerException( "model" );
}
Model m = model.clone();
final long t0 = System.currentTimeMillis();
for ( final ModelProvider provider
: this.createServiceObjects( model.getIdentifier(), ModelProvider.class.getName(),
ModelProvider.class ) )
{
if ( this.isLoggable( Level.FINER ) )
{
this.log( Level.FINER, getMessage( "creatingModel", m.getIdentifier(), provider.toString() ), null );
}
final Model provided = provider.findModel( this, m );
if ( provided != null )
{
m = provided;
}
}
if ( this.isLoggable( Level.FINE ) )
{
this.log( Level.FINE, getMessage( "findModelReport", m.getIdentifier(), System.currentTimeMillis() - t0 ),
null );
}
return m;
}
/**
* {@inheritDoc}
* <p>
* This method creates all {@code ModelProcessor} service objects of {@code model} to process the given
* {@code Model}.
* </p>
*
* @see #createServiceObjects(java.lang.String, java.lang.String, java.lang.Class) createServiceObjects( model, ModelProcessor.class.getName(), ModelProcessor.class )
* @see ModelProcessor#processModel(org.jomc.modlet.ModelContext, org.jomc.modlet.Model)
*/
@Override
public Model processModel( final Model model ) throws ModelException
{
if ( model == null )
{
throw new NullPointerException( "model" );
}
Model processed = model;
final long t0 = System.currentTimeMillis();
for ( final ModelProcessor processor
: this.createServiceObjects( model.getIdentifier(), ModelProcessor.class.getName(),
ModelProcessor.class ) )
{
if ( this.isLoggable( Level.FINER ) )
{
this.log( Level.FINER, getMessage( "processingModel", model.getIdentifier(),
processor.toString() ), null );
}
final Model current = processor.processModel( this, processed );
if ( current != null )
{
processed = current;
}
}
if ( this.isLoggable( Level.FINE ) )
{
this.log( Level.FINE, getMessage( "processModelReport", model.getIdentifier(),
System.currentTimeMillis() - t0 ), null );
}
return processed;
}
/**
* {@inheritDoc}
* <p>
* This method creates all {@code ModelValidator} service objects of {@code model} to validate the given
* {@code Model}.
* </p>
*
* @see #createServiceObjects(java.lang.String, java.lang.String, java.lang.Class) createServiceObjects( model, ModelValidator.class.getName(), ModelValidator.class )
* @see ModelValidator#validateModel(org.jomc.modlet.ModelContext, org.jomc.modlet.Model)
*/
@Override
public ModelValidationReport validateModel( final Model model ) throws ModelException
{
if ( model == null )
{
throw new NullPointerException( "model" );
}
final long t0 = System.currentTimeMillis();
final ModelValidationReport report = new ModelValidationReport();
for ( final ModelValidator validator
: this.createServiceObjects( model.getIdentifier(), ModelValidator.class.getName(),
ModelValidator.class ) )
{
if ( this.isLoggable( Level.FINER ) )
{
this.log( Level.FINER, getMessage( "validatingModel", model.getIdentifier(),
validator.toString() ), null );
}
final ModelValidationReport current = validator.validateModel( this, model );
if ( current != null )
{
report.getDetails().addAll( current.getDetails() );
}
}
if ( this.isLoggable( Level.FINE ) )
{
this.log( Level.FINE, getMessage( "validateModelReport", model.getIdentifier(),
System.currentTimeMillis() - t0 ), null );
}
return report;
}
/**
* {@inheritDoc}
*
* @see #createSchema(java.lang.String)
*/
@Override
public ModelValidationReport validateModel( final String model, final Source source ) throws ModelException
{
if ( model == null )
{
throw new NullPointerException( "model" );
}
if ( source == null )
{
throw new NullPointerException( "source" );
}
final long t0 = System.currentTimeMillis();
final javax.xml.validation.Schema schema = this.createSchema( model );
final Validator validator = schema.newValidator();
final ModelErrorHandler modelErrorHandler = new ModelErrorHandler( this );
validator.setErrorHandler( modelErrorHandler );
try
{
validator.validate( source );
}
catch ( final SAXException e )
{
String message = getMessage( e );
if ( message == null && e.getException() != null )
{
message = getMessage( e.getException() );
}
if ( this.isLoggable( Level.FINE ) )
{
this.log( Level.FINE, message, e );
}
if ( modelErrorHandler.getReport().isModelValid() )
{
throw new ModelException( message, e );
}
}
catch ( final IOException e )
{
throw new ModelException( getMessage( e ), e );
}
if ( this.isLoggable( Level.FINE ) )
{
this.log( Level.FINE, getMessage( "validateModelReport", model, System.currentTimeMillis() - t0 ), null );
}
return modelErrorHandler.getReport();
}
@Override
public EntityResolver createEntityResolver( final String model ) throws ModelException
{
if ( model == null )
{
throw new NullPointerException( "model" );
}
return this.createEntityResolver( this.getModlets().getSchemas( model ) );
}
@Override
@Deprecated
public EntityResolver createEntityResolver( final URI publicId ) throws ModelException
{
if ( publicId == null )
{
throw new NullPointerException( "publicId" );
}
return this.createEntityResolver( this.getModlets().getSchemas( publicId ) );
}
@Override
public LSResourceResolver createResourceResolver( final String model ) throws ModelException
{
if ( model == null )
{
throw new NullPointerException( "model" );
}
return this.createResourceResolver( this.createEntityResolver( model ) );
}
@Override
@Deprecated
public LSResourceResolver createResourceResolver( final URI publicId ) throws ModelException
{
if ( publicId == null )
{
throw new NullPointerException( "publicId" );
}
return this.createResourceResolver( this.createEntityResolver( publicId ) );
}
@Override
public javax.xml.validation.Schema createSchema( final String model ) throws ModelException
{
if ( model == null )
{
throw new NullPointerException( "model" );
}
return this.createSchema( this.getModlets().getSchemas( model ), this.createEntityResolver( model ),
this.createResourceResolver( model ), model, null );
}
@Override
@Deprecated
public javax.xml.validation.Schema createSchema( final URI publicId ) throws ModelException
{
if ( publicId == null )
{
throw new NullPointerException( "publicId" );
}
return this.createSchema( this.getModlets().getSchemas( publicId ), this.createEntityResolver( publicId ),
this.createResourceResolver( publicId ), null, publicId );
}
@Override
public JAXBContext createContext( final String model ) throws ModelException
{
if ( model == null )
{
throw new NullPointerException( "model" );
}
return this.createContext( this.getModlets().getSchemas( model ), model, null );
}
@Override
@Deprecated
public JAXBContext createContext( final URI publicId ) throws ModelException
{
if ( publicId == null )
{
throw new NullPointerException( "publicId" );
}
return this.createContext( this.getModlets().getSchemas( publicId ), null, publicId );
}
@Override
public Marshaller createMarshaller( final String model ) throws ModelException
{
if ( model == null )
{
throw new NullPointerException( "model" );
}
return this.createMarshaller( model, null );
}
@Override
@Deprecated
public Marshaller createMarshaller( final URI publicId ) throws ModelException
{
if ( publicId == null )
{
throw new NullPointerException( "publicId" );
}
return this.createMarshaller( null, publicId );
}
@Override
public Unmarshaller createUnmarshaller( final String model ) throws ModelException
{
if ( model == null )
{
throw new NullPointerException( "model" );
}
return this.createUnmarshaller( model, null );
}
@Override
@Deprecated
public Unmarshaller createUnmarshaller( final URI publicId ) throws ModelException
{
if ( publicId == null )
{
throw new NullPointerException( "publicId" );
}
return this.createUnmarshaller( null, publicId );
}
/**
* {@inheritDoc}
* <p>
* This method loads {@code ServiceFactory} classes setup via the platform provider configuration file and
* {@code <provider-location>/org.jomc.modlet.ServiceFactory} resources to create a new service object.
* </p>
*
* @since 1.9
*/
@Override
public <T> Collection<? extends T> createServiceObjects( final String model, final String service,
final Class<T> type )
throws ModelException
{
if ( model == null )
{
throw new NullPointerException( "model" );
}
if ( service == null )
{
throw new NullPointerException( "service" );
}
if ( type == null )
{
throw new NullPointerException( "type" );
}
final Services modelServices = this.getModlets().getServices( model );
final Collection<T> serviceObjects =
new ArrayList<T>( modelServices != null ? modelServices.getService().size() : 0 );
if ( modelServices != null )
{
final Collection<ServiceFactory> factories = this.loadModletServices( ServiceFactory.class );
for ( final Service s : modelServices.getServices( service ) )
{
serviceObjects.add( this.createServiceObject( s, type, factories ) );
}
}
return Collections.unmodifiableCollection( serviceObjects );
}
/**
* {@inheritDoc}
* <p>
* This method loads {@code ServiceFactory} classes setup via the platform provider configuration file and
* {@code <provider-location>/org.jomc.modlet.ServiceFactory} resources to create a new service object.
* </p>
*
* @see #getProviderLocation()
* @see #getPlatformProviderLocation()
* @see ServiceFactory#createServiceObject(org.jomc.modlet.ModelContext, org.jomc.modlet.Service, java.lang.Class)
* @since 1.2
* @deprecated As of JOMC 1.9, please use method {@link #createServiceObjects(java.lang.String, java.lang.String, java.lang.Class)}.
* This method will be removed in JOMC 2.0.
*/
@Override
@Deprecated
public <T> T createServiceObject( final Service service, final Class<T> type ) throws ModelException
{
if ( service == null )
{
throw new NullPointerException( "service" );
}
if ( type == null )
{
throw new NullPointerException( "type" );
}
return this.createServiceObject( service, type, this.loadModletServices( ServiceFactory.class ) );
}
/**
* This method creates a new service object for a given service using a given collection of service factories.
*
* @param <T> The type of the service.
* @param service The service to create a new object of.
* @param type The class of the type of the service.
* @param factories The service factories to use for creating the new service object.
*
* @return An new service object for {@code service}.
*
* @throws NullPointerException if {@code service}, {@code type} or {@code factories} is {@code null}.
* @throws ModelException if creating the service object fails.
* @since 1.9
*/
private <T> T createServiceObject( final Service service, final Class<T> type,
final Collection<ServiceFactory> factories ) throws ModelException
{
if ( service == null )
{
throw new NullPointerException( "service" );
}
if ( type == null )
{
throw new NullPointerException( "type" );
}
if ( factories == null )
{
throw new NullPointerException( "factories" );
}
T serviceObject = null;
for ( final ServiceFactory factory : factories )
{
final T current = factory.createServiceObject( this, service, type );
if ( current != null )
{
if ( this.isLoggable( Level.FINER ) )
{
this.log( Level.FINER, getMessage( "creatingService", service.getOrdinal(), service.getIdentifier(),
service.getClazz(), factory.toString() ), null );
}
serviceObject = current;
break;
}
}
if ( serviceObject == null )
{
throw new ModelException( getMessage( "serviceNotCreated", service.getOrdinal(), service.getIdentifier(),
service.getClazz() ), null );
}
return serviceObject;
}
private <T> Collection<T> loadModletServices( final Class<T> serviceClass ) throws ModelException
{
try
{
final String serviceNamePrefix = serviceClass.getName() + ".";
final Map<String, T> sortedPlatformServices = new TreeMap<String, T>( new Comparator<String>()
{
public int compare( final String key1, final String key2 )
{
return key1.compareTo( key2 );
}
} );
final File platformServices = new File( this.getPlatformProviderLocation() );
if ( platformServices.exists() )
{
if ( this.isLoggable( Level.FINEST ) )
{
this.log( Level.FINEST, getMessage( "processing", platformServices.getAbsolutePath() ), null );
}
InputStream in = null;
boolean suppressExceptionOnClose = true;
final java.util.Properties p = new java.util.Properties();
try
{
in = new FileInputStream( platformServices );
p.load( in );
suppressExceptionOnClose = false;
}
finally
{
try
{
if ( in != null )
{
in.close();
}
}
catch ( final IOException e )
{
if ( suppressExceptionOnClose )
{
this.log( Level.SEVERE, getMessage( e ), e );
}
else
{
throw e;
}
}
}
for ( final Map.Entry<Object, Object> e : p.entrySet() )
{
if ( e.getKey().toString().startsWith( serviceNamePrefix ) )
{
final String configuration = e.getValue().toString();
if ( this.isLoggable( Level.FINEST ) )
{
this.log( Level.FINEST, getMessage( "serviceInfo", platformServices.getAbsolutePath(),
serviceClass.getName(), configuration ), null );
}
sortedPlatformServices.put( e.getKey().toString(),
this.createModletServiceObject( serviceClass, configuration ) );
}
}
}
final Enumeration<URL> classpathServices =
this.findResources( this.getProviderLocation() + '/' + serviceClass.getName() );
int count = 0;
final long t0 = System.currentTimeMillis();
final List<T> sortedClasspathServices = new ArrayList<T>();
while ( classpathServices.hasMoreElements() )
{
count++;
final URL url = classpathServices.nextElement();
if ( this.isLoggable( Level.FINEST ) )
{
this.log( Level.FINEST, getMessage( "processing", url.toExternalForm() ), null );
}
BufferedReader reader = null;
boolean suppressExceptionOnClose = true;
try
{
reader = new BufferedReader( new InputStreamReader( url.openStream(), "UTF-8" ) );
String line;
while ( ( line = reader.readLine() ) != null )
{
if ( line.contains( "#" ) )
{
continue;
}
if ( this.isLoggable( Level.FINEST ) )
{
this.log( Level.FINEST, getMessage( "serviceInfo", url.toExternalForm(),
serviceClass.getName(), line ), null );
}
final T serviceObject = this.createModletServiceObject( serviceClass, line );
sortedClasspathServices.add( serviceObject );
}
Collections.sort( sortedClasspathServices,
new Comparator<Object>()
{
public int compare( final Object o1, final Object o2 )
{
return ordinalOf( o1 ) - ordinalOf( o2 );
}
} );
suppressExceptionOnClose = false;
}
finally
{
try
{
if ( reader != null )
{
reader.close();
}
}
catch ( final IOException e )
{
if ( suppressExceptionOnClose )
{
this.log( Level.SEVERE, getMessage( e ), e );
}
else
{
throw new ModelException( getMessage( e ), e );
}
}
}
}
if ( this.isLoggable( Level.FINE ) )
{
this.log( Level.FINE, getMessage( "contextReport", count,
this.getProviderLocation() + '/' + serviceClass.getName(),
System.currentTimeMillis() - t0 ), null );
}
final List<T> services =
new ArrayList<T>( sortedPlatformServices.size() + sortedClasspathServices.size() );
services.addAll( sortedPlatformServices.values() );
services.addAll( sortedClasspathServices );
return services;
}
catch ( final IOException e )
{
throw new ModelException( getMessage( e ), e );
}
}
private <T> T createModletServiceObject( final Class<T> serviceClass, final String configuration )
throws ModelException
{
String className = configuration;
final int i0 = configuration.indexOf( '[' );
final int i1 = configuration.lastIndexOf( ']' );
final Service service = new Service();
service.setIdentifier( serviceClass.getName() );
if ( i0 != -1 && i1 != -1 )
{
className = configuration.substring( 0, i0 );
final StringTokenizer propertyTokens =
new StringTokenizer( configuration.substring( i0 + 1, i1 ), "," );
while ( propertyTokens.hasMoreTokens() )
{
final String property = propertyTokens.nextToken();
final int d0 = property.indexOf( '=' );
String propertyName = property;
String propertyValue = null;
if ( d0 != -1 )
{
propertyName = property.substring( 0, d0 );
propertyValue = property.substring( d0 + 1, property.length() );
}
final Property p = new Property();
service.getProperty().add( p );
p.setName( propertyName );
p.setValue( propertyValue );
}
}
service.setClazz( className );
// Need a way to exchange the service factory creating modlet service objects?
return new DefaultServiceFactory().createServiceObject( this, service, serviceClass );
}
/**
* Searches the context for {@code META-INF/MANIFEST.MF} resources and returns a set of URIs of entries whose names
* end with a known schema extension.
*
* @return Set of URIs of any matching entries.
*
* @throws IOException if reading fails.
* @throws URISyntaxException if parsing fails.
* @throws ModelException if searching the context fails.
*/
private Set<URI> getSchemaResources() throws IOException, URISyntaxException, ModelException
{
final Set<URI> resources = new HashSet<URI>();
final long t0 = System.currentTimeMillis();
int count = 0;
for ( final Enumeration<URL> e = this.findResources( "META-INF/MANIFEST.MF" );
e.hasMoreElements(); )
{
InputStream manifestStream = null;
boolean suppressExceptionOnClose = true;
try
{
count++;
final URL manifestUrl = e.nextElement();
final String externalForm = manifestUrl.toExternalForm();
final String baseUrl = externalForm.substring( 0, externalForm.indexOf( "META-INF" ) );
manifestStream = manifestUrl.openStream();
final Manifest mf = new Manifest( manifestStream );
if ( this.isLoggable( Level.FINEST ) )
{
this.log( Level.FINEST, getMessage( "processing", externalForm ), null );
}
for ( final Map.Entry<String, Attributes> entry : mf.getEntries().entrySet() )
{
for ( int i = SCHEMA_EXTENSIONS.length - 1; i >= 0; i-- )
{
if ( entry.getKey().toLowerCase().endsWith( '.' + SCHEMA_EXTENSIONS[i].toLowerCase() ) )
{
final URL schemaUrl = new URL( baseUrl + entry.getKey() );
resources.add( schemaUrl.toURI() );
if ( this.isLoggable( Level.FINEST ) )
{
this.log( Level.FINEST, getMessage( "foundSchemaCandidate",
schemaUrl.toExternalForm() ), null );
}
}
}
}
suppressExceptionOnClose = false;
}
finally
{
try
{
if ( manifestStream != null )
{
manifestStream.close();
}
}
catch ( final IOException ex )
{
if ( suppressExceptionOnClose )
{
this.log( Level.SEVERE, getMessage( ex ), ex );
}
else
{
throw ex;
}
}
}
}
if ( this.isLoggable( Level.FINE ) )
{
this.log( Level.FINE, getMessage( "contextReport", count, "META-INF/MANIFEST.MF",
System.currentTimeMillis() - t0 ), null );
}
return resources;
}
private EntityResolver createEntityResolver( final Schemas schemas )
{
return new DefaultHandler()
{
@Override
public InputSource resolveEntity( final String publicId, final String systemId )
throws SAXException, IOException
{
InputSource schemaSource = null;
try
{
Schema s = null;
if ( schemas != null )
{
if ( systemId != null && !"".equals( systemId ) )
{
s = schemas.getSchemaBySystemId( systemId );
}
else if ( publicId != null )
{
s = schemas.getSchemaByPublicId( publicId );
}
}
if ( s != null )
{
schemaSource = new InputSource();
schemaSource.setPublicId( s.getPublicId() );
schemaSource.setSystemId( s.getSystemId() );
if ( s.getClasspathId() != null )
{
final URL resource = findResource( s.getClasspathId() );
if ( resource != null )
{
schemaSource.setSystemId( resource.toExternalForm() );
}
else if ( isLoggable( Level.WARNING ) )
{
log( Level.WARNING, getMessage( "resourceNotFound", s.getClasspathId() ), null );
}
}
if ( isLoggable( Level.FINEST ) )
{
log( Level.FINEST, getMessage( "resolutionInfo", publicId + ", " + systemId,
schemaSource.getPublicId() + ", "
+ schemaSource.getSystemId() ), null );
}
}
if ( schemaSource == null && systemId != null && !"".equals( systemId ) )
{
final URI systemUri = new URI( systemId );
String schemaName = systemUri.getPath();
if ( schemaName != null )
{
final int lastIndexOfSlash = schemaName.lastIndexOf( '/' );
if ( lastIndexOfSlash != -1 && lastIndexOfSlash < schemaName.length() )
{
schemaName = schemaName.substring( lastIndexOfSlash + 1 );
}
for ( final URI uri : getSchemaResources() )
{
if ( uri.getSchemeSpecificPart() != null
&& uri.getSchemeSpecificPart().endsWith( schemaName ) )
{
schemaSource = new InputSource();
schemaSource.setPublicId( publicId );
schemaSource.setSystemId( uri.toASCIIString() );
if ( isLoggable( Level.FINEST ) )
{
log( Level.FINEST, getMessage( "resolutionInfo", systemUri.toASCIIString(),
schemaSource.getSystemId() ), null );
}
break;
}
}
}
else
{
if ( isLoggable( Level.WARNING ) )
{
log( Level.WARNING, getMessage( "unsupportedIdUri", systemId,
systemUri.toASCIIString() ), null );
}
schemaSource = null;
}
}
}
catch ( final URISyntaxException e )
{
if ( isLoggable( Level.WARNING ) )
{
log( Level.WARNING, getMessage( "unsupportedIdUri", systemId, getMessage( e ) ), null );
}
schemaSource = null;
}
catch ( final ModelException e )
{
String message = getMessage( e );
if ( message == null )
{
message = "";
}
else if ( message.length() > 0 )
{
message = " " + message;
}
String resource = "";
if ( publicId != null )
{
resource = publicId + ", ";
}
resource += systemId;
// JDK: As of JDK 6, "new IOException( message, cause )".
throw (IOException) new IOException( getMessage(
"failedResolving", resource, message ) ).initCause( e );
}
return schemaSource;
}
};
}
private LSResourceResolver createResourceResolver( final EntityResolver entityResolver )
{
if ( entityResolver == null )
{
throw new NullPointerException( "entityResolver" );
}
return new LSResourceResolver()
{
public LSInput resolveResource( final String type, final String namespaceURI, final String publicId,
final String systemId, final String baseURI )
{
final String resolvePublicId = namespaceURI == null ? publicId : namespaceURI;
final String resolveSystemId = systemId == null ? "" : systemId;
try
{
if ( XMLConstants.W3C_XML_SCHEMA_NS_URI.equals( type ) )
{
final InputSource schemaSource =
entityResolver.resolveEntity( resolvePublicId, resolveSystemId );
if ( schemaSource != null )
{
return new LSInput()
{
public Reader getCharacterStream()
{
return schemaSource.getCharacterStream();
}
public void setCharacterStream( final Reader characterStream )
{
if ( isLoggable( Level.WARNING ) )
{
log( Level.WARNING, getMessage(
"unsupportedOperation", "setCharacterStream",
DefaultModelContext.class.getName() + ".LSResourceResolver" ), null );
}
}
public InputStream getByteStream()
{
return schemaSource.getByteStream();
}
public void setByteStream( final InputStream byteStream )
{
if ( isLoggable( Level.WARNING ) )
{
log( Level.WARNING, getMessage(
"unsupportedOperation", "setByteStream",
DefaultModelContext.class.getName() + ".LSResourceResolver" ), null );
}
}
public String getStringData()
{
return null;
}
public void setStringData( final String stringData )
{
if ( isLoggable( Level.WARNING ) )
{
log( Level.WARNING, getMessage(
"unsupportedOperation", "setStringData",
DefaultModelContext.class.getName() + ".LSResourceResolver" ), null );
}
}
public String getSystemId()
{
return schemaSource.getSystemId();
}
public void setSystemId( final String systemId )
{
if ( isLoggable( Level.WARNING ) )
{
log( Level.WARNING, getMessage(
"unsupportedOperation", "setSystemId",
DefaultModelContext.class.getName() + ".LSResourceResolver" ), null );
}
}
public String getPublicId()
{
return schemaSource.getPublicId();
}
public void setPublicId( final String publicId )
{
if ( isLoggable( Level.WARNING ) )
{
log( Level.WARNING, getMessage(
"unsupportedOperation", "setPublicId",
DefaultModelContext.class.getName() + ".LSResourceResolver" ), null );
}
}
public String getBaseURI()
{
return baseURI;
}
public void setBaseURI( final String baseURI )
{
if ( isLoggable( Level.WARNING ) )
{
log( Level.WARNING, getMessage(
"unsupportedOperation", "setBaseURI",
DefaultModelContext.class.getName() + ".LSResourceResolver" ), null );
}
}
public String getEncoding()
{
return schemaSource.getEncoding();
}
public void setEncoding( final String encoding )
{
if ( isLoggable( Level.WARNING ) )
{
log( Level.WARNING, getMessage(
"unsupportedOperation", "setEncoding",
DefaultModelContext.class.getName() + ".LSResourceResolver" ), null );
}
}
public boolean getCertifiedText()
{
return false;
}
public void setCertifiedText( final boolean certifiedText )
{
if ( isLoggable( Level.WARNING ) )
{
log( Level.WARNING, getMessage(
"unsupportedOperation", "setCertifiedText",
DefaultModelContext.class.getName() + ".LSResourceResolver" ), null );
}
}
};
}
}
else if ( isLoggable( Level.WARNING ) )
{
log( Level.WARNING, getMessage( "unsupportedResourceType", type ), null );
}
}
catch ( final SAXException e )
{
String message = getMessage( e );
if ( message == null && e.getException() != null )
{
message = getMessage( e.getException() );
}
if ( message == null )
{
message = "";
}
else if ( message.length() > 0 )
{
message = " " + message;
}
String resource = "";
if ( resolvePublicId != null )
{
resource = resolvePublicId + ", ";
}
resource += resolveSystemId;
if ( isLoggable( Level.SEVERE ) )
{
log( Level.SEVERE, getMessage( "failedResolving", resource, message ), e );
}
}
catch ( final IOException e )
{
String message = getMessage( e );
if ( message == null )
{
message = "";
}
else if ( message.length() > 0 )
{
message = " " + message;
}
String resource = "";
if ( resolvePublicId != null )
{
resource = resolvePublicId + ", ";
}
resource += resolveSystemId;
if ( isLoggable( Level.SEVERE ) )
{
log( Level.SEVERE, getMessage( "failedResolving", resource, message ), e );
}
}
return null;
}
};
}
private javax.xml.validation.Schema createSchema( final Schemas schemas, final EntityResolver entityResolver,
final LSResourceResolver resourceResolver, final String model,
final URI publicId ) throws ModelException
{
if ( entityResolver == null )
{
throw new NullPointerException( "entityResolver" );
}
if ( model != null && publicId != null )
{
throw new IllegalArgumentException( "model=" + model + ", publicId=" + publicId.toASCIIString() );
}
try
{
final long t0 = System.currentTimeMillis();
final SchemaFactory f = SchemaFactory.newInstance( XMLConstants.W3C_XML_SCHEMA_NS_URI );
final List<Source> sources = new ArrayList<Source>( schemas != null ? schemas.getSchema().size() : 0 );
if ( schemas != null )
{
for ( final Schema s : schemas.getSchema() )
{
final InputSource inputSource = entityResolver.resolveEntity( s.getPublicId(), s.getSystemId() );
if ( inputSource != null )
{
sources.add( new SAXSource( inputSource ) );
}
}
}
if ( sources.isEmpty() )
{
if ( model != null )
{
throw new ModelException( getMessage( "missingSchemasForModel", model ) );
}
if ( publicId != null )
{
throw new ModelException( getMessage( "missingSchemasForPublicId", publicId ) );
}
}
f.setResourceResolver( resourceResolver );
f.setErrorHandler( new ErrorHandler()
{
// See http://java.net/jira/browse/JAXP-66
public void warning( final SAXParseException e ) throws SAXException
{
String message = getMessage( e );
if ( message == null && e.getException() != null )
{
message = getMessage( e.getException() );
}
if ( isLoggable( Level.WARNING ) )
{
log( Level.WARNING, message, e );
}
}
public void error( final SAXParseException e ) throws SAXException
{
throw e;
}
public void fatalError( final SAXParseException e ) throws SAXException
{
throw e;
}
} );
final javax.xml.validation.Schema schema = f.newSchema( sources.toArray( new Source[ sources.size() ] ) );
if ( this.isLoggable( Level.FINE ) )
{
final StringBuilder schemaInfo = new StringBuilder( sources.size() * 50 );
for ( final Source s : sources )
{
schemaInfo.append( ", " ).append( s.getSystemId() );
}
this.log( Level.FINE, getMessage( "creatingSchema", schemaInfo.substring( 2 ),
System.currentTimeMillis() - t0 ), null );
}
return schema;
}
catch ( final IOException e )
{
throw new ModelException( getMessage( e ), e );
}
catch ( final SAXException e )
{
String message = getMessage( e );
if ( message == null && e.getException() != null )
{
message = getMessage( e.getException() );
}
throw new ModelException( message, e );
}
}
private JAXBContext createContext( final Schemas schemas, final String model, final URI publicId )
throws ModelException
{
if ( model != null && publicId != null )
{
throw new IllegalArgumentException( "model=" + model + ", publicId=" + publicId.toASCIIString() );
}
try
{
StringBuilder packageNames = null;
final long t0 = System.currentTimeMillis();
if ( schemas != null )
{
packageNames = new StringBuilder( schemas.getSchema().size() * 25 );
for ( final Schema schema : schemas.getSchema() )
{
if ( schema.getContextId() != null )
{
packageNames.append( ':' ).append( schema.getContextId() );
}
}
}
if ( packageNames == null || packageNames.length() == 0 )
{
if ( model != null )
{
throw new ModelException( getMessage( "missingSchemasForModel", model ) );
}
if ( publicId != null )
{
throw new ModelException( getMessage( "missingSchemasForPublicId", publicId ) );
}
}
final JAXBContext context = JAXBContext.newInstance( packageNames.substring( 1 ), this.getClassLoader() );
if ( this.isLoggable( Level.FINE ) )
{
this.log( Level.FINE, getMessage( "creatingContext", packageNames.substring( 1 ),
System.currentTimeMillis() - t0 ), null );
}
return context;
}
catch ( final JAXBException e )
{
String message = getMessage( e );
if ( message == null && e.getLinkedException() != null )
{
message = getMessage( e.getLinkedException() );
}
throw new ModelException( message, e );
}
}
private Marshaller createMarshaller( final String model, final URI publicId )
throws ModelException
{
if ( model != null && publicId != null )
{
throw new IllegalArgumentException( "model=" + model + ", publicId=" + publicId.toASCIIString() );
}
Schemas schemas = null;
if ( model != null )
{
schemas = this.getModlets().getSchemas( model );
}
if ( publicId != null )
{
schemas = this.getModlets().getSchemas( publicId );
}
try
{
StringBuilder packageNames = null;
StringBuilder schemaLocation = null;
final long t0 = System.currentTimeMillis();
if ( schemas != null )
{
packageNames = new StringBuilder( schemas.getSchema().size() * 25 );
schemaLocation = new StringBuilder( schemas.getSchema().size() * 50 );
for ( final Schema schema : schemas.getSchema() )
{
if ( schema.getContextId() != null )
{
packageNames.append( ':' ).append( schema.getContextId() );
}
if ( schema.getPublicId() != null && schema.getSystemId() != null )
{
schemaLocation.append( ' ' ).append( schema.getPublicId() ).append( ' ' ).
append( schema.getSystemId() );
}
}
}
if ( packageNames == null || packageNames.length() == 0 )
{
if ( model != null )
{
throw new ModelException( getMessage( "missingSchemasForModel", model ) );
}
if ( publicId != null )
{
throw new ModelException( getMessage( "missingSchemasForPublicId", publicId ) );
}
}
final Marshaller m =
JAXBContext.newInstance( packageNames.substring( 1 ), this.getClassLoader() ).createMarshaller();
if ( schemaLocation != null && schemaLocation.length() != 0 )
{
m.setProperty( Marshaller.JAXB_SCHEMA_LOCATION, schemaLocation.substring( 1 ) );
}
MarshallerListenerList listenerList = null;
if ( model != null )
{
final Collection<? extends Marshaller.Listener> listeners =
this.createServiceObjects( model, MARSHALLER_LISTENER_SERVICE, Marshaller.Listener.class );
if ( !listeners.isEmpty() )
{
listenerList = new MarshallerListenerList();
listenerList.getListeners().addAll( listeners );
m.setListener( listenerList );
}
}
if ( this.isLoggable( Level.FINE ) )
{
if ( listenerList == null )
{
this.log( Level.FINE, getMessage( "creatingMarshaller", packageNames.substring( 1 ),
schemaLocation.substring( 1 ),
System.currentTimeMillis() - t0 ), null );
}
else
{
final StringBuilder b = new StringBuilder( listenerList.getListeners().size() * 100 );
for ( int i = 0, s0 = listenerList.getListeners().size(); i < s0; i++ )
{
b.append( ',' ).append( listenerList.getListeners().get( i ) );
}
this.log( Level.FINE, getMessage( "creatingMarshallerWithListeners", packageNames.substring( 1 ),
schemaLocation.substring( 1 ), b.substring( 1 ),
System.currentTimeMillis() - t0 ), null );
}
}
return m;
}
catch ( final JAXBException e )
{
String message = getMessage( e );
if ( message == null && e.getLinkedException() != null )
{
message = getMessage( e.getLinkedException() );
}
throw new ModelException( message, e );
}
}
private Unmarshaller createUnmarshaller( final String model, final URI publicId )
throws ModelException
{
if ( model != null && publicId != null )
{
throw new IllegalArgumentException( "model=" + model + ", publicId=" + publicId.toASCIIString() );
}
Schemas schemas = null;
if ( model != null )
{
schemas = this.getModlets().getSchemas( model );
}
if ( publicId != null )
{
schemas = this.getModlets().getSchemas( publicId );
}
try
{
StringBuilder packageNames = null;
final long t0 = System.currentTimeMillis();
if ( schemas != null )
{
packageNames = new StringBuilder( schemas.getSchema().size() * 25 );
for ( final Schema schema : schemas.getSchema() )
{
if ( schema.getContextId() != null )
{
packageNames.append( ':' ).append( schema.getContextId() );
}
}
}
if ( packageNames == null || packageNames.length() == 0 )
{
if ( model != null )
{
throw new ModelException( getMessage( "missingSchemasForModel", model ) );
}
if ( publicId != null )
{
throw new ModelException( getMessage( "missingSchemasForPublicId", publicId ) );
}
}
final Unmarshaller u =
JAXBContext.newInstance( packageNames.substring( 1 ), this.getClassLoader() ).createUnmarshaller();
UnmarshallerListenerList listenerList = null;
if ( model != null )
{
final Collection<? extends Unmarshaller.Listener> listeners =
this.createServiceObjects( model, UNMARSHALLER_LISTENER_SERVICE, Unmarshaller.Listener.class );
if ( !listeners.isEmpty() )
{
listenerList = new UnmarshallerListenerList();
listenerList.getListeners().addAll( listeners );
u.setListener( listenerList );
}
}
if ( this.isLoggable( Level.FINE ) )
{
if ( listenerList == null )
{
this.log( Level.FINE, getMessage( "creatingUnmarshaller", packageNames.substring( 1 ),
System.currentTimeMillis() - t0 ), null );
}
else
{
final StringBuilder b = new StringBuilder( listenerList.getListeners().size() * 100 );
for ( int i = 0, s0 = listenerList.getListeners().size(); i < s0; i++ )
{
b.append( ',' ).append( listenerList.getListeners().get( i ) );
}
this.log( Level.FINE, getMessage( "creatingUnmarshallerWithListeners",
packageNames.substring( 1 ), b.substring( 1 ),
System.currentTimeMillis() - t0 ), null );
}
}
return u;
}
catch ( final JAXBException e )
{
String message = getMessage( e );
if ( message == null && e.getLinkedException() != null )
{
message = getMessage( e.getLinkedException() );
}
throw new ModelException( message, e );
}
}
private static int ordinalOf( final Object serviceObject )
{
int ordinal = 0;
if ( serviceObject instanceof ModletProvider )
{
ordinal = ( (ModletProvider) serviceObject ).getOrdinal();
}
if ( serviceObject instanceof ModletProcessor )
{
ordinal = ( (ModletProcessor) serviceObject ).getOrdinal();
}
if ( serviceObject instanceof ModletValidator )
{
ordinal = ( (ModletValidator) serviceObject ).getOrdinal();
}
if ( serviceObject instanceof ServiceFactory )
{
ordinal = ( (ServiceFactory) serviceObject ).getOrdinal();
}
return ordinal;
}
private static String getMessage( final String key, final Object... arguments )
{
return MessageFormat.format( ResourceBundle.getBundle(
DefaultModelContext.class.getName().replace( '.', '/' ) ).getString( key ), arguments );
}
private static String getMessage( final Throwable t )
{
return t != null
? t.getMessage() != null && t.getMessage().trim().length() > 0
? t.getMessage()
: getMessage( t.getCause() )
: null;
}
}
/**
* {@code ErrorHandler} collecting {@code ModelValidationReport} details.
*
* @author <a href="mailto:cs@schulte.it">Christian Schulte</a>
* @version $JOMC: DefaultModelContext.java 5051 2015-05-30 17:29:32Z schulte $
*/
class ModelErrorHandler extends DefaultHandler
{
/**
* The context of the instance.
*/
private ModelContext context;
/**
* The report of the instance.
*/
private ModelValidationReport report;
/**
* Creates a new {@code ModelErrorHandler} instance taking a context.
*
* @param context The context of the instance.
*/
ModelErrorHandler( final ModelContext context )
{
this( context, null );
}
/**
* Creates a new {@code ModelErrorHandler} instance taking a report to use for collecting validation events.
*
* @param context The context of the instance.
* @param report A report to use for collecting validation events.
*/
ModelErrorHandler( final ModelContext context, final ModelValidationReport report )
{
super();
this.context = context;
this.report = report;
}
/**
* Gets the report of the instance.
*
* @return The report of the instance.
*/
public ModelValidationReport getReport()
{
if ( this.report == null )
{
this.report = new ModelValidationReport();
}
return this.report;
}
@Override
public void warning( final SAXParseException exception ) throws SAXException
{
String message = getMessage( exception );
if ( message == null && exception.getException() != null )
{
message = getMessage( exception.getException() );
}
if ( this.context != null && this.context.isLoggable( Level.FINE ) )
{
this.context.log( Level.FINE, message, exception );
}
this.getReport().getDetails().add( new ModelValidationReport.Detail(
"W3C XML 1.0 Recommendation - Warning condition", Level.WARNING, message, null ) );
}
@Override
public void error( final SAXParseException exception ) throws SAXException
{
String message = getMessage( exception );
if ( message == null && exception.getException() != null )
{
message = getMessage( exception.getException() );
}
if ( this.context != null && this.context.isLoggable( Level.FINE ) )
{
this.context.log( Level.FINE, message, exception );
}
this.getReport().getDetails().add( new ModelValidationReport.Detail(
"W3C XML 1.0 Recommendation - Section 1.2 - Error", Level.SEVERE, message, null ) );
}
@Override
public void fatalError( final SAXParseException exception ) throws SAXException
{
String message = getMessage( exception );
if ( message == null && exception.getException() != null )
{
message = getMessage( exception.getException() );
}
if ( this.context != null && this.context.isLoggable( Level.FINE ) )
{
this.context.log( Level.FINE, message, exception );
}
this.getReport().getDetails().add( new ModelValidationReport.Detail(
"W3C XML 1.0 Recommendation - Section 1.2 - Fatal Error", Level.SEVERE, message, null ) );
}
private static String getMessage( final Throwable t )
{
return t != null
? t.getMessage() != null && t.getMessage().trim().length() > 0
? t.getMessage()
: getMessage( t.getCause() )
: null;
}
}
/**
* List of {@code Marshaller.Listener}s.
*
* @author <a href="mailto:cs@schulte.it">Christian Schulte</a>
* @version $JOMC: DefaultModelContext.java 5051 2015-05-30 17:29:32Z schulte $
* @since 1.2
*/
class MarshallerListenerList extends Marshaller.Listener
{
/**
* The {@code Marshaller.Listener}s of the instance.
*/
private List<Marshaller.Listener> listeners;
/**
* Creates a new {@code MarshallerListenerList} instance.
*/
MarshallerListenerList()
{
super();
}
/**
* Gets the listeners of the instance.
* <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
* listeners property.
* </p>
*
* @return The list of listeners of the instance.
*/
List<Marshaller.Listener> getListeners()
{
if ( this.listeners == null )
{
this.listeners = new ArrayList<Marshaller.Listener>();
}
return this.listeners;
}
@Override
public void beforeMarshal( final Object source )
{
for ( int i = 0, s0 = this.getListeners().size(); i < s0; i++ )
{
this.getListeners().get( i ).beforeMarshal( source );
}
}
@Override
public void afterMarshal( final Object source )
{
for ( int i = 0, s0 = this.getListeners().size(); i < s0; i++ )
{
this.getListeners().get( i ).afterMarshal( source );
}
}
}
/**
* List of {@code Unmarshaller.Listener}s.
*
* @author <a href="mailto:cs@schulte.it">Christian Schulte</a>
* @version $JOMC: DefaultModelContext.java 5051 2015-05-30 17:29:32Z schulte $
* @since 1.2
*/
class UnmarshallerListenerList extends Unmarshaller.Listener
{
/**
* The {@code Unmarshaller.Listener}s of the instance.
*/
private List<Unmarshaller.Listener> listeners;
/**
* Creates a new {@code UnmarshallerListenerList} instance.
*/
UnmarshallerListenerList()
{
super();
}
/**
* Gets the listeners of the instance.
* <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
* listeners property.
* </p>
*
* @return The list of listeners of the instance.
*/
List<Unmarshaller.Listener> getListeners()
{
if ( this.listeners == null )
{
this.listeners = new ArrayList<Unmarshaller.Listener>();
}
return this.listeners;
}
@Override
public void beforeUnmarshal( final Object target, final Object parent )
{
for ( int i = 0, s0 = this.getListeners().size(); i < s0; i++ )
{
this.getListeners().get( i ).beforeUnmarshal( target, parent );
}
}
@Override
public void afterUnmarshal( final Object target, final Object parent )
{
for ( int i = 0, s0 = this.getListeners().size(); i < s0; i++ )
{
this.getListeners().get( i ).afterUnmarshal( target, parent );
}
}
}