HHH-7981 - Load (now) locally defined orm.xsd while processing orm.xml files
This commit is contained in:
parent
03a56f58b9
commit
86aca3d101
|
@ -69,6 +69,14 @@ public class InvalidMappingException extends MappingException {
|
|||
this("Could not parse mapping document from " + type + (path==null?"":" " + path), type, path, cause);
|
||||
}
|
||||
|
||||
public InvalidMappingException(String message, org.hibernate.internal.util.xml.Origin origin, Exception cause) {
|
||||
this( message, origin.getType(), origin.getName(), cause );
|
||||
}
|
||||
|
||||
public InvalidMappingException(String message, org.hibernate.internal.util.xml.Origin origin) {
|
||||
this( message, origin, null );
|
||||
}
|
||||
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,147 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2013, Red Hat Inc. or third-party contributors as
|
||||
* indicated by the @author tags or express copyright attribution
|
||||
* statements applied by the authors. All third-party contributions are
|
||||
* distributed under license by Red Hat Inc.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||
* Lesser General Public License, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this distribution; if not, write to:
|
||||
* Free Software Foundation, Inc.
|
||||
* 51 Franklin Street, Fifth Floor
|
||||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.hibernate.internal.util.xml;
|
||||
|
||||
import javax.xml.stream.XMLEventReader;
|
||||
import javax.xml.stream.XMLStreamConstants;
|
||||
import javax.xml.stream.XMLStreamException;
|
||||
import javax.xml.stream.events.Characters;
|
||||
import javax.xml.stream.events.EntityDeclaration;
|
||||
import javax.xml.stream.events.EntityReference;
|
||||
import javax.xml.stream.events.XMLEvent;
|
||||
import javax.xml.stream.util.EventReaderDelegate;
|
||||
|
||||
/**
|
||||
* Base for XMLEventReader that implements the {@link #getElementText()} and {@link #nextTag()} APIs in a
|
||||
* way that is agnostic from the rest of the XMLEventReader implementation. Both will use the subclasses
|
||||
* {@link #internalNextEvent()} as the exclusive way to read events.
|
||||
*
|
||||
* Note, copied from the uPortal project by permission of author. See
|
||||
* https://github.com/Jasig/uPortal/blob/master/uportal-war/src/main/java/org/jasig/portal/xml/stream/BaseXMLEventReader.java
|
||||
*
|
||||
* @author Eric Dalquist
|
||||
*/
|
||||
public abstract class BaseXMLEventReader extends EventReaderDelegate {
|
||||
private XMLEvent previousEvent;
|
||||
|
||||
public BaseXMLEventReader(XMLEventReader reader) {
|
||||
super(reader);
|
||||
}
|
||||
|
||||
/**
|
||||
* Subclass's version of {@link #nextEvent()}, called by {@link #next()}
|
||||
*/
|
||||
protected abstract XMLEvent internalNextEvent() throws XMLStreamException;
|
||||
|
||||
/**
|
||||
* @return The XMLEvent returned by the last call to {@link #internalNextEvent()}
|
||||
*/
|
||||
protected final XMLEvent getPreviousEvent() {
|
||||
return this.previousEvent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final XMLEvent nextEvent() throws XMLStreamException {
|
||||
this.previousEvent = this.internalNextEvent();
|
||||
return this.previousEvent;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see java.util.Iterator#next()
|
||||
*/
|
||||
@Override
|
||||
public final Object next() {
|
||||
try {
|
||||
return this.nextEvent();
|
||||
}
|
||||
catch (XMLStreamException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see javax.xml.stream.XMLEventReader#getElementText()
|
||||
*/
|
||||
@Override
|
||||
public final String getElementText() throws XMLStreamException {
|
||||
XMLEvent event = this.previousEvent;
|
||||
if (event == null) {
|
||||
throw new XMLStreamException("Must be on START_ELEMENT to read next text, element was null");
|
||||
}
|
||||
if (!event.isStartElement()) {
|
||||
throw new XMLStreamException("Must be on START_ELEMENT to read next text", event.getLocation());
|
||||
}
|
||||
|
||||
final StringBuilder text = new StringBuilder();
|
||||
while (!event.isEndDocument()) {
|
||||
switch (event.getEventType()) {
|
||||
case XMLStreamConstants.CHARACTERS:
|
||||
case XMLStreamConstants.SPACE:
|
||||
case XMLStreamConstants.CDATA: {
|
||||
final Characters characters = event.asCharacters();
|
||||
text.append(characters.getData());
|
||||
break;
|
||||
}
|
||||
case XMLStreamConstants.ENTITY_REFERENCE: {
|
||||
final EntityReference entityReference = (EntityReference)event;
|
||||
final EntityDeclaration declaration = entityReference.getDeclaration();
|
||||
text.append(declaration.getReplacementText());
|
||||
break;
|
||||
}
|
||||
case XMLStreamConstants.COMMENT:
|
||||
case XMLStreamConstants.PROCESSING_INSTRUCTION: {
|
||||
//Ignore
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
throw new XMLStreamException("Unexpected event type '" + XMLStreamConstantsUtils.getEventName(event.getEventType()) + "' encountered. Found event: " + event, event.getLocation());
|
||||
}
|
||||
}
|
||||
|
||||
event = this.nextEvent();
|
||||
}
|
||||
|
||||
return text.toString();
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see javax.xml.stream.XMLEventReader#nextTag()
|
||||
*/
|
||||
@Override
|
||||
public final XMLEvent nextTag() throws XMLStreamException {
|
||||
XMLEvent event = this.nextEvent();
|
||||
while ((event.isCharacters() && event.asCharacters().isWhiteSpace())
|
||||
|| event.isProcessingInstruction()
|
||||
|| event.getEventType() == XMLStreamConstants.COMMENT) {
|
||||
|
||||
event = this.nextEvent();
|
||||
}
|
||||
|
||||
if (!event.isStartElement() && event.isEndElement()) {
|
||||
throw new XMLStreamException("Unexpected event type '" + XMLStreamConstantsUtils.getEventName(event.getEventType()) + "' encountered. Found event: " + event, event.getLocation());
|
||||
}
|
||||
|
||||
return event;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,196 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2013, Red Hat Inc. or third-party contributors as
|
||||
* indicated by the @author tags or express copyright attribution
|
||||
* statements applied by the authors. All third-party contributions are
|
||||
* distributed under license by Red Hat Inc.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||
* Lesser General Public License, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this distribution; if not, write to:
|
||||
* Free Software Foundation, Inc.
|
||||
* 51 Franklin Street, Fifth Floor
|
||||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.hibernate.internal.util.xml;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.ListIterator;
|
||||
|
||||
import javax.xml.stream.XMLEventReader;
|
||||
import javax.xml.stream.XMLStreamException;
|
||||
import javax.xml.stream.events.XMLEvent;
|
||||
|
||||
/**
|
||||
* Buffers XML events for later re-reading
|
||||
*
|
||||
* Note, copied from the uPortal project by permission of author. See
|
||||
* https://github.com/Jasig/uPortal/blob/master/uportal-war/src/main/java/org/jasig/portal/xml/stream/BufferedXMLEventReader.java
|
||||
*
|
||||
* @author Eric Dalquist
|
||||
*/
|
||||
public class BufferedXMLEventReader extends BaseXMLEventReader {
|
||||
private final LinkedList<XMLEvent> eventBuffer = new LinkedList<XMLEvent>();
|
||||
private int eventLimit = 0;
|
||||
private ListIterator<XMLEvent> bufferReader = null;
|
||||
|
||||
/**
|
||||
* Create new buffering reader, no buffering is done until {@link #mark(int)} is called.
|
||||
*/
|
||||
public BufferedXMLEventReader(XMLEventReader reader) {
|
||||
super(reader);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create new buffering reader. Calls {@link #mark(int)} with the specified event limit
|
||||
* @see #mark(int)
|
||||
*/
|
||||
public BufferedXMLEventReader(XMLEventReader reader, int eventLimit) {
|
||||
super(reader);
|
||||
this.eventLimit = eventLimit;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return A copy of the current buffer
|
||||
*/
|
||||
public List<XMLEvent> getBuffer() {
|
||||
return new ArrayList<XMLEvent>(this.eventBuffer);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.jasig.portal.xml.stream.BaseXMLEventReader#internalNextEvent()
|
||||
*/
|
||||
@Override
|
||||
protected XMLEvent internalNextEvent() throws XMLStreamException {
|
||||
//If there is an iterator to read from reset was called, use the iterator
|
||||
//until it runs out of events.
|
||||
if (this.bufferReader != null) {
|
||||
final XMLEvent event = this.bufferReader.next();
|
||||
|
||||
//If nothing left in the iterator, remove the reference and fall through to direct reading
|
||||
if (!this.bufferReader.hasNext()) {
|
||||
this.bufferReader = null;
|
||||
}
|
||||
|
||||
return event;
|
||||
}
|
||||
|
||||
//Get the next event from the underlying reader
|
||||
final XMLEvent event = this.getParent().nextEvent();
|
||||
|
||||
//if buffering add the event
|
||||
if (this.eventLimit != 0) {
|
||||
this.eventBuffer.offer(event);
|
||||
|
||||
//If limited buffer size and buffer is too big trim the buffer.
|
||||
if (this.eventLimit > 0 && this.eventBuffer.size() > this.eventLimit) {
|
||||
this.eventBuffer.poll();
|
||||
}
|
||||
}
|
||||
|
||||
return event;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
return this.bufferReader != null || super.hasNext();
|
||||
}
|
||||
|
||||
@Override
|
||||
public XMLEvent peek() throws XMLStreamException {
|
||||
if (this.bufferReader != null) {
|
||||
final XMLEvent event = this.bufferReader.next();
|
||||
this.bufferReader.previous(); //move the iterator back
|
||||
return event;
|
||||
}
|
||||
return super.peek();
|
||||
}
|
||||
|
||||
/**
|
||||
* Same as calling {@link #mark(int)} with -1.
|
||||
*/
|
||||
public void mark() {
|
||||
this.mark(-1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Start buffering events
|
||||
* @param eventLimit the maximum number of events to buffer. -1 will buffer all events, 0 will buffer no events.
|
||||
*/
|
||||
public void mark(int eventLimit) {
|
||||
this.eventLimit = eventLimit;
|
||||
|
||||
//Buffering no events now, clear the buffer and buffered reader
|
||||
if (this.eventLimit == 0) {
|
||||
this.eventBuffer.clear();
|
||||
this.bufferReader = null;
|
||||
}
|
||||
//Buffering limited set of events, lets trim the buffer if needed
|
||||
else if (this.eventLimit > 0) {
|
||||
//If there is an iterator check its current position and calculate the new iterator start position
|
||||
int iteratorIndex = 0;
|
||||
if (this.bufferReader != null) {
|
||||
final int nextIndex = this.bufferReader.nextIndex();
|
||||
iteratorIndex = Math.max(0, nextIndex - (this.eventBuffer.size() - this.eventLimit));
|
||||
}
|
||||
|
||||
//Trim the buffer until it is not larger than the limit
|
||||
while (this.eventBuffer.size() > this.eventLimit) {
|
||||
this.eventBuffer.poll();
|
||||
}
|
||||
|
||||
//If there is an iterator re-create it using the newly calculated index
|
||||
if (this.bufferReader != null) {
|
||||
this.bufferReader = this.eventBuffer.listIterator(iteratorIndex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset the reader to these start of the buffered events.
|
||||
*/
|
||||
public void reset() {
|
||||
if (this.eventBuffer.isEmpty()) {
|
||||
this.bufferReader = null;
|
||||
}
|
||||
else {
|
||||
this.bufferReader = this.eventBuffer.listIterator();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws XMLStreamException {
|
||||
this.mark(0);
|
||||
super.close();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The number of events in the buffer.
|
||||
*/
|
||||
public int bufferSize() {
|
||||
return this.eventBuffer.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* If reading from the buffer after a {@link #reset()} call an {@link IllegalStateException} will be thrown.
|
||||
*/
|
||||
@Override
|
||||
public void remove() {
|
||||
if (this.bufferReader != null && this.bufferReader.hasNext()) {
|
||||
throw new IllegalStateException("Cannot remove a buffered element");
|
||||
}
|
||||
|
||||
super.remove();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,141 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2013, Red Hat Inc. or third-party contributors as
|
||||
* indicated by the @author tags or express copyright attribution
|
||||
* statements applied by the authors. All third-party contributions are
|
||||
* distributed under license by Red Hat Inc.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||
* Lesser General Public License, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this distribution; if not, write to:
|
||||
* Free Software Foundation, Inc.
|
||||
* 51 Franklin Street, Fifth Floor
|
||||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.hibernate.internal.util.xml;
|
||||
|
||||
import java.util.Deque;
|
||||
import java.util.LinkedList;
|
||||
import java.util.NoSuchElementException;
|
||||
|
||||
import javax.xml.namespace.QName;
|
||||
import javax.xml.stream.XMLEventReader;
|
||||
import javax.xml.stream.XMLStreamException;
|
||||
import javax.xml.stream.events.EndElement;
|
||||
import javax.xml.stream.events.StartElement;
|
||||
import javax.xml.stream.events.XMLEvent;
|
||||
|
||||
/**
|
||||
* Base class for {@link XMLEventReader}s that want to modify or remove events from the reader stream.
|
||||
* If a {@link StartElement} event is removed the subclass's {@link #filterEvent(XMLEvent, boolean)} will
|
||||
* not see any events until after the matching {@link EndElement} event.
|
||||
*
|
||||
* Note, copied from the uPortal project by permission of author. See
|
||||
* https://github.com/Jasig/uPortal/blob/master/uportal-war/src/main/java/org/jasig/portal/xml/stream/FilteringXMLEventReader.java
|
||||
*
|
||||
* @author Eric Dalquist
|
||||
*/
|
||||
public abstract class FilteringXMLEventReader extends BaseXMLEventReader {
|
||||
private final Deque<QName> prunedElements = new LinkedList<QName>();
|
||||
private XMLEvent peekedEvent = null;
|
||||
|
||||
public FilteringXMLEventReader(XMLEventReader reader) {
|
||||
super(reader);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected final XMLEvent internalNextEvent() throws XMLStreamException {
|
||||
return this.internalNext(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
try {
|
||||
return peekedEvent != null || (super.hasNext() && this.peek() != null);
|
||||
}
|
||||
catch (XMLStreamException e) {
|
||||
throw new RuntimeException(e.getMessage(), e);
|
||||
}
|
||||
catch (NoSuchElementException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public final XMLEvent peek() throws XMLStreamException {
|
||||
if (peekedEvent != null) {
|
||||
return peekedEvent;
|
||||
}
|
||||
|
||||
peekedEvent = internalNext(true);
|
||||
return peekedEvent;
|
||||
}
|
||||
|
||||
protected final XMLEvent internalNext(boolean peek) throws XMLStreamException {
|
||||
XMLEvent event = null;
|
||||
|
||||
if (peekedEvent != null) {
|
||||
event = peekedEvent;
|
||||
peekedEvent = null;
|
||||
return event;
|
||||
}
|
||||
|
||||
do {
|
||||
event = super.getParent().nextEvent();
|
||||
|
||||
//If there are pruned elements in the queue filtering events is still needed
|
||||
if (!prunedElements.isEmpty()) {
|
||||
//If another start element add it to the queue
|
||||
if (event.isStartElement()) {
|
||||
final StartElement startElement = event.asStartElement();
|
||||
prunedElements.push(startElement.getName());
|
||||
}
|
||||
//If end element pop the newest name of the queue and double check that the start/end elements match up
|
||||
else if (event.isEndElement()) {
|
||||
final QName startElementName = prunedElements.pop();
|
||||
|
||||
final EndElement endElement = event.asEndElement();
|
||||
final QName endElementName = endElement.getName();
|
||||
|
||||
if (!startElementName.equals(endElementName)) {
|
||||
throw new IllegalArgumentException("Malformed XMLEvent stream. Expected end element for " + startElementName + " but found end element for " + endElementName);
|
||||
}
|
||||
}
|
||||
|
||||
event = null;
|
||||
}
|
||||
else {
|
||||
final XMLEvent filteredEvent = this.filterEvent(event, peek);
|
||||
|
||||
//If the event is being removed and it is a start element all elements until the matching
|
||||
//end element need to be removed as well
|
||||
if (filteredEvent == null && event.isStartElement()) {
|
||||
final StartElement startElement = event.asStartElement();
|
||||
final QName name = startElement.getName();
|
||||
prunedElements.push(name);
|
||||
}
|
||||
|
||||
event = filteredEvent;
|
||||
}
|
||||
}
|
||||
while (event == null);
|
||||
|
||||
return event;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param event The current event
|
||||
* @param peek If the event is from a {@link #peek()} call
|
||||
* @return The event to return, if null is returned the event is dropped from the stream and the next event will be used.
|
||||
*/
|
||||
protected abstract XMLEvent filterEvent(XMLEvent event, boolean peek);
|
||||
}
|
|
@ -0,0 +1,148 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2013, Red Hat Inc. or third-party contributors as
|
||||
* indicated by the @author tags or express copyright attribution
|
||||
* statements applied by the authors. All third-party contributions are
|
||||
* distributed under license by Red Hat Inc.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||
* Lesser General Public License, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this distribution; if not, write to:
|
||||
* Free Software Foundation, Inc.
|
||||
* 51 Franklin Street, Fifth Floor
|
||||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.hibernate.internal.util.xml;
|
||||
|
||||
import javax.xml.stream.XMLResolver;
|
||||
import javax.xml.stream.XMLStreamException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.URL;
|
||||
|
||||
import org.xml.sax.InputSource;
|
||||
|
||||
import org.jboss.logging.Logger;
|
||||
|
||||
import org.hibernate.internal.CoreMessageLogger;
|
||||
import org.hibernate.internal.util.ConfigHelper;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class LocalXmlResourceResolver implements javax.xml.stream.XMLResolver {
|
||||
private static final CoreMessageLogger log = Logger.getMessageLogger(
|
||||
CoreMessageLogger.class,
|
||||
MappingReader.class.getName()
|
||||
);
|
||||
|
||||
public static final LocalXmlResourceResolver INSTANCE = new LocalXmlResourceResolver();
|
||||
|
||||
/**
|
||||
* Namespace for the orm.xml xsd for jpa 1.0 and 2.0
|
||||
*/
|
||||
public static final String INITIAL_JPA_ORM_NS = "http://java.sun.com/xml/ns/persistence/orm";
|
||||
|
||||
/**
|
||||
* Namespace for the orm.xml xsd for jpa 2.1
|
||||
*/
|
||||
public static final String SECOND_JPA_ORM_NS = "http://xmlns.jcp.org/xml/ns/persistence/orm";
|
||||
|
||||
public static final String HIBERNATE_MAPPING_DTD_URL_BASE = "http://www.hibernate.org/dtd/";
|
||||
public static final String LEGACY_HIBERNATE_MAPPING_DTD_URL_BASE = "http://hibernate.sourceforge.net/";
|
||||
public static final String CLASSPATH_EXTENSION_URL_BASE = "classpath://";
|
||||
|
||||
@Override
|
||||
public Object resolveEntity(String publicID, String systemID, String baseURI, String namespace) throws XMLStreamException {
|
||||
log.tracef( "In resolveEntity(%s, %s, %s, %s)", publicID, systemID, baseURI, namespace );
|
||||
|
||||
if ( namespace != null ) {
|
||||
log.debugf( "Interpreting namespace : %s", namespace );
|
||||
if ( INITIAL_JPA_ORM_NS.equals( namespace ) ) {
|
||||
return openUrlStream( MappingReader.SupportedOrmXsdVersion.ORM_2_0.getSchemaUrl() );
|
||||
}
|
||||
else if ( SECOND_JPA_ORM_NS.equals( namespace ) ) {
|
||||
return openUrlStream( MappingReader.SupportedOrmXsdVersion.ORM_2_1.getSchemaUrl() );
|
||||
}
|
||||
}
|
||||
|
||||
if ( systemID != null ) {
|
||||
log.debugf( "Interpreting systemID : %s", namespace );
|
||||
InputStream stream = null;
|
||||
if ( systemID.startsWith( HIBERNATE_MAPPING_DTD_URL_BASE ) ) {
|
||||
log.debug( "Recognized hibernate namespace; attempting to resolve on classpath under org/hibernate/" );
|
||||
stream = resolveOnClassPath( systemID, HIBERNATE_MAPPING_DTD_URL_BASE );
|
||||
}
|
||||
else if ( systemID.startsWith( LEGACY_HIBERNATE_MAPPING_DTD_URL_BASE ) ) {
|
||||
log.recognizedObsoleteHibernateNamespace( LEGACY_HIBERNATE_MAPPING_DTD_URL_BASE, HIBERNATE_MAPPING_DTD_URL_BASE );
|
||||
log.debug( "Attempting to resolve on classpath under org/hibernate/" );
|
||||
stream = resolveOnClassPath( systemID, LEGACY_HIBERNATE_MAPPING_DTD_URL_BASE );
|
||||
}
|
||||
else if ( systemID.startsWith( CLASSPATH_EXTENSION_URL_BASE ) ) {
|
||||
log.debug( "Recognized local namespace; attempting to resolve on classpath" );
|
||||
final String path = systemID.substring( CLASSPATH_EXTENSION_URL_BASE.length() );
|
||||
stream = resolveInLocalNamespace( path );
|
||||
if ( stream == null ) {
|
||||
log.debugf( "Unable to resolve [%s] on classpath", systemID );
|
||||
}
|
||||
else {
|
||||
log.debugf( "Resolved [%s] on classpath", systemID );
|
||||
}
|
||||
}
|
||||
|
||||
if ( stream != null ) {
|
||||
return stream;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private InputStream openUrlStream(URL url) {
|
||||
try {
|
||||
return url.openStream();
|
||||
}
|
||||
catch (IOException e) {
|
||||
throw new XmlInfrastructureException( "Could not open url stream : " + url.toExternalForm(), e );
|
||||
}
|
||||
}
|
||||
|
||||
private InputStream resolveOnClassPath(String systemID, String namespace) {
|
||||
final String relativeResourceName = systemID.substring( namespace.length() );
|
||||
final String path = "org/hibernate/" + relativeResourceName;
|
||||
InputStream dtdStream = resolveInHibernateNamespace( path );
|
||||
if ( dtdStream == null ) {
|
||||
log.debugf( "Unable to locate [%s] on classpath", systemID );
|
||||
if ( relativeResourceName.contains( "2.0" ) ) {
|
||||
log.usingOldDtd();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
else {
|
||||
log.debugf( "Located [%s] in classpath", systemID );
|
||||
return dtdStream;
|
||||
}
|
||||
}
|
||||
|
||||
private InputStream resolveInHibernateNamespace(String path) {
|
||||
return this.getClass().getClassLoader().getResourceAsStream( path );
|
||||
}
|
||||
|
||||
private InputStream resolveInLocalNamespace(String path) {
|
||||
try {
|
||||
return ConfigHelper.getUserResourceAsStream( path );
|
||||
}
|
||||
catch ( Throwable t ) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -23,10 +23,27 @@
|
|||
*/
|
||||
package org.hibernate.internal.util.xml;
|
||||
|
||||
import javax.xml.XMLConstants;
|
||||
import javax.xml.namespace.QName;
|
||||
import javax.xml.stream.XMLEventReader;
|
||||
import javax.xml.stream.XMLInputFactory;
|
||||
import javax.xml.stream.XMLStreamConstants;
|
||||
import javax.xml.stream.XMLStreamException;
|
||||
import javax.xml.stream.events.Attribute;
|
||||
import javax.xml.stream.events.XMLEvent;
|
||||
import javax.xml.transform.stax.StAXSource;
|
||||
import javax.xml.transform.stream.StreamSource;
|
||||
import javax.xml.validation.Schema;
|
||||
import javax.xml.validation.SchemaFactory;
|
||||
import javax.xml.validation.Validator;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.StringReader;
|
||||
import java.net.URL;
|
||||
|
||||
import org.dom4j.Document;
|
||||
import org.dom4j.io.SAXReader;
|
||||
import org.dom4j.io.STAXEventReader;
|
||||
import org.xml.sax.EntityResolver;
|
||||
import org.xml.sax.InputSource;
|
||||
import org.xml.sax.SAXException;
|
||||
|
@ -59,7 +76,236 @@ public class MappingReader {
|
|||
private MappingReader() {
|
||||
}
|
||||
|
||||
public XmlDocument readMappingDocument(InputSource source, Origin origin) {
|
||||
XMLEventReader staxReader = buildStaxEventReader( source, origin );
|
||||
try {
|
||||
return read( staxReader, origin );
|
||||
}
|
||||
finally {
|
||||
try {
|
||||
staxReader.close();
|
||||
}
|
||||
catch ( Exception ignore ) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private XMLEventReader buildStaxEventReader(InputSource source, Origin origin) {
|
||||
XMLEventReader reader = null;
|
||||
|
||||
if ( source.getByteStream() != null ) {
|
||||
try {
|
||||
reader = staxFactory().createXMLEventReader( source.getByteStream() );
|
||||
}
|
||||
catch (XMLStreamException e) {
|
||||
throw new XmlInfrastructureException(
|
||||
"Unable to create stax reader, origin = " + toLoggableString( origin ),
|
||||
e
|
||||
);
|
||||
}
|
||||
}
|
||||
else if ( source.getCharacterStream() != null ) {
|
||||
try {
|
||||
reader = staxFactory().createXMLEventReader( source.getCharacterStream() );
|
||||
}
|
||||
catch (XMLStreamException e) {
|
||||
throw new XmlInfrastructureException(
|
||||
"Unable to create stax reader, origin = " + toLoggableString( origin ),
|
||||
e
|
||||
);
|
||||
}
|
||||
}
|
||||
// todo : try to interpret the InputSource SystemId or Origin path?
|
||||
|
||||
if ( reader == null ) {
|
||||
throw new XmlInfrastructureException( "Unable to convert SAX InputStream into StAX XMLEventReader" );
|
||||
}
|
||||
|
||||
// For performance we wrap the reader in a buffered reader
|
||||
return new BufferedXMLEventReader( reader );
|
||||
}
|
||||
|
||||
private XMLInputFactory staxFactory;
|
||||
|
||||
private XMLInputFactory staxFactory() {
|
||||
if ( staxFactory == null ) {
|
||||
staxFactory = buildStaxFactory();
|
||||
}
|
||||
return staxFactory;
|
||||
}
|
||||
|
||||
@SuppressWarnings( { "UnnecessaryLocalVariable" })
|
||||
private XMLInputFactory buildStaxFactory() {
|
||||
XMLInputFactory staxFactory = XMLInputFactory.newInstance();
|
||||
staxFactory.setXMLResolver( LocalXmlResourceResolver.INSTANCE );
|
||||
return staxFactory;
|
||||
}
|
||||
|
||||
private String toLoggableString(Origin origin) {
|
||||
return "[type=" + origin.getType() + ", name=" + origin.getName() + "]";
|
||||
}
|
||||
|
||||
private static final QName ORM_VERSION_ATTRIBUTE_QNAME = new QName( "version" );
|
||||
|
||||
private XmlDocument read(XMLEventReader staxEventReader, Origin origin) {
|
||||
XMLEvent event;
|
||||
try {
|
||||
event = staxEventReader.peek();
|
||||
while ( event != null && !event.isStartElement() ) {
|
||||
staxEventReader.nextEvent();
|
||||
event = staxEventReader.peek();
|
||||
}
|
||||
}
|
||||
catch ( Exception e ) {
|
||||
throw new InvalidMappingException( "Error accessing stax stream", origin, e );
|
||||
}
|
||||
|
||||
if ( event == null ) {
|
||||
throw new InvalidMappingException( "Could not locate root element", origin );
|
||||
}
|
||||
|
||||
final String rootElementName = event.asStartElement().getName().getLocalPart();
|
||||
|
||||
if ( "entity-mappings".equals( rootElementName ) ) {
|
||||
final Attribute attribute = event.asStartElement().getAttributeByName( ORM_VERSION_ATTRIBUTE_QNAME );
|
||||
final String explicitVersion = attribute == null ? null : attribute.getValue();
|
||||
validateMapping(
|
||||
SupportedOrmXsdVersion.parse( explicitVersion, origin ),
|
||||
staxEventReader,
|
||||
origin
|
||||
);
|
||||
}
|
||||
|
||||
return new XmlDocumentImpl( toDom4jDocument( staxEventReader, origin ), origin );
|
||||
}
|
||||
|
||||
private Document toDom4jDocument(XMLEventReader staxEventReader, Origin origin) {
|
||||
STAXEventReader dom4jStaxEventReader = new STAXEventReader();
|
||||
try {
|
||||
// the dom4j converter class is touchy about comments (aka, comments make it implode)
|
||||
// so wrap the event stream in a filtering stream to filter out comment events
|
||||
staxEventReader = new FilteringXMLEventReader( staxEventReader ) {
|
||||
@Override
|
||||
protected XMLEvent filterEvent(XMLEvent event, boolean peek) {
|
||||
return event.getEventType() == XMLStreamConstants.COMMENT
|
||||
? null
|
||||
: event;
|
||||
}
|
||||
};
|
||||
|
||||
return dom4jStaxEventReader.readDocument( staxEventReader );
|
||||
}
|
||||
catch (XMLStreamException e) {
|
||||
throw new InvalidMappingException( "Unable to read StAX source as dom4j Document for processing", origin, e );
|
||||
}
|
||||
}
|
||||
|
||||
private void validateMapping(SupportedOrmXsdVersion xsdVersion, XMLEventReader staxEventReader, Origin origin) {
|
||||
final Validator validator = xsdVersion.getSchema().newValidator();
|
||||
final StAXSource staxSource;
|
||||
try {
|
||||
staxSource = new StAXSource( staxEventReader );
|
||||
}
|
||||
catch (XMLStreamException e) {
|
||||
throw new InvalidMappingException( "Unable to generate StAXSource from mapping", origin, e );
|
||||
}
|
||||
|
||||
try {
|
||||
validator.validate( staxSource );
|
||||
}
|
||||
catch (SAXException e) {
|
||||
throw new InvalidMappingException( "SAXException performing validation", origin, e );
|
||||
}
|
||||
catch (IOException e) {
|
||||
throw new InvalidMappingException( "IOException performing validation", origin, e );
|
||||
}
|
||||
}
|
||||
|
||||
public static enum SupportedOrmXsdVersion {
|
||||
ORM_1_0( "org/hibernate/jpa/orm_1_0.xsd" ),
|
||||
ORM_2_0( "org/hibernate/jpa/orm_2_0.xsd" ),
|
||||
ORM_2_1( "org/hibernate/jpa/orm_2_1.xsd" );
|
||||
|
||||
private final String schemaResourceName;
|
||||
|
||||
private SupportedOrmXsdVersion(String schemaResourceName) {
|
||||
this.schemaResourceName = schemaResourceName;
|
||||
}
|
||||
|
||||
public static SupportedOrmXsdVersion parse(String name, Origin origin) {
|
||||
if ( "1.0".equals( name ) ) {
|
||||
return ORM_1_0;
|
||||
}
|
||||
else if ( "2.0".equals( name ) ) {
|
||||
return ORM_2_0;
|
||||
}
|
||||
else if ( "2.1".equals( name ) ) {
|
||||
return ORM_2_1;
|
||||
}
|
||||
throw new UnsupportedOrmXsdVersionException( name, origin );
|
||||
}
|
||||
|
||||
private URL schemaUrl;
|
||||
|
||||
public URL getSchemaUrl() {
|
||||
if ( schemaUrl == null ) {
|
||||
schemaUrl = resolveLocalSchemaUrl( schemaResourceName );
|
||||
}
|
||||
return schemaUrl;
|
||||
}
|
||||
|
||||
private Schema schema;
|
||||
|
||||
public Schema getSchema() {
|
||||
if ( schema == null ) {
|
||||
schema = resolveLocalSchema( getSchemaUrl() );
|
||||
}
|
||||
return schema;
|
||||
}
|
||||
}
|
||||
|
||||
private static URL resolveLocalSchemaUrl(String schemaName) {
|
||||
URL url = MappingReader.class.getClassLoader().getResource( schemaName );
|
||||
if ( url == null ) {
|
||||
throw new XmlInfrastructureException( "Unable to locate schema [" + schemaName + "] via classpath" );
|
||||
}
|
||||
return url;
|
||||
}
|
||||
|
||||
private static Schema resolveLocalSchema(URL schemaUrl) {
|
||||
|
||||
try {
|
||||
InputStream schemaStream = schemaUrl.openStream();
|
||||
try {
|
||||
StreamSource source = new StreamSource(schemaUrl.openStream());
|
||||
SchemaFactory schemaFactory = SchemaFactory.newInstance( XMLConstants.W3C_XML_SCHEMA_NS_URI );
|
||||
return schemaFactory.newSchema(source);
|
||||
}
|
||||
catch ( Exception e ) {
|
||||
throw new XmlInfrastructureException( "Unable to load schema [" + schemaUrl.toExternalForm() + "]", e );
|
||||
}
|
||||
finally {
|
||||
try {
|
||||
schemaStream.close();
|
||||
}
|
||||
catch ( IOException e ) {
|
||||
LOG.debugf( "Problem closing schema stream - %s", e.toString() );
|
||||
}
|
||||
}
|
||||
}
|
||||
catch ( IOException e ) {
|
||||
throw new XmlInfrastructureException( "Stream error handling schema url [" + schemaUrl.toExternalForm() + "]" );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
public XmlDocument readMappingDocument(EntityResolver entityResolver, InputSource source, Origin origin) {
|
||||
return legacyReadMappingDocument( entityResolver, source, origin );
|
||||
// return readMappingDocument( source, origin );
|
||||
}
|
||||
|
||||
private XmlDocument legacyReadMappingDocument(EntityResolver entityResolver, InputSource source, Origin origin) {
|
||||
// IMPL NOTE : this is the legacy logic as pulled from the old AnnotationConfiguration code
|
||||
|
||||
Exception failure;
|
||||
|
|
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2013, Red Hat Inc. or third-party contributors as
|
||||
* indicated by the @author tags or express copyright attribution
|
||||
* statements applied by the authors. All third-party contributions are
|
||||
* distributed under license by Red Hat Inc.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||
* Lesser General Public License, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this distribution; if not, write to:
|
||||
* Free Software Foundation, Inc.
|
||||
* 51 Franklin Street, Fifth Floor
|
||||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.hibernate.internal.util.xml;
|
||||
|
||||
import org.hibernate.HibernateException;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class UnsupportedOrmXsdVersionException extends HibernateException {
|
||||
public UnsupportedOrmXsdVersionException(String requestedVersion, Origin origin) {
|
||||
super(
|
||||
String.format(
|
||||
"Encountered unsupported orm.xml xsd version [%s] in mapping document [type=%s, name=%s]",
|
||||
requestedVersion,
|
||||
origin.getType(),
|
||||
origin.getName()
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,69 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2013, Red Hat Inc. or third-party contributors as
|
||||
* indicated by the @author tags or express copyright attribution
|
||||
* statements applied by the authors. All third-party contributions are
|
||||
* distributed under license by Red Hat Inc.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||
* Lesser General Public License, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this distribution; if not, write to:
|
||||
* Free Software Foundation, Inc.
|
||||
* 51 Franklin Street, Fifth Floor
|
||||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.hibernate.internal.util.xml;
|
||||
|
||||
import javax.xml.stream.XMLStreamConstants;
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
* Note, copied from the uPortal project by permission of author. See
|
||||
* https://github.com/Jasig/uPortal/blob/master/uportal-war/src/main/java/org/jasig/portal/xml/stream/XMLStreamConstantsUtils.java
|
||||
*
|
||||
* @author Eric Dalquist
|
||||
*/
|
||||
public class XMLStreamConstantsUtils {
|
||||
/**
|
||||
* Get the human readable event name for the numeric event id
|
||||
*/
|
||||
public static String getEventName(int eventId) {
|
||||
switch (eventId) {
|
||||
case XMLStreamConstants.START_ELEMENT:
|
||||
return "StartElementEvent";
|
||||
case XMLStreamConstants.END_ELEMENT:
|
||||
return "EndElementEvent";
|
||||
case XMLStreamConstants.PROCESSING_INSTRUCTION:
|
||||
return "ProcessingInstructionEvent";
|
||||
case XMLStreamConstants.CHARACTERS:
|
||||
return "CharacterEvent";
|
||||
case XMLStreamConstants.COMMENT:
|
||||
return "CommentEvent";
|
||||
case XMLStreamConstants.START_DOCUMENT:
|
||||
return "StartDocumentEvent";
|
||||
case XMLStreamConstants.END_DOCUMENT:
|
||||
return "EndDocumentEvent";
|
||||
case XMLStreamConstants.ENTITY_REFERENCE:
|
||||
return "EntityReferenceEvent";
|
||||
case XMLStreamConstants.ATTRIBUTE:
|
||||
return "AttributeBase";
|
||||
case XMLStreamConstants.DTD:
|
||||
return "DTDEvent";
|
||||
case XMLStreamConstants.CDATA:
|
||||
return "CDATA";
|
||||
}
|
||||
return "UNKNOWN_EVENT_TYPE";
|
||||
}
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2013, Red Hat Inc. or third-party contributors as
|
||||
* indicated by the @author tags or express copyright attribution
|
||||
* statements applied by the authors. All third-party contributions are
|
||||
* distributed under license by Red Hat Inc.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||
* Lesser General Public License, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this distribution; if not, write to:
|
||||
* Free Software Foundation, Inc.
|
||||
* 51 Franklin Street, Fifth Floor
|
||||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.hibernate.internal.util.xml;
|
||||
|
||||
import org.hibernate.HibernateException;
|
||||
|
||||
/**
|
||||
* An error using XML infrastructure (jaxp, stax, etc).
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class XmlInfrastructureException extends HibernateException {
|
||||
public XmlInfrastructureException(String message) {
|
||||
super( message );
|
||||
}
|
||||
|
||||
public XmlInfrastructureException(String message, Throwable root) {
|
||||
super( message, root );
|
||||
}
|
||||
}
|
|
@ -27,6 +27,7 @@ import java.io.InputStream;
|
|||
|
||||
import org.hibernate.InvalidMappingException;
|
||||
import org.hibernate.cfg.Configuration;
|
||||
import org.hibernate.internal.util.xml.UnsupportedOrmXsdVersionException;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
|
@ -49,5 +50,7 @@ public class NonExistentOrmVersionTest extends BaseCoreFunctionalTestCase {
|
|||
}
|
||||
catch ( InvalidMappingException expected ) {
|
||||
}
|
||||
catch ( UnsupportedOrmXsdVersionException expected ) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue