All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.hibernate.validator.internal.xml.XmlParserHelper Maven / Gradle / Ivy

There is a newer version: 8.0.1.Final
Show newest version
/*
 * Hibernate Validator, declare and validate application constraints
 *
 * License: Apache License, Version 2.0
 * See the license.txt file in the root directory or .
 */
package org.hibernate.validator.internal.xml;

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

import java.io.InputStream;
import java.lang.invoke.MethodHandles;
import java.net.URL;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.security.PrivilegedExceptionAction;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

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.hibernate.validator.internal.util.Contracts;
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.GetResource;
import org.hibernate.validator.internal.util.privilegedactions.NewSchema;

/**
 * Provides common functionality used within the different XML descriptor
 * parsers.
 *
 * @author Gunnar Morling
 */
public class XmlParserHelper {

	private static final Log LOG = LoggerFactory.make( MethodHandles.lookup() );

	/**
	 * The expected number of XML schemas managed by this class. Used to set the
	 * initial cache size.
	 */
	private static final int NUMBER_OF_SCHEMAS = 4;
	private static final String DEFAULT_VERSION = "1.0";
	private static final QName VERSION_QNAME = new QName( "version" );

	// xmlInputFactory used to be static in order to cache the factory, but that introduced a leakage of
	// class loader in WildFly. See HV-842
	private final XMLInputFactory xmlInputFactory = XMLInputFactory.newInstance();

	private static final ConcurrentMap schemaCache = new ConcurrentHashMap(
			NUMBER_OF_SCHEMAS
	);

	/**
	 * Retrieves the schema version applying for the given XML input stream as
	 * represented by the "version" attribute of the root element of the stream.
	 * 

* The given reader will be advanced to the root element of the given XML * structure. It can be used for unmarshalling from there. * * @param resourceName The name of the represented XML resource. * @param xmlEventReader An STAX event reader * * @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 getSchemaVersion(String resourceName, XMLEventReader xmlEventReader) { Contracts.assertNotNull( xmlEventReader, MESSAGES.parameterMustNotBeNull( "xmlEventReader" ) ); try { StartElement rootElement = getRootElement( xmlEventReader ); return getVersionValue( rootElement ); } catch (XMLStreamException e) { throw LOG.getUnableToDetermineSchemaVersionException( resourceName, e ); } } public synchronized XMLEventReader createXmlEventReader(String resourceName, InputStream xmlStream) { try { return xmlInputFactory.createXMLEventReader( xmlStream ); } catch (Exception e) { throw LOG.getUnableToCreateXMLEventReader( resourceName, e ); } } private String getVersionValue(StartElement startElement) { if ( startElement == null ) { return null; } Attribute versionAttribute = startElement.getAttributeByName( VERSION_QNAME ); return versionAttribute != null ? versionAttribute.getValue() : DEFAULT_VERSION; } private StartElement getRootElement(XMLEventReader xmlEventReader) throws XMLStreamException { XMLEvent event = xmlEventReader.peek(); while ( event != null && !event.isStartElement() ) { xmlEventReader.nextEvent(); event = xmlEventReader.peek(); } return event == null ? null : event.asStartElement(); } /** * Returns the XML schema identified by the given resource name. * * @param schemaResource * the resource name identifying the schema. * @return the schema identified by the given resource name or {@code null} if the resource was not found or could * not be loaded. */ public Schema getSchema(String schemaResource) { Schema schema = schemaCache.get( schemaResource ); if ( schema != null ) { return schema; } schema = loadSchema( schemaResource ); if ( schema != null ) { Schema previous = schemaCache.putIfAbsent( schemaResource, schema ); return previous != null ? previous : schema; } else { return null; } } private Schema loadSchema(String schemaResource) { ClassLoader loader = run( GetClassLoader.fromClass( XmlParserHelper.class ) ); URL schemaUrl = run( GetResource.action( loader, schemaResource ) ); SchemaFactory sf = SchemaFactory.newInstance( javax.xml.XMLConstants.W3C_XML_SCHEMA_NS_URI ); Schema schema = null; try { schema = run( NewSchema.action( sf, schemaUrl ) ); } catch (Exception e) { LOG.unableToCreateSchema( schemaResource, e.getMessage() ); } return schema; } /** * 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. */ private T run(PrivilegedAction action) { return System.getSecurityManager() != null ? AccessController.doPrivileged( action ) : action.run(); } private T run(PrivilegedExceptionAction action) throws Exception { return System.getSecurityManager() != null ? AccessController.doPrivileged( action ) : action.run(); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy