Skip to content

Commit

Permalink
HV-595: Determining schema for validation of constraint mapping files…
Browse files Browse the repository at this point in the history
… by examining "version" attribute (work in progress)
  • Loading branch information
gunnarmorling committed Jul 30, 2012
1 parent 2f6cfe9 commit fcbe36d
Show file tree
Hide file tree
Showing 11 changed files with 376 additions and 82 deletions.
2 changes: 1 addition & 1 deletion engine/pom.xml
Expand Up @@ -151,7 +151,7 @@
<configuration>
<packageName>org.hibernate.validator.internal.xml</packageName>
<extension>true</extension>
<schemaFiles>validation-configuration-1.1.xsd,validation-mapping-1.0.xsd</schemaFiles>
<schemaFiles>validation-configuration-1.1.xsd,validation-mapping-1.1.xsd</schemaFiles>
</configuration>
<dependencies>
<dependency>
Expand Down
Expand Up @@ -439,7 +439,7 @@ public interface Log extends BasicLogger {
@Message(id = 121, value = "Unable to parse %s.")
ValidationException getUnableToDetermineSchemaVersionException(String file, @Cause XMLStreamException e);

@Message(id = 122, value = "Unsupported schema version for file %s: %s.")
@Message(id = 122, value = "Unsupported schema version for %s: %s.")
ValidationException getUnsupportedSchemaVersionException(String file, String version);

@Message(id = 123, value = "Unable to parse %s.")
Expand Down
Expand Up @@ -19,7 +19,6 @@
import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
Expand All @@ -32,11 +31,7 @@
import javax.xml.bind.Unmarshaller;
import javax.xml.transform.stream.StreamSource;
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;

import org.xml.sax.SAXException;

import org.hibernate.validator.internal.util.ReflectionHelper;
import org.hibernate.validator.internal.util.ResourceLoaderHelper;
import org.hibernate.validator.internal.util.logging.Log;
import org.hibernate.validator.internal.util.logging.LoggerFactory;
Expand All @@ -45,18 +40,12 @@
* Parser for <i>validation.xml</i> using JAXB.
*
* @author Hardy Ferentschik
* @author Gunnar Morling
*/
public class ValidationXmlParser {

private static final Log log = LoggerFactory.make();

/**
* Read limit for the buffered input stream. Resetting the stream after
* reading the version attribute will fail, if this has required reading
* more bytes than this limit (1MB) from the stream. Practically, this
* should never happen.
*/
private static final int READ_LIMIT = 1024 * 1024;
private static final String VALIDATION_XML_FILE = "META-INF/validation.xml";
private static final ConcurrentMap<String, String> SCHEMAS_BY_VERSION = new ConcurrentHashMap<String, String>(
2,
Expand Down Expand Up @@ -114,8 +103,9 @@ private ValidationConfigType getValidationConfig() {
return null;
}

String schemaVersion = getSchemaVersion( inputStream );
Schema schema = getSchema( schemaVersion );
String schemaVersion = xmlParserHelper.getSchemaVersion( VALIDATION_XML_FILE, inputStream );
String schemaResourceName = getSchemaResourceName( schemaVersion );
Schema schema = xmlParserHelper.getSchema( schemaResourceName );

ValidationConfigType validationConfig = unmarshal( inputStream, schema );

Expand All @@ -124,43 +114,20 @@ private ValidationConfigType getValidationConfig() {
return validationConfig;
}

private BufferedInputStream getInputStream() {
log.debugf( "Trying to load %s for XML based Validator configuration.", VALIDATION_XML_FILE );
InputStream inputStream = ResourceLoaderHelper.getInputStreamForPath( VALIDATION_XML_FILE );
return inputStream != null ? new BufferedInputStream( inputStream ) : null;
}

private String getSchemaVersion(BufferedInputStream inputStream) {
inputStream.mark( READ_LIMIT );
String version = xmlParserHelper.getVersion( VALIDATION_XML_FILE, inputStream );
try {
inputStream.reset();
}
catch ( IOException e ) {
throw log.getUnableToResetXmlInputStreamException( VALIDATION_XML_FILE, e );
}
return version;
}

private Schema getSchema(String version) {
String schemaResource = SCHEMAS_BY_VERSION.get( version );
private String getSchemaResourceName(String schemaVersion) {
String schemaResource = SCHEMAS_BY_VERSION.get( schemaVersion );

if ( schemaResource == null ) {
throw log.getUnsupportedSchemaVersionException( VALIDATION_XML_FILE, version );
throw log.getUnsupportedSchemaVersionException( VALIDATION_XML_FILE, schemaVersion );
}

ClassLoader loader = ReflectionHelper.getClassLoaderFromClass( ValidationXmlParser.class );
return schemaResource;
}

URL schemaUrl = loader.getResource( schemaResource );
SchemaFactory sf = SchemaFactory.newInstance( javax.xml.XMLConstants.W3C_XML_SCHEMA_NS_URI );
Schema schema = null;
try {
schema = sf.newSchema( schemaUrl );
}
catch ( SAXException e ) {
log.unableToCreateSchema( schemaResource, e.getMessage() );
}
return schema;
private BufferedInputStream getInputStream() {
log.debugf( "Trying to load %s for XML based Validator configuration.", VALIDATION_XML_FILE );
InputStream inputStream = ResourceLoaderHelper.getInputStreamForPath( VALIDATION_XML_FILE );
return inputStream != null ? new BufferedInputStream( inputStream ) : null;
}

private ValidationConfigType unmarshal(InputStream inputStream, Schema schema) {
Expand Down
Expand Up @@ -16,6 +16,7 @@
*/
package org.hibernate.validator.internal.xml;

import java.io.BufferedInputStream;
import java.io.FilterInputStream;
import java.io.IOException;
import java.io.InputStream;
Expand All @@ -25,12 +26,13 @@
import java.lang.reflect.Field;
import java.lang.reflect.Member;
import java.lang.reflect.Method;
import java.net.URL;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import javax.validation.Constraint;
import javax.validation.ConstraintValidator;
import javax.validation.Payload;
Expand All @@ -40,9 +42,6 @@
import javax.xml.bind.Unmarshaller;
import javax.xml.transform.stream.StreamSource;
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;

import org.xml.sax.SAXException;

import org.hibernate.validator.internal.metadata.core.AnnotationProcessingOptions;
import org.hibernate.validator.internal.metadata.core.ConstraintHelper;
Expand All @@ -66,7 +65,6 @@
public class XmlMappingParser {

private static final Log log = LoggerFactory.make();
private static final String VALIDATION_MAPPING_XSD = "META-INF/validation-mapping-1.0.xsd";
private static final String MESSAGE_PARAM = "message";
private static final String GROUPS_PARAM = "groups";
private static final String PAYLOAD_PARAM = "payload";
Expand All @@ -79,6 +77,19 @@ public class XmlMappingParser {
private final Map<Class<?>, List<Member>> cascadedMembers;
private final Map<Class<?>, List<Class<?>>> defaultSequences;

private final XmlParserHelper xmlParserHelper = new XmlParserHelper();

private static final ConcurrentMap<String, String> SCHEMAS_BY_VERSION = new ConcurrentHashMap<String, String>(
2,
0.75f,
1
);

static {
SCHEMAS_BY_VERSION.put( "1.0", "META-INF/validation-mapping-1.0.xsd" );
SCHEMAS_BY_VERSION.put( "1.1", "META-INF/validation-mapping-1.1.xsd" );
}

public XmlMappingParser(ConstraintHelper constraintHelper) {
this.constraintHelper = constraintHelper;
this.annotationProcessingOptions = new AnnotationProcessingOptions();
Expand All @@ -89,15 +100,21 @@ public XmlMappingParser(ConstraintHelper constraintHelper) {

public final void parse(Set<InputStream> mappingStreams) {

Schema schema = getMappingSchema();

try {
JAXBContext jc = JAXBContext.newInstance( ConstraintMappingsType.class );
Unmarshaller unmarshaller = jc.createUnmarshaller();
unmarshaller.setSchema( schema );

for ( InputStream in : mappingStreams ) {
ConstraintMappingsType mapping = getValidationConfig( in, unmarshaller );

InputStream resettableStream = in.markSupported() ? in : new BufferedInputStream( in );

String schemaVersion = xmlParserHelper.getSchemaVersion( "constraint mapping file", resettableStream );
String schemaResourceName = getSchemaResourceName( schemaVersion );
Schema schema = xmlParserHelper.getSchema( schemaResourceName );

Unmarshaller unmarshaller = jc.createUnmarshaller();
unmarshaller.setSchema( schema );

ConstraintMappingsType mapping = getValidationConfig( resettableStream, unmarshaller );
String defaultPackage = mapping.getDefaultPackage();

parseConstraintDefinitions( mapping.getConstraintDefinition(), defaultPackage );
Expand Down Expand Up @@ -593,20 +610,6 @@ private boolean isQualifiedClass(String clazz) {
return clazz.contains( PACKAGE_SEPARATOR );
}

private Schema getMappingSchema() {
ClassLoader loader = ReflectionHelper.getClassLoaderFromClass( XmlMappingParser.class );
URL schemaUrl = loader.getResource( VALIDATION_MAPPING_XSD );
SchemaFactory sf = SchemaFactory.newInstance( javax.xml.XMLConstants.W3C_XML_SCHEMA_NS_URI );
Schema schema = null;
try {
schema = sf.newSchema( schemaUrl );
}
catch ( SAXException e ) {
log.unableToCreateSchema( VALIDATION_MAPPING_XSD, e.getMessage() );
}
return schema;
}

private ConstraintMappingsType getValidationConfig(InputStream in, Unmarshaller unmarshaller) {
ConstraintMappingsType constraintMappings;
try {
Expand Down Expand Up @@ -635,9 +638,18 @@ private ConstraintMappingsType getValidationConfig(InputStream in, Unmarshaller
return constraintMappings;
}

private String getSchemaResourceName(String schemaVersion) {
String schemaResource = SCHEMAS_BY_VERSION.get( schemaVersion );

if ( schemaResource == null ) {
throw log.getUnsupportedSchemaVersionException( "constraint mapping file", schemaVersion );
}

return schemaResource;
}

// JAXB closes the underlying input stream
public class CloseIgnoringInputStream extends FilterInputStream {
private static class CloseIgnoringInputStream extends FilterInputStream {
public CloseIgnoringInputStream(InputStream in) {
super( in );
}
Expand Down
Expand Up @@ -16,18 +16,28 @@
*/
package org.hibernate.validator.internal.xml;

import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import javax.xml.namespace.QName;
import javax.xml.stream.XMLEventReader;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.events.Attribute;
import javax.xml.stream.events.StartElement;
import javax.xml.stream.events.XMLEvent;
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;

import org.xml.sax.SAXException;

import org.hibernate.validator.internal.util.Contracts;
import org.hibernate.validator.internal.util.ReflectionHelper;
import org.hibernate.validator.internal.util.logging.Log;
import org.hibernate.validator.internal.util.logging.LoggerFactory;

import static org.hibernate.validator.internal.util.logging.Messages.MESSAGES;

/**
* Provides common functionality used within the different XML descriptor
* parsers.
Expand All @@ -41,17 +51,31 @@ public class XmlParserHelper {
private static final String DEFAULT_VERSION = "1.0";

/**
* Retrieves the value of the "version" attribute of the root element of the
* given XML input stream.
* Read limit for the buffered input stream. Resetting the stream after
* reading the version attribute will fail, if this has required reading
* more bytes than this limit (1MB) from the stream. Practically, this
* should never happen.
*/
private static final int READ_LIMIT = 1024 * 1024;

/**
* Retrieves the schema version applying for the given XML input stream as
* represented by the "version" attribute of the root element of the stream.
*
* @param resourceName The name of the represented XML resource.
* @param xmlInputStream An input stream representing an XML resource.
* @param xmlInputStream An input stream representing an XML resource. Must support the
* {@link InputStream#mark(int)} and {@link InputStream#reset()}
* methods.
*
* @return The value of the "version" attribute. For compatibility with BV
* 1.0, "1.0" will be returned if the given stream doesn't have a
* "version" attribute.
*/
public String getVersion(String resourceName, InputStream xmlInputStream) {
public String getSchemaVersion(String resourceName, InputStream xmlInputStream) {

Contracts.assertNotNull( xmlInputStream, MESSAGES.parameterMustNotBeNull( "xmlInputStream" ) );

xmlInputStream.mark( READ_LIMIT );

try {
XMLEventReader xmlEventReader = createXmlEventReader( xmlInputStream );
Expand All @@ -62,6 +86,14 @@ public String getVersion(String resourceName, InputStream xmlInputStream) {
catch ( XMLStreamException e ) {
throw log.getUnableToDetermineSchemaVersionException( resourceName, e );
}
finally {
try {
xmlInputStream.reset();
}
catch ( IOException e ) {
throw log.getUnableToResetXmlInputStreamException( resourceName, e );
}
}
}

private String getVersionValue(StartElement startElement) {
Expand Down Expand Up @@ -89,4 +121,20 @@ private StartElement getRootElement(XMLEventReader xmlEventReader) throws XMLStr
private synchronized XMLEventReader createXmlEventReader(InputStream xmlStream) throws XMLStreamException {
return xmlInputFactory.createXMLEventReader( xmlStream );
}

public Schema getSchema(String schemaResource) {

ClassLoader loader = ReflectionHelper.getClassLoaderFromClass( XmlParserHelper.class );

URL schemaUrl = loader.getResource( schemaResource );
SchemaFactory sf = SchemaFactory.newInstance( javax.xml.XMLConstants.W3C_XML_SCHEMA_NS_URI );
Schema schema = null;
try {
schema = sf.newSchema( schemaUrl );
}
catch ( SAXException e ) {
log.unableToCreateSchema( schemaResource, e.getMessage() );
}
return schema;
}
}
2 changes: 1 addition & 1 deletion engine/src/main/xjb/binding-customization.xjb
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<jxb:bindings version="1.0" xmlns:jxb="http://java.sun.com/xml/ns/jaxb"
xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc">
<jxb:bindings schemaLocation="../xsd/validation-mapping-1.0.xsd" node="/xs:schema">
<jxb:bindings schemaLocation="../xsd/validation-mapping-1.1.xsd" node="/xs:schema">
<!-- let jaxb be whitespace tolerant - http://www.highlevelbits.com/2009/08/jaxb-with-maven_16.html -->
<jxb:globalBindings>
<xjc:javaType name="java.lang.String" xmlType="xs:string"
Expand Down

0 comments on commit fcbe36d

Please sign in to comment.