/*
 * Hibernate Validator, declare and validate application constraints
 *
 * License: Apache License, Version 2.0
 * See the license.txt file in the root directory or <http://www.apache.org/licenses/LICENSE-2.0>.
 */
package org.hibernate.validator.internal.xml.config;

import java.io.IOException;
import java.io.InputStream;
import java.lang.invoke.MethodHandles;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.Collections;
import java.util.Map;

import javax.validation.BootstrapConfiguration;
import javax.xml.stream.XMLEventReader;
import javax.xml.stream.XMLStreamException;
import javax.xml.transform.stream.StreamSource;
import javax.xml.validation.Schema;
import javax.xml.validation.Validator;

import org.hibernate.validator.internal.util.CollectionHelper;
import org.hibernate.validator.internal.util.logging.Log;
import org.hibernate.validator.internal.util.logging.LoggerFactory;
import org.hibernate.validator.internal.util.privilegedactions.GetClassLoader;
import org.hibernate.validator.internal.util.privilegedactions.SetContextClassLoader;
import org.hibernate.validator.internal.xml.CloseIgnoringInputStream;
import org.hibernate.validator.internal.xml.XmlParserHelper;

import org.xml.sax.SAXException;

Parser for validation.xml.
Author:Hardy Ferentschik, Gunnar Morling
/** * Parser for <i>validation.xml</i>. * * @author Hardy Ferentschik * @author Gunnar Morling */
public class ValidationXmlParser { private static final Log LOG = LoggerFactory.make( MethodHandles.lookup() ); private static final String VALIDATION_XML_FILE = "META-INF/validation.xml"; private static final Map<String, String> SCHEMAS_BY_VERSION = Collections.unmodifiableMap( getSchemasByVersion() ); private final ClassLoader externalClassLoader; private static Map<String, String> getSchemasByVersion() { Map<String, String> schemasByVersion = CollectionHelper.newHashMap( 3 ); schemasByVersion.put( "1.0", "META-INF/validation-configuration-1.0.xsd" ); schemasByVersion.put( "1.1", "META-INF/validation-configuration-1.1.xsd" ); schemasByVersion.put( "2.0", "META-INF/validation-configuration-2.0.xsd" ); return schemasByVersion; } public ValidationXmlParser(ClassLoader externalClassLoader) { this.externalClassLoader = externalClassLoader; }
Tries to check whether a validation.xml file exists and parses it.
Returns:The parameters parsed out of validation.xml wrapped in an instance of ConfigurationImpl.ValidationBootstrapParameters.
/** * Tries to check whether a <i>validation.xml</i> file exists and parses it. * * @return The parameters parsed out of <i>validation.xml</i> wrapped in an instance of {@code ConfigurationImpl.ValidationBootstrapParameters}. */
public final BootstrapConfiguration parseValidationXml() { InputStream in = getValidationXmlInputStream(); if ( in == null ) { return BootstrapConfigurationImpl.getDefaultBootstrapConfiguration(); } ClassLoader previousTccl = run( GetClassLoader.fromContext() ); try { run( SetContextClassLoader.action( ValidationXmlParser.class.getClassLoader() ) ); // HV-970 The parser helper is only loaded if there actually is a validation.xml file; // this avoids accessing javax.xml.stream.* (which does not exist on Android) when not actually // working with the XML configuration XmlParserHelper xmlParserHelper = new XmlParserHelper(); // the InputStream supports mark and reset in.mark( Integer.MAX_VALUE ); XMLEventReader xmlEventReader = xmlParserHelper.createXmlEventReader( VALIDATION_XML_FILE, new CloseIgnoringInputStream( in ) ); String schemaVersion = xmlParserHelper.getSchemaVersion( VALIDATION_XML_FILE, xmlEventReader ); xmlEventReader.close(); in.reset(); // The validation is done first as StAX builders used below are assuming that the XML file is correct and don't // do any validation of the input. Schema schema = getSchema( xmlParserHelper, schemaVersion ); Validator validator = schema.newValidator(); validator.validate( new StreamSource( new CloseIgnoringInputStream( in ) ) ); in.reset(); xmlEventReader = xmlParserHelper.createXmlEventReader( VALIDATION_XML_FILE, new CloseIgnoringInputStream( in ) ); ValidationConfigStaxBuilder validationConfigStaxBuilder = new ValidationConfigStaxBuilder( xmlEventReader ); xmlEventReader.close(); in.reset(); return validationConfigStaxBuilder.build(); } catch (XMLStreamException | IOException | SAXException e) { throw LOG.getUnableToParseValidationXmlFileException( VALIDATION_XML_FILE, e ); } finally { run( SetContextClassLoader.action( previousTccl ) ); closeStream( in ); } } private InputStream getValidationXmlInputStream() { LOG.debugf( "Trying to load %s for XML based Validator configuration.", VALIDATION_XML_FILE ); InputStream inputStream = ResourceLoaderHelper.getResettableInputStreamForPath( VALIDATION_XML_FILE, externalClassLoader ); if ( inputStream != null ) { return inputStream; } else { LOG.debugf( "No %s found. Using annotation based configuration only.", VALIDATION_XML_FILE ); return null; } } private Schema getSchema(XmlParserHelper xmlParserHelper, String schemaVersion) { String schemaResource = SCHEMAS_BY_VERSION.get( schemaVersion ); if ( schemaResource == null ) { throw LOG.getUnsupportedSchemaVersionException( VALIDATION_XML_FILE, schemaVersion ); } Schema schema = xmlParserHelper.getSchema( schemaResource ); if ( schema == null ) { throw LOG.unableToGetXmlSchema( schemaResource ); } return schema; } private void closeStream(InputStream inputStream) { try { inputStream.close(); } catch (IOException io) { LOG.unableToCloseXMLFileInputStream( VALIDATION_XML_FILE ); } }
Runs the given privileged action, using a privileged block if required.

NOTE: This must never be changed into a publicly available method to avoid execution of arbitrary privileged actions within HV's protection domain.

/** * Runs the given privileged action, using a privileged block if required. * <p> * <b>NOTE:</b> This must never be changed into a publicly available method to avoid execution of arbitrary * privileged actions within HV's protection domain. */
private static <T> T run(PrivilegedAction<T> action) { return System.getSecurityManager() != null ? AccessController.doPrivileged( action ) : action.run(); } }