diff --git a/hibernate-core/hibernate-core.gradle b/hibernate-core/hibernate-core.gradle
index 3f65833c23..0bb0b8f4c5 100644
--- a/hibernate-core/hibernate-core.gradle
+++ b/hibernate-core/hibernate-core.gradle
@@ -84,7 +84,7 @@ task jaxb {
// input schemas
cfgXsd = file( 'src/main/resources/org/hibernate/hibernate-configuration-4.0.xsd')
hbmXsd = file( 'src/main/resources/org/hibernate/hibernate-mapping-4.0.xsd' )
- ormXsd = file( 'src/main/resources/org/hibernate/ejb/orm_2_0.xsd' )
+ ormXsd = file( 'src/main/resources/org/hibernate/jpa/orm_2_1.xsd' )
// input bindings
cfgXjb = file( 'src/main/xjb/hbm-configuration-bindings.xjb' )
diff --git a/hibernate-core/src/main/java/org/hibernate/InvalidMappingException.java b/hibernate-core/src/main/java/org/hibernate/InvalidMappingException.java
index 59a1d862a0..c4e461cb7d 100644
--- a/hibernate-core/src/main/java/org/hibernate/InvalidMappingException.java
+++ b/hibernate-core/src/main/java/org/hibernate/InvalidMappingException.java
@@ -49,26 +49,34 @@ public class InvalidMappingException extends MappingException {
this.path=path;
}
- public InvalidMappingException(String customMessage, XmlDocument xmlDocument, Throwable cause) {
- this( customMessage, xmlDocument.getOrigin().getType(), xmlDocument.getOrigin().getName(), cause );
- }
-
- public InvalidMappingException(String customMessage, XmlDocument xmlDocument) {
- this( customMessage, xmlDocument.getOrigin().getType(), xmlDocument.getOrigin().getName() );
- }
-
- public InvalidMappingException(String customMessage, Origin origin) {
- this( customMessage, origin.getType().toString(), origin.getName() );
- }
-
- public InvalidMappingException(String type, String path) {
- this("Could not parse mapping document from " + type + (path==null?"":" " + path), type, path);
- }
+// public InvalidMappingException(String customMessage, XmlDocument xmlDocument, Throwable cause) {
+// this( customMessage, xmlDocument.getOrigin().getType(), xmlDocument.getOrigin().getName(), cause );
+// }
+//
+// public InvalidMappingException(String customMessage, XmlDocument xmlDocument) {
+// this( customMessage, xmlDocument.getOrigin().getType(), xmlDocument.getOrigin().getName() );
+// }
+//
+// public InvalidMappingException(String customMessage, Origin origin) {
+// this( customMessage, origin.getType().toString(), origin.getName() );
+// }
+//
+// public InvalidMappingException(String type, String path) {
+// this("Could not parse mapping document from " + type + (path==null?"":" " + path), type, path);
+// }
public InvalidMappingException(String type, String path, Throwable cause) {
this("Could not parse mapping document from " + type + (path==null?"":" " + path), type, path, cause);
}
+ public InvalidMappingException(String message, Origin origin, Exception cause) {
+ this( message, origin.getType().name(), origin.getName(), cause );
+ }
+
+ public InvalidMappingException(String message, Origin origin) {
+ this( message, origin, null );
+ }
+
public String getType() {
return type;
}
diff --git a/hibernate-core/src/main/java/org/hibernate/cfg/AnnotationBinder.java b/hibernate-core/src/main/java/org/hibernate/cfg/AnnotationBinder.java
index 5147b9e066..2c36c31f1c 100644
--- a/hibernate-core/src/main/java/org/hibernate/cfg/AnnotationBinder.java
+++ b/hibernate-core/src/main/java/org/hibernate/cfg/AnnotationBinder.java
@@ -155,6 +155,7 @@ import org.hibernate.id.SequenceHiLoGenerator;
import org.hibernate.id.TableHiLoGenerator;
import org.hibernate.id.enhanced.SequenceStyleGenerator;
import org.hibernate.internal.CoreMessageLogger;
+import org.hibernate.internal.util.StringHelper;
import org.hibernate.mapping.Any;
import org.hibernate.mapping.Component;
import org.hibernate.mapping.DependantValue;
@@ -2090,12 +2091,12 @@ public final class AnnotationBinder {
if ( naturalIdAnn != null ) {
if ( joinColumns != null ) {
for ( Ejb3Column column : joinColumns ) {
- column.addUniqueKey( "_UniqueKey", inSecondPass );
+ column.addUniqueKey( StringHelper.randomFixedLengthHex("UK_"), inSecondPass );
}
}
else {
for ( Ejb3Column column : columns ) {
- column.addUniqueKey( "_UniqueKey", inSecondPass );
+ column.addUniqueKey( StringHelper.randomFixedLengthHex("UK_"), inSecondPass );
}
}
}
diff --git a/hibernate-core/src/main/java/org/hibernate/cfg/Configuration.java b/hibernate-core/src/main/java/org/hibernate/cfg/Configuration.java
index 8afa907d9e..6f83f594de 100644
--- a/hibernate-core/src/main/java/org/hibernate/cfg/Configuration.java
+++ b/hibernate-core/src/main/java/org/hibernate/cfg/Configuration.java
@@ -112,11 +112,11 @@ import org.hibernate.internal.util.collections.JoinedIterator;
import org.hibernate.internal.util.config.ConfigurationHelper;
import org.hibernate.internal.util.xml.ErrorLogger;
import org.hibernate.internal.util.xml.MappingReader;
-import org.hibernate.internal.util.xml.Origin;
-import org.hibernate.internal.util.xml.OriginImpl;
import org.hibernate.internal.util.xml.XMLHelper;
import org.hibernate.internal.util.xml.XmlDocument;
import org.hibernate.internal.util.xml.XmlDocumentImpl;
+import org.hibernate.jaxb.spi.Origin;
+import org.hibernate.jaxb.spi.SourceType;
import org.hibernate.mapping.AuxiliaryDatabaseObject;
import org.hibernate.mapping.Collection;
import org.hibernate.mapping.Column;
@@ -473,12 +473,12 @@ public class Configuration implements Serializable {
catch ( FileNotFoundException e ) {
throw new MappingNotFoundException( "file", xmlFile.toString() );
}
- add( inputSource, "file", name );
+ add( inputSource, SourceType.FILE, name );
return this;
}
- private XmlDocument add(InputSource inputSource, String originType, String originName) {
- return add( inputSource, new OriginImpl( originType, originName ) );
+ private XmlDocument add(InputSource inputSource, SourceType originType, String originName) {
+ return add( inputSource, new Origin( originType, originName ) );
}
private XmlDocument add(InputSource inputSource, Origin origin) {
@@ -549,7 +549,7 @@ public class Configuration implements Serializable {
}
LOG.readingMappingsFromFile( xmlFile.getPath() );
- XmlDocument metadataXml = add( inputSource, "file", name );
+ XmlDocument metadataXml = add( inputSource, SourceType.FILE, name );
try {
LOG.debugf( "Writing cache file for: %s to: %s", xmlFile, cachedFile );
@@ -592,7 +592,7 @@ public class Configuration implements Serializable {
LOG.readingCachedMappings( cachedFile );
Document document = ( Document ) SerializationHelper.deserialize( new FileInputStream( cachedFile ) );
- add( new XmlDocumentImpl( document, "file", xmlFile.getAbsolutePath() ) );
+ add( new XmlDocumentImpl( document, SourceType.FILE, xmlFile.getAbsolutePath() ) );
return this;
}
@@ -622,7 +622,7 @@ public class Configuration implements Serializable {
public Configuration addXML(String xml) throws MappingException {
LOG.debugf( "Mapping XML:\n%s", xml );
final InputSource inputSource = new InputSource( new StringReader( xml ) );
- add( inputSource, "string", "XML String" );
+ add( inputSource, SourceType.STRING, "XML String" );
return this;
}
@@ -640,7 +640,7 @@ public class Configuration implements Serializable {
LOG.debugf( "Reading mapping document from URL : %s", urlExternalForm );
try {
- add( url.openStream(), "URL", urlExternalForm );
+ add( url.openStream(), SourceType.URL, urlExternalForm );
}
catch ( IOException e ) {
throw new InvalidMappingException( "Unable to open url stream [" + urlExternalForm + "]", "URL", urlExternalForm, e );
@@ -648,7 +648,7 @@ public class Configuration implements Serializable {
return this;
}
- private XmlDocument add(InputStream inputStream, final String type, final String name) {
+ private XmlDocument add(InputStream inputStream, final SourceType type, final String name) {
final InputSource inputSource = new InputSource( inputStream );
try {
return add( inputSource, type, name );
@@ -675,7 +675,7 @@ public class Configuration implements Serializable {
LOG.debugf( "Mapping Document:\n%s", doc );
final Document document = xmlHelper.createDOMReader().read( doc );
- add( new XmlDocumentImpl( document, "unknown", null ) );
+ add( new XmlDocumentImpl( document, SourceType.DOM, null ) );
return this;
}
@@ -689,7 +689,7 @@ public class Configuration implements Serializable {
* processing the contained mapping document.
*/
public Configuration addInputStream(InputStream xmlInputStream) throws MappingException {
- add( xmlInputStream, "input stream", null );
+ add( xmlInputStream, SourceType.INPUT_STREAM, null );
return this;
}
@@ -708,7 +708,7 @@ public class Configuration implements Serializable {
if ( resourceInputStream == null ) {
throw new MappingNotFoundException( "resource", resourceName );
}
- add( resourceInputStream, "resource", resourceName );
+ add( resourceInputStream, SourceType.RESOURCE, resourceName );
return this;
}
@@ -734,7 +734,7 @@ public class Configuration implements Serializable {
if ( resourceInputStream == null ) {
throw new MappingNotFoundException( "resource", resourceName );
}
- add( resourceInputStream, "resource", resourceName );
+ add( resourceInputStream, SourceType.RESOURCE, resourceName );
return this;
}
@@ -1186,6 +1186,21 @@ public class Configuration implements Serializable {
table.isQuoted()
);
+ Iterator uniqueIter = table.getUniqueKeyIterator();
+ while ( uniqueIter.hasNext() ) {
+ final UniqueKey uniqueKey = (UniqueKey) uniqueIter.next();
+ // Skip if index already exists
+ if ( tableInfo != null && StringHelper.isNotEmpty( uniqueKey.getName() ) ) {
+ final IndexMetadata meta = tableInfo.getIndexMetadata( uniqueKey.getName() );
+ if ( meta != null ) {
+ continue;
+ }
+ }
+ String constraintString = uniqueKey.sqlCreateString( dialect,
+ mapping, tableCatalog, tableSchema );
+ if (constraintString != null) script.add( constraintString );
+ }
+
if ( dialect.hasAlterTable() ) {
Iterator subIter = table.getForeignKeyIterator();
while ( subIter.hasNext() ) {
@@ -1378,11 +1393,9 @@ public class Configuration implements Serializable {
for ( Map.Entry
> tableListEntry : uniqueConstraintHoldersByTable.entrySet() ) {
final Table table = tableListEntry.getKey();
final List uniqueConstraints = tableListEntry.getValue();
- int uniqueIndexPerTable = 0;
for ( UniqueConstraintHolder holder : uniqueConstraints ) {
- uniqueIndexPerTable++;
final String keyName = StringHelper.isEmpty( holder.getName() )
- ? "UK_" + table.getName() + "_" + uniqueIndexPerTable
+ ? StringHelper.randomFixedLengthHex("UK_")
: holder.getName();
buildUniqueKeyFromColumnNames( table, keyName, holder.getColumns() );
}
@@ -3537,7 +3550,7 @@ public class Configuration implements Serializable {
}
catch ( MappingException me ) {
throw new InvalidMappingException(
- metadataXml.getOrigin().getType(),
+ metadataXml.getOrigin().getType().name(),
metadataXml.getOrigin().getName(),
me
);
diff --git a/hibernate-core/src/main/java/org/hibernate/cfg/EJB3DTDEntityResolver.java b/hibernate-core/src/main/java/org/hibernate/cfg/EJB3DTDEntityResolver.java
index 4eff1d24bb..78d21b3148 100644
--- a/hibernate-core/src/main/java/org/hibernate/cfg/EJB3DTDEntityResolver.java
+++ b/hibernate-core/src/main/java/org/hibernate/cfg/EJB3DTDEntityResolver.java
@@ -56,37 +56,57 @@ public class EJB3DTDEntityResolver extends DTDEntityResolver {
@Override
public InputSource resolveEntity(String publicId, String systemId) {
LOG.tracev( "Resolving XML entity {0} : {1}", publicId, systemId );
- InputSource is = super.resolveEntity( publicId, systemId );
- if ( is == null ) {
- if ( systemId != null ) {
- if ( systemId.endsWith( "orm_1_0.xsd" ) ) {
- InputStream dtdStream = getStreamFromClasspath( "orm_1_0.xsd" );
- final InputSource source = buildInputSource( publicId, systemId, dtdStream, false );
- if (source != null) return source;
+ if ( systemId != null ) {
+ if ( systemId.endsWith( "orm_2_1.xsd" ) ) {
+ InputStream dtdStream = getStreamFromClasspath( "orm_2_1.xsd" );
+ final InputSource source = buildInputSource( publicId, systemId, dtdStream, false );
+ if ( source != null ) {
+ return source;
}
- else if ( systemId.endsWith( "orm_2_0.xsd" ) ) {
- InputStream dtdStream = getStreamFromClasspath( "orm_2_0.xsd" );
- final InputSource source = buildInputSource( publicId, systemId, dtdStream, false );
- if (source != null) return source;
+ }
+ else if ( systemId.endsWith( "orm_2_0.xsd" ) ) {
+ InputStream dtdStream = getStreamFromClasspath( "orm_2_0.xsd" );
+ final InputSource source = buildInputSource( publicId, systemId, dtdStream, false );
+ if ( source != null ) {
+ return source;
}
- else if ( systemId.endsWith( "persistence_1_0.xsd" ) ) {
- InputStream dtdStream = getStreamFromClasspath( "persistence_1_0.xsd" );
- final InputSource source = buildInputSource( publicId, systemId, dtdStream, true );
- if (source != null) return source;
+ }
+ else if ( systemId.endsWith( "orm_1_0.xsd" ) ) {
+ InputStream dtdStream = getStreamFromClasspath( "orm_1_0.xsd" );
+ final InputSource source = buildInputSource( publicId, systemId, dtdStream, false );
+ if ( source != null ) {
+ return source;
}
- else if ( systemId.endsWith( "persistence_2_0.xsd" ) ) {
- InputStream dtdStream = getStreamFromClasspath( "persistence_2_0.xsd" );
- final InputSource source = buildInputSource( publicId, systemId, dtdStream, true );
- if (source != null) return source;
+ }
+ else if ( systemId.endsWith( "persistence_2_1.xsd" ) ) {
+ InputStream dtdStream = getStreamFromClasspath( "persistence_2_1.xsd" );
+ final InputSource source = buildInputSource( publicId, systemId, dtdStream, true );
+ if ( source != null ) {
+ return source;
+ }
+ }
+ else if ( systemId.endsWith( "persistence_2_0.xsd" ) ) {
+ InputStream dtdStream = getStreamFromClasspath( "persistence_2_0.xsd" );
+ final InputSource source = buildInputSource( publicId, systemId, dtdStream, true );
+ if ( source != null ) {
+ return source;
+ }
+ }
+ else if ( systemId.endsWith( "persistence_1_0.xsd" ) ) {
+ InputStream dtdStream = getStreamFromClasspath( "persistence_1_0.xsd" );
+ final InputSource source = buildInputSource( publicId, systemId, dtdStream, true );
+ if ( source != null ) {
+ return source;
}
}
}
- else {
+
+ // because the old code did this too (in terms of setting resolved)
+ InputSource source = super.resolveEntity( publicId, systemId );
+ if ( source != null ) {
resolved = true;
- return is;
}
- //use the default behavior
- return null;
+ return source;
}
private InputSource buildInputSource(String publicId, String systemId, InputStream dtdStream, boolean resolved) {
@@ -103,8 +123,8 @@ public class EJB3DTDEntityResolver extends DTDEntityResolver {
}
private InputStream getStreamFromClasspath(String fileName) {
- LOG.trace( "Recognized JPA ORM namespace; attempting to resolve on classpath under org/hibernate/ejb" );
- String path = "org/hibernate/ejb/" + fileName;
+ LOG.trace( "Recognized JPA ORM namespace; attempting to resolve on classpath under org/hibernate/jpa" );
+ String path = "org/hibernate/jpa/" + fileName;
InputStream dtdStream = resolveInHibernateNamespace( path );
return dtdStream;
}
diff --git a/hibernate-core/src/main/java/org/hibernate/cfg/HbmBinder.java b/hibernate-core/src/main/java/org/hibernate/cfg/HbmBinder.java
index 52eefa3abf..2ddff1e0d3 100644
--- a/hibernate-core/src/main/java/org/hibernate/cfg/HbmBinder.java
+++ b/hibernate-core/src/main/java/org/hibernate/cfg/HbmBinder.java
@@ -2247,7 +2247,7 @@ public final class HbmBinder {
}
else if ( "natural-id".equals( name ) ) {
UniqueKey uk = new UniqueKey();
- uk.setName("_UniqueKey");
+ uk.setName(StringHelper.randomFixedLengthHex("UK_"));
uk.setTable(table);
//by default, natural-ids are "immutable" (constant)
boolean mutableId = "true".equals( subnode.attributeValue("mutable") );
diff --git a/hibernate-core/src/main/java/org/hibernate/cfg/annotations/reflection/JPAOverriddenAnnotationReader.java b/hibernate-core/src/main/java/org/hibernate/cfg/annotations/reflection/JPAOverriddenAnnotationReader.java
index f16bb78eb2..8db6de8449 100644
--- a/hibernate-core/src/main/java/org/hibernate/cfg/annotations/reflection/JPAOverriddenAnnotationReader.java
+++ b/hibernate-core/src/main/java/org/hibernate/cfg/annotations/reflection/JPAOverriddenAnnotationReader.java
@@ -65,10 +65,12 @@ import javax.persistence.ExcludeDefaultListeners;
import javax.persistence.ExcludeSuperclassListeners;
import javax.persistence.FetchType;
import javax.persistence.FieldResult;
+import javax.persistence.ForeignKey;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.IdClass;
+import javax.persistence.Index;
import javax.persistence.Inheritance;
import javax.persistence.InheritanceType;
import javax.persistence.JoinColumn;
@@ -227,6 +229,8 @@ public class JPAOverriddenAnnotationReader implements AnnotationReader {
annotationToXml.put( MapKeyJoinColumns.class, "map-key-join-column" );
annotationToXml.put( OrderColumn.class, "order-column" );
annotationToXml.put( Cacheable.class, "cacheable" );
+ annotationToXml.put( Index.class, "index" );
+ annotationToXml.put( ForeignKey.class, "foreign-key" );
}
private XMLContext xmlContext;
@@ -659,6 +663,7 @@ public class JPAOverriddenAnnotationReader implements AnnotationReader {
annotation.setValue( "schema", defaults.getSchema() );
}
buildUniqueConstraints( annotation, subelement );
+ buildIndex( annotation, subelement );
annotation.setValue( "joinColumns", getJoinColumns( subelement, false ) );
annotation.setValue( "inverseJoinColumns", getJoinColumns( subelement, true ) );
return AnnotationFactory.create( annotation );
@@ -1069,6 +1074,7 @@ public class JPAOverriddenAnnotationReader implements AnnotationReader {
annotation.setValue( "joinColumns", joinColumns );
}
buildUniqueConstraints( annotation, subelement );
+ buildIndex( annotation, subelement );
annotationList.add( AnnotationFactory.create( annotation ) );
}
}
@@ -2298,6 +2304,7 @@ public class JPAOverriddenAnnotationReader implements AnnotationReader {
annotation.setValue( "schema", defaults.getSchema() );
}
buildUniqueConstraints( annotation, subelement );
+ buildIndex( annotation, subelement );
return AnnotationFactory.create( annotation );
}
}
@@ -2321,6 +2328,7 @@ public class JPAOverriddenAnnotationReader implements AnnotationReader {
annotation.setValue( "schema", defaults.getSchema() );
}
buildUniqueConstraints( annotation, element );
+ buildIndex( annotation, element );
annotation.setValue( "pkJoinColumns", buildPrimaryKeyJoinColumns( element ) );
secondaryTables.add( (SecondaryTable) AnnotationFactory.create( annotation ) );
}
@@ -2376,7 +2384,19 @@ public class JPAOverriddenAnnotationReader implements AnnotationReader {
}
}
}
-
+ private static void buildIndex(AnnotationDescriptor annotation, Element element){
+ List indexElementList = element.elements( "index" );
+ Index[] indexes = new Index[indexElementList.size()];
+ for(int i=0;i length) {
+ s = s.substring( 0, length );
+ }
+ return prefix + s;
+ }
}
diff --git a/hibernate-core/src/main/java/org/hibernate/internal/util/xml/BaseXMLEventReader.java b/hibernate-core/src/main/java/org/hibernate/internal/util/xml/BaseXMLEventReader.java
new file mode 100644
index 0000000000..e77971bf4b
--- /dev/null
+++ b/hibernate-core/src/main/java/org/hibernate/internal/util/xml/BaseXMLEventReader.java
@@ -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;
+ }
+}
diff --git a/hibernate-core/src/main/java/org/hibernate/internal/util/xml/BufferedXMLEventReader.java b/hibernate-core/src/main/java/org/hibernate/internal/util/xml/BufferedXMLEventReader.java
new file mode 100644
index 0000000000..529143c27f
--- /dev/null
+++ b/hibernate-core/src/main/java/org/hibernate/internal/util/xml/BufferedXMLEventReader.java
@@ -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 eventBuffer = new LinkedList();
+ private int eventLimit = 0;
+ private ListIterator 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 getBuffer() {
+ return new ArrayList(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();
+ }
+}
diff --git a/hibernate-core/src/main/java/org/hibernate/internal/util/xml/ErrorLogger.java b/hibernate-core/src/main/java/org/hibernate/internal/util/xml/ErrorLogger.java
index acbb0762a2..fceacce7f6 100644
--- a/hibernate-core/src/main/java/org/hibernate/internal/util/xml/ErrorLogger.java
+++ b/hibernate-core/src/main/java/org/hibernate/internal/util/xml/ErrorLogger.java
@@ -58,9 +58,7 @@ public class ErrorLogger implements ErrorHandler, Serializable {
this.file = file;
}
- /**
- * {@inheritDoc}
- */
+ @Override
public void error(SAXParseException error) {
if ( this.errors == null ) {
errors = new ArrayList();
@@ -68,23 +66,16 @@ public class ErrorLogger implements ErrorHandler, Serializable {
errors.add( error );
}
- /**
- * {@inheritDoc}
- */
+ @Override
public void fatalError(SAXParseException error) {
error( error );
}
- /**
- * {@inheritDoc}
- */
+ @Override
public void warning(SAXParseException warn) {
LOG.parsingXmlWarning( warn.getLineNumber(), warn.getMessage() );
}
- /**
- * @return returns a list of encountered xml parsing errors, or the empty list if there was no error
- */
public List getErrors() {
return errors;
}
diff --git a/hibernate-core/src/main/java/org/hibernate/internal/util/xml/FilteringXMLEventReader.java b/hibernate-core/src/main/java/org/hibernate/internal/util/xml/FilteringXMLEventReader.java
new file mode 100644
index 0000000000..5d115f31dd
--- /dev/null
+++ b/hibernate-core/src/main/java/org/hibernate/internal/util/xml/FilteringXMLEventReader.java
@@ -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 prunedElements = new LinkedList();
+ 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);
+}
diff --git a/hibernate-core/src/main/java/org/hibernate/internal/util/xml/LocalXmlResourceResolver.java b/hibernate-core/src/main/java/org/hibernate/internal/util/xml/LocalXmlResourceResolver.java
new file mode 100644
index 0000000000..a442963248
--- /dev/null
+++ b/hibernate-core/src/main/java/org/hibernate/internal/util/xml/LocalXmlResourceResolver.java
@@ -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;
+ }
+ }
+}
diff --git a/hibernate-core/src/main/java/org/hibernate/internal/util/xml/MappingReader.java b/hibernate-core/src/main/java/org/hibernate/internal/util/xml/MappingReader.java
index d40e2b3eb4..0331c9e271 100644
--- a/hibernate-core/src/main/java/org/hibernate/internal/util/xml/MappingReader.java
+++ b/hibernate-core/src/main/java/org/hibernate/internal/util/xml/MappingReader.java
@@ -23,17 +23,36 @@
*/
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.jboss.logging.Logger;
+import org.dom4j.io.STAXEventReader;
import org.xml.sax.EntityResolver;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
+import org.jboss.logging.Logger;
+
import org.hibernate.InvalidMappingException;
import org.hibernate.internal.CoreMessageLogger;
+import org.hibernate.jaxb.spi.Origin;
/**
* Handles reading mapping documents, both {@code hbm} and {@code orm} varieties.
@@ -41,7 +60,6 @@ import org.hibernate.internal.CoreMessageLogger;
* @author Steve Ebersole
*/
public class MappingReader {
-
private static final CoreMessageLogger LOG = Logger.getMessageLogger(
CoreMessageLogger.class,
MappingReader.class.getName()
@@ -59,10 +77,241 @@ 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 );
+ }
+ }
+
+ public static 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" ),
+ HBM_4_0( "org/hibernate/hibernate-mapping-4.0.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;
+
ErrorLogger errorHandler = new ErrorLogger();
SAXReader saxReader = new SAXReader();
@@ -73,193 +322,81 @@ public class MappingReader {
Document document = null;
try {
- // first try with orm 2.0 xsd validation
- setValidationFor( saxReader, "orm_2_0.xsd" );
+ // first try with orm 2.1 xsd validation
+ setValidationFor( saxReader, "orm_2_1.xsd" );
document = saxReader.read( source );
if ( errorHandler.hasErrors() ) {
throw errorHandler.getErrors().get( 0 );
}
- return new XmlDocumentImpl( document, origin.getType(), origin.getName() );
+ return new XmlDocumentImpl( document, origin );
}
- catch ( Exception orm2Problem ) {
+ catch ( Exception e ) {
if ( LOG.isDebugEnabled() ) {
- LOG.debugf( "Problem parsing XML using orm 2 xsd : %s", orm2Problem.getMessage() );
+ LOG.debugf( "Problem parsing XML using orm 2.1 xsd, trying 2.0 xsd : %s", e.getMessage() );
}
- failure = orm2Problem;
+ failure = e;
errorHandler.reset();
if ( document != null ) {
- // next try with orm 1.0 xsd validation
+ // next try with orm 2.0 xsd validation
try {
- setValidationFor( saxReader, "orm_1_0.xsd" );
+ setValidationFor( saxReader, "orm_2_0.xsd" );
document = saxReader.read( new StringReader( document.asXML() ) );
if ( errorHandler.hasErrors() ) {
errorHandler.logErrors();
throw errorHandler.getErrors().get( 0 );
}
- return new XmlDocumentImpl( document, origin.getType(), origin.getName() );
+ return new XmlDocumentImpl( document, origin );
}
- catch ( Exception orm1Problem ) {
+ catch ( Exception e2 ) {
if ( LOG.isDebugEnabled() ) {
- LOG.debugf( "Problem parsing XML using orm 1 xsd : %s", orm1Problem.getMessage() );
+ LOG.debugf( "Problem parsing XML using orm 2.0 xsd, trying 1.0 xsd : %s", e2.getMessage() );
+ }
+ errorHandler.reset();
+
+ if ( document != null ) {
+ // next try with orm 1.0 xsd validation
+ try {
+ setValidationFor( saxReader, "orm_1_0.xsd" );
+ document = saxReader.read( new StringReader( document.asXML() ) );
+ if ( errorHandler.hasErrors() ) {
+ errorHandler.logErrors();
+ throw errorHandler.getErrors().get( 0 );
+ }
+ return new XmlDocumentImpl( document, origin );
+ }
+ catch ( Exception e3 ) {
+ if ( LOG.isDebugEnabled() ) {
+ LOG.debugf( "Problem parsing XML using orm 1.0 xsd : %s", e3.getMessage() );
+ }
+ }
}
}
}
}
- throw new InvalidMappingException( "Unable to read XML", origin.getType(), origin.getName(), failure );
+ throw new InvalidMappingException( "Unable to read XML", origin, failure );
}
private void setValidationFor(SAXReader saxReader, String xsd) {
try {
saxReader.setFeature( "http://apache.org/xml/features/validation/schema", true );
- //saxReader.setFeature( "http://apache.org/xml/features/validation/dynamic", true );
- //set the default schema locators
- saxReader.setProperty(
- "http://apache.org/xml/properties/schema/external-schemaLocation",
- "http://java.sun.com/xml/ns/persistence/orm " + xsd
- );
+ // saxReader.setFeature( "http://apache.org/xml/features/validation/dynamic", true );
+ if ( "orm_2_1.xsd".equals( xsd ) ) {
+ saxReader.setProperty(
+ "http://apache.org/xml/properties/schema/external-schemaLocation",
+ LocalXmlResourceResolver.SECOND_JPA_ORM_NS + " " + xsd
+ );
+ }
+ else {
+ saxReader.setProperty(
+ "http://apache.org/xml/properties/schema/external-schemaLocation",
+ LocalXmlResourceResolver.INITIAL_JPA_ORM_NS + " " + xsd
+ );
+ }
}
catch ( SAXException e ) {
saxReader.setValidation( false );
}
}
- // this is the version of the code I'd like to use, but it unfortunately works very differently between
- // JDK 1.5 ad JDK 1.6. On 1.5 the vaildation "passes" even with invalid content.
- //
- // Options:
- // 1) continue using the code above
- // 2) Document the issue on 1.5 and how to fix (specifying alternate SchemaFactory instance)
- // 3) Use a specific JAXP library (Xerces2, Saxon, Jing, MSV) and its SchemaFactory instance directly
-
-// public XmlDocument readMappingDocument(EntityResolver entityResolver, InputSource source, Origin origin) {
-// ErrorLogger errorHandler = new ErrorLogger();
-//
-// SAXReader saxReader = new SAXReader( new DOMDocumentFactory() );
-// saxReader.setEntityResolver( entityResolver );
-// saxReader.setErrorHandler( errorHandler );
-// saxReader.setMergeAdjacentText( true );
-//
-// Document documentTree = null;
-//
-// // IMPL NOTE : here we enable DTD validation in case the mapping is a HBM file. This will validate
-// // the document as it is parsed. This is needed because the DTD defines default values that have to be
-// // applied as the document is parsed, so thats something we need to account for as we (if we) transition
-// // to XSD.
-// saxReader.setValidation( true );
-// try {
-// documentTree = saxReader.read( source );
-// }
-// catch ( DocumentException e ) {
-// // we had issues reading the input, most likely malformed document or validation error against DTD
-// throw new InvalidMappingException( "Unable to read XML", origin.getType(), origin.getName(), e );
-// }
-//
-// Element rootElement = documentTree.getRootElement();
-// if ( rootElement == null ) {
-// throw new InvalidMappingException( "No root element", origin.getType(), origin.getName() );
-// }
-//
-// if ( "entity-mappings".equals( rootElement.getName() ) ) {
-// final String explicitVersion = rootElement.attributeValue( "version" );
-// final String xsdVersionString = explicitVersion == null ? ASSUMED_ORM_XSD_VERSION : explicitVersion;
-// final SupportedOrmXsdVersion xsdVersion = SupportedOrmXsdVersion.parse( xsdVersionString );
-// final Schema schema = xsdVersion == SupportedOrmXsdVersion.ORM_1_0 ? orm1Schema() : orm2Schema();
-// try {
-// schema.newValidator().validate( new DOMSource( (org.w3c.dom.Document) documentTree ) );
-// }
-// catch ( SAXException e ) {
-// throw new InvalidMappingException( "Validation problem", origin.getType(), origin.getName(), e );
-// }
-// catch ( IOException e ) {
-// throw new InvalidMappingException( "Validation problem", origin.getType(), origin.getName(), e );
-// }
-// }
-// else {
-// if ( errorHandler.getError() != null ) {
-// throw new InvalidMappingException(
-// "Error validating hibernate-mapping against DTD",
-// origin.getType(),
-// origin.getName(),
-// errorHandler.getError()
-// );
-// }
-// }
-//
-// return new XmlDocumentImpl( documentTree, origin );
-// }
-//
-// public static enum SupportedOrmXsdVersion {
-// ORM_1_0,
-// ORM_2_0;
-//
-// public static SupportedOrmXsdVersion parse(String name) {
-// if ( "1.0".equals( name ) ) {
-// return ORM_1_0;
-// }
-// else if ( "2.0".equals( name ) ) {
-// return ORM_2_0;
-// }
-// throw new IllegalArgumentException( "Unsupported orm.xml XSD version encountered [" + name + "]" );
-// }
-// }
-//
-//
-// public static final String ORM_1_SCHEMA_NAME = "org/hibernate/ejb/orm_1_0.xsd";
-// public static final String ORM_2_SCHEMA_NAME = "org/hibernate/ejb/orm_2_0.xsd";
-//
-// private static Schema orm1Schema;
-//
-// private static Schema orm1Schema() {
-// if ( orm1Schema == null ) {
-// orm1Schema = resolveLocalSchema( ORM_1_SCHEMA_NAME );
-// }
-// return orm1Schema;
-// }
-//
-// private static Schema orm2Schema;
-//
-// private static Schema orm2Schema() {
-// if ( orm2Schema == null ) {
-// orm2Schema = resolveLocalSchema( ORM_2_SCHEMA_NAME );
-// }
-// return orm2Schema;
-// }
-//
-// private static Schema resolveLocalSchema(String schemaName) {
-// return resolveLocalSchema( schemaName, XMLConstants.W3C_XML_SCHEMA_NS_URI );
-// }
-//
-// private static Schema resolveLocalSchema(String schemaName, String schemaLanguage) {
-// URL url = ConfigHelper.findAsResource( schemaName );
-// if ( url == null ) {
-// throw new MappingException( "Unable to locate schema [" + schemaName + "] via classpath" );
-// }
-// try {
-// InputStream schemaStream = url.openStream();
-// try {
-// StreamSource source = new StreamSource(url.openStream());
-// SchemaFactory schemaFactory = SchemaFactory.newInstance( schemaLanguage );
-// return schemaFactory.newSchema(source);
-// }
-// catch ( SAXException e ) {
-// throw new MappingException( "Unable to load schema [" + schemaName + "]", e );
-// }
-// catch ( IOException e ) {
-// throw new MappingException( "Unable to load schema [" + schemaName + "]", e );
-// }
-// finally {
-// try {
-// schemaStream.close();
-// }
-// catch ( IOException e ) {
-// log.warn( "Problem closing schema stream [{}]", e.toString() );
-// }
-// }
-// }
-// catch ( IOException e ) {
-// throw new MappingException( "Stream error handling schema url [" + url.toExternalForm() + "]" );
-// }
-//
-// }
}
diff --git a/hibernate-core/src/main/java/org/hibernate/internal/util/xml/UnsupportedOrmXsdVersionException.java b/hibernate-core/src/main/java/org/hibernate/internal/util/xml/UnsupportedOrmXsdVersionException.java
new file mode 100644
index 0000000000..dcdd80b6d6
--- /dev/null
+++ b/hibernate-core/src/main/java/org/hibernate/internal/util/xml/UnsupportedOrmXsdVersionException.java
@@ -0,0 +1,43 @@
+/*
+ * 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;
+import org.hibernate.jaxb.spi.Origin;
+
+/**
+ * @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()
+ )
+ );
+ }
+}
diff --git a/hibernate-core/src/main/java/org/hibernate/internal/util/xml/XMLStreamConstantsUtils.java b/hibernate-core/src/main/java/org/hibernate/internal/util/xml/XMLStreamConstantsUtils.java
new file mode 100644
index 0000000000..b79250f109
--- /dev/null
+++ b/hibernate-core/src/main/java/org/hibernate/internal/util/xml/XMLStreamConstantsUtils.java
@@ -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";
+ }
+}
diff --git a/hibernate-core/src/main/java/org/hibernate/internal/util/xml/XmlDocument.java b/hibernate-core/src/main/java/org/hibernate/internal/util/xml/XmlDocument.java
index 0822a9f6aa..3e6a1ff902 100644
--- a/hibernate-core/src/main/java/org/hibernate/internal/util/xml/XmlDocument.java
+++ b/hibernate-core/src/main/java/org/hibernate/internal/util/xml/XmlDocument.java
@@ -27,6 +27,8 @@ import java.io.Serializable;
import org.dom4j.Document;
+import org.hibernate.jaxb.spi.Origin;
+
/**
* Describes a parsed xml document.
*
diff --git a/hibernate-core/src/main/java/org/hibernate/internal/util/xml/XmlDocumentImpl.java b/hibernate-core/src/main/java/org/hibernate/internal/util/xml/XmlDocumentImpl.java
index e936c92add..f63a7ee8aa 100644
--- a/hibernate-core/src/main/java/org/hibernate/internal/util/xml/XmlDocumentImpl.java
+++ b/hibernate-core/src/main/java/org/hibernate/internal/util/xml/XmlDocumentImpl.java
@@ -27,6 +27,9 @@ import java.io.Serializable;
import org.dom4j.Document;
+import org.hibernate.jaxb.spi.Origin;
+import org.hibernate.jaxb.spi.SourceType;
+
/**
* Basic implemementation of {@link XmlDocument}
*
@@ -36,8 +39,8 @@ public class XmlDocumentImpl implements XmlDocument, Serializable {
private final Document documentTree;
private final Origin origin;
- public XmlDocumentImpl(Document documentTree, String originType, String originName) {
- this( documentTree, new OriginImpl( originType, originName ) );
+ public XmlDocumentImpl(Document documentTree, SourceType originType, String originName) {
+ this( documentTree, new Origin( originType, originName ) );
}
public XmlDocumentImpl(Document documentTree, Origin origin) {
diff --git a/hibernate-core/src/main/java/org/hibernate/internal/util/xml/OriginImpl.java b/hibernate-core/src/main/java/org/hibernate/internal/util/xml/XmlInfrastructureException.java
similarity index 68%
rename from hibernate-core/src/main/java/org/hibernate/internal/util/xml/OriginImpl.java
rename to hibernate-core/src/main/java/org/hibernate/internal/util/xml/XmlInfrastructureException.java
index 8f58fcc095..b6a3c3040c 100644
--- a/hibernate-core/src/main/java/org/hibernate/internal/util/xml/OriginImpl.java
+++ b/hibernate-core/src/main/java/org/hibernate/internal/util/xml/XmlInfrastructureException.java
@@ -1,7 +1,7 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
- * Copyright (c) 2010, Red Hat Inc. or third-party contributors as
+ * 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.
@@ -23,33 +23,19 @@
*/
package org.hibernate.internal.util.xml;
-import java.io.Serializable;
+import org.hibernate.HibernateException;
/**
- * Basic implementation of {@link Origin}
+ * An error using XML infrastructure (jaxp, stax, etc).
*
* @author Steve Ebersole
*/
-public class OriginImpl implements Origin, Serializable {
- private final String type;
- private final String name;
-
- public OriginImpl(String type, String name) {
- this.type = type;
- this.name = name;
+public class XmlInfrastructureException extends HibernateException {
+ public XmlInfrastructureException(String message) {
+ super( message );
}
- /**
- * {@inheritDoc}
- */
- public String getType() {
- return type;
- }
-
- /**
- * {@inheritDoc}
- */
- public String getName() {
- return name;
+ public XmlInfrastructureException(String message, Throwable root) {
+ super( message, root );
}
}
diff --git a/hibernate-core/src/main/java/org/hibernate/jaxb/internal/JaxbMappingProcessor.java b/hibernate-core/src/main/java/org/hibernate/jaxb/internal/JaxbMappingProcessor.java
index 56720bee25..d13d3e078a 100644
--- a/hibernate-core/src/main/java/org/hibernate/jaxb/internal/JaxbMappingProcessor.java
+++ b/hibernate-core/src/main/java/org/hibernate/jaxb/internal/JaxbMappingProcessor.java
@@ -41,16 +41,22 @@ import javax.xml.stream.events.Attribute;
import javax.xml.stream.events.StartElement;
import javax.xml.stream.events.XMLEvent;
import javax.xml.transform.dom.DOMSource;
+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 org.jboss.logging.Logger;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.xml.sax.SAXException;
+import org.hibernate.InvalidMappingException;
import org.hibernate.boot.registry.classloading.spi.ClassLoaderService;
+import org.hibernate.internal.util.StringHelper;
+import org.hibernate.internal.util.xml.LocalXmlResourceResolver;
+import org.hibernate.internal.util.xml.MappingReader;
import org.hibernate.jaxb.spi.JaxbRoot;
import org.hibernate.jaxb.spi.Origin;
import org.hibernate.jaxb.spi.hbm.JaxbHibernateMapping;
@@ -68,7 +74,7 @@ import org.hibernate.service.ServiceRegistry;
public class JaxbMappingProcessor {
private static final Logger log = Logger.getLogger( JaxbMappingProcessor.class );
- public static final String ASSUMED_ORM_XSD_VERSION = "2.0";
+ public static final String ASSUMED_ORM_XSD_VERSION = "2.1";
public static final String VALIDATE_XML_SETTING = "hibernate.xml.validate";
public static final String HIBERNATE_MAPPING_URI = "http://www.hibernate.org/xsd/hibernate-mapping";
@@ -123,6 +129,7 @@ public class JaxbMappingProcessor {
@SuppressWarnings( { "UnnecessaryLocalVariable" })
private XMLInputFactory buildStaxFactory() {
XMLInputFactory staxFactory = XMLInputFactory.newInstance();
+ staxFactory.setXMLResolver( LocalXmlResourceResolver.INSTANCE );
return staxFactory;
}
@@ -154,7 +161,23 @@ public class JaxbMappingProcessor {
if ( "entity-mappings".equals( elementName ) ) {
final Attribute attribute = event.asStartElement().getAttributeByName( ORM_VERSION_ATTRIBUTE_QNAME );
final String explicitVersion = attribute == null ? null : attribute.getValue();
- validationSchema = validateXml ? resolveSupportedOrmXsd( explicitVersion ) : null;
+ if ( !"2.1".equals( explicitVersion ) ) {
+ if ( validateXml ) {
+ MappingReader.validateMapping(
+ MappingReader.SupportedOrmXsdVersion.parse( explicitVersion, origin ),
+ staxEventReader,
+ origin
+ );
+ }
+ staxEventReader = new LegacyJPAEventReader(
+ staxEventReader,
+ LocalXmlResourceResolver.SECOND_JPA_ORM_NS
+ );
+ validationSchema = null; //disable JAXB validation
+ }
+ else {
+ validationSchema = validateXml ? resolveSupportedOrmXsd( explicitVersion, origin ) : null;
+ }
jaxbTarget = JaxbEntityMappings.class;
}
else {
@@ -163,7 +186,7 @@ public class JaxbMappingProcessor {
log.debug( "HBM mapping document did not define namespaces; wrapping in custom event reader to introduce namespace information" );
staxEventReader = new NamespaceAddingEventReader( staxEventReader, HIBERNATE_MAPPING_URI );
}
- validationSchema = validateXml ? hbmSchema() : null;
+ validationSchema = validateXml ? MappingReader.SupportedOrmXsdVersion.HBM_4_0.getSchema() : null;
jaxbTarget = JaxbHibernateMapping.class;
}
@@ -177,6 +200,7 @@ public class JaxbMappingProcessor {
target = unmarshaller.unmarshal( staxEventReader );
}
catch ( JAXBException e ) {
+ e.printStackTrace();
StringBuilder builder = new StringBuilder();
builder.append( "Unable to perform unmarshalling at line number " );
builder.append( handler.getLineNumber() );
@@ -190,6 +214,7 @@ public class JaxbMappingProcessor {
return new JaxbRoot( target, origin );
}
+
private boolean isNamespaced(StartElement startElement) {
return ! "".equals( startElement.getName().getNamespaceURI() );
}
@@ -206,7 +231,7 @@ public class JaxbMappingProcessor {
if ( "entity-mappings".equals( rootElement.getNodeName() ) ) {
final String explicitVersion = rootElement.getAttribute( "version" );
- validationSchema = validateXml ? resolveSupportedOrmXsd( explicitVersion ) : null;
+ validationSchema = validateXml ? resolveSupportedOrmXsd( explicitVersion, origin ) : null;
jaxbTarget = JaxbEntityMappings.class;
}
else {
@@ -228,20 +253,14 @@ public class JaxbMappingProcessor {
return new JaxbRoot( target, origin );
}
- private Schema resolveSupportedOrmXsd(String explicitVersion) {
- final String xsdVersionString = explicitVersion == null ? ASSUMED_ORM_XSD_VERSION : explicitVersion;
- if ( "1.0".equals( xsdVersionString ) ) {
- return orm1Schema();
+ private Schema resolveSupportedOrmXsd(String explicitVersion, Origin origin) {
+ if( StringHelper.isEmpty(explicitVersion)){
+ return MappingReader.SupportedOrmXsdVersion.ORM_2_1.getSchema();
}
- else if ( "2.0".equals( xsdVersionString ) ) {
- return orm2Schema();
- }
- throw new IllegalArgumentException( "Unsupported orm.xml XSD version encountered [" + xsdVersionString + "]" );
+ return MappingReader.SupportedOrmXsdVersion.parse( explicitVersion, origin ).getSchema();
}
public static final String HBM_SCHEMA_NAME = "org/hibernate/hibernate-mapping-4.0.xsd";
- public static final String ORM_1_SCHEMA_NAME = "org/hibernate/ejb/orm_1_0.xsd";
- public static final String ORM_2_SCHEMA_NAME = "org/hibernate/ejb/orm_2_0.xsd";
private Schema hbmSchema;
@@ -252,23 +271,6 @@ public class JaxbMappingProcessor {
return hbmSchema;
}
- private Schema orm1Schema;
-
- private Schema orm1Schema() {
- if ( orm1Schema == null ) {
- orm1Schema = resolveLocalSchema( ORM_1_SCHEMA_NAME );
- }
- return orm1Schema;
- }
-
- private Schema orm2Schema;
-
- private Schema orm2Schema() {
- if ( orm2Schema == null ) {
- orm2Schema = resolveLocalSchema( ORM_2_SCHEMA_NAME );
- }
- return orm2Schema;
- }
private Schema resolveLocalSchema(String schemaName) {
return resolveLocalSchema( schemaName, XMLConstants.W3C_XML_SCHEMA_NS_URI );
diff --git a/hibernate-core/src/main/java/org/hibernate/jaxb/internal/LegacyJPAEventReader.java b/hibernate-core/src/main/java/org/hibernate/jaxb/internal/LegacyJPAEventReader.java
new file mode 100644
index 0000000000..2678e9add6
--- /dev/null
+++ b/hibernate-core/src/main/java/org/hibernate/jaxb/internal/LegacyJPAEventReader.java
@@ -0,0 +1,89 @@
+package org.hibernate.jaxb.internal;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import javax.xml.namespace.QName;
+import javax.xml.stream.XMLEventFactory;
+import javax.xml.stream.XMLEventReader;
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.events.Attribute;
+import javax.xml.stream.events.Namespace;
+import javax.xml.stream.events.StartElement;
+import javax.xml.stream.events.XMLEvent;
+import javax.xml.stream.util.EventReaderDelegate;
+
+import org.hibernate.internal.util.xml.LocalXmlResourceResolver;
+
+/**
+ * @author Strong Liu
+ */
+public class LegacyJPAEventReader extends EventReaderDelegate {
+ private final XMLEventFactory xmlEventFactory;
+ private final String namespaceUri;
+
+ public LegacyJPAEventReader(XMLEventReader reader, String namespaceUri) {
+ this( reader, XMLEventFactory.newInstance(), namespaceUri );
+ }
+
+ public LegacyJPAEventReader(XMLEventReader reader, XMLEventFactory xmlEventFactory, String namespaceUri) {
+ super( reader );
+ this.xmlEventFactory = xmlEventFactory;
+ this.namespaceUri = namespaceUri;
+ }
+
+ private StartElement withNamespace(StartElement startElement) {
+ // otherwise, wrap the start element event to provide a default namespace mapping
+ final List namespaces = new ArrayList();
+ namespaces.add( xmlEventFactory.createNamespace( "", namespaceUri ) );
+ Iterator> originalNamespaces = startElement.getNamespaces();
+ while ( originalNamespaces.hasNext() ) {
+ Namespace ns = (Namespace) originalNamespaces.next();
+ if ( !LocalXmlResourceResolver.INITIAL_JPA_ORM_NS.equals( ns.getNamespaceURI() ) ) {
+ namespaces.add( ns );
+ }
+ }
+ Iterator> attributes;
+ if ( "entity-mappings".equals( startElement.getName().getLocalPart() ) ) {
+ List st = new ArrayList();
+ Iterator itr = startElement.getAttributes();
+ while ( itr.hasNext() ) {
+ Attribute obj = (Attribute) itr.next();
+ if ( "version".equals( obj.getName().getLocalPart() ) ) {
+ if ( "".equals( obj.getName().getPrefix() ) ) {
+ st.add( xmlEventFactory.createAttribute( obj.getName(), "2.1" ) );
+ }
+ }
+ else {
+ st.add( obj );
+ }
+ }
+ attributes = st.iterator();
+ } else {
+ attributes = startElement.getAttributes();
+ }
+
+ return xmlEventFactory.createStartElement(
+ new QName( namespaceUri, startElement.getName().getLocalPart() ),
+ attributes,
+ namespaces.iterator()
+ );
+ }
+
+ @Override
+ public XMLEvent nextEvent() throws XMLStreamException {
+ return wrap( super.nextEvent() );
+ }
+
+ private XMLEvent wrap(XMLEvent event) {
+ if ( event.isStartElement() ) {
+ return withNamespace( event.asStartElement() );
+ }
+ return event;
+ }
+
+ @Override
+ public XMLEvent peek() throws XMLStreamException {
+ return wrap( super.peek() );
+ }
+}
diff --git a/hibernate-core/src/main/java/org/hibernate/jaxb/internal/NamespaceAddingEventReader.java b/hibernate-core/src/main/java/org/hibernate/jaxb/internal/NamespaceAddingEventReader.java
index 3407379c98..eb21651478 100644
--- a/hibernate-core/src/main/java/org/hibernate/jaxb/internal/NamespaceAddingEventReader.java
+++ b/hibernate-core/src/main/java/org/hibernate/jaxb/internal/NamespaceAddingEventReader.java
@@ -35,6 +35,8 @@ import javax.xml.stream.events.StartElement;
import javax.xml.stream.events.XMLEvent;
import javax.xml.stream.util.EventReaderDelegate;
+import org.hibernate.internal.util.xml.LocalXmlResourceResolver;
+
/**
* Used to wrap a StAX {@link XMLEventReader} in order to introduce namespaces into the underlying document. This
* is intended for temporary migration feature to allow legacy HBM mapping documents (DTD-based) to continue to
@@ -62,7 +64,10 @@ public class NamespaceAddingEventReader extends EventReaderDelegate {
namespaces.add( xmlEventFactory.createNamespace( "", namespaceUri ) );
Iterator> originalNamespaces = startElement.getNamespaces();
while ( originalNamespaces.hasNext() ) {
- namespaces.add( (Namespace) originalNamespaces.next() );
+ Namespace ns = (Namespace) originalNamespaces.next();
+ if ( !LocalXmlResourceResolver.INITIAL_JPA_ORM_NS.equals( ns.getNamespaceURI() ) ) {
+ namespaces.add( ns );
+ }
}
return xmlEventFactory.createStartElement(
new QName( namespaceUri, startElement.getName().getLocalPart() ),
@@ -73,7 +78,10 @@ public class NamespaceAddingEventReader extends EventReaderDelegate {
@Override
public XMLEvent nextEvent() throws XMLStreamException {
- XMLEvent event = super.nextEvent();
+ return wrap( super.nextEvent() );
+ }
+
+ private XMLEvent wrap(XMLEvent event) {
if ( event.isStartElement() ) {
return withNamespace( event.asStartElement() );
}
@@ -82,12 +90,6 @@ public class NamespaceAddingEventReader extends EventReaderDelegate {
@Override
public XMLEvent peek() throws XMLStreamException {
- XMLEvent event = super.peek();
- if ( event.isStartElement() ) {
- return withNamespace( event.asStartElement() );
- }
- else {
- return event;
- }
+ return wrap( super.peek() );
}
}
diff --git a/hibernate-core/src/main/java/org/hibernate/mapping/Collection.java b/hibernate-core/src/main/java/org/hibernate/mapping/Collection.java
index dcc56e732d..7e496c34ef 100644
--- a/hibernate-core/src/main/java/org/hibernate/mapping/Collection.java
+++ b/hibernate-core/src/main/java/org/hibernate/mapping/Collection.java
@@ -212,7 +212,7 @@ public abstract class Collection implements Fetchable, Value, Filterable {
}
public void setRole(String role) {
- this.role = role==null ? null : role.intern();
+ this.role = role;
}
public void setSorted(boolean sorted) {
@@ -549,7 +549,7 @@ public abstract class Collection implements Fetchable, Value, Filterable {
}
public void setLoaderName(String name) {
- this.loaderName = name==null ? null : name.intern();
+ this.loaderName = name;
}
public String getReferencedPropertyName() {
@@ -557,7 +557,7 @@ public abstract class Collection implements Fetchable, Value, Filterable {
}
public void setReferencedPropertyName(String propertyRef) {
- this.referencedPropertyName = propertyRef==null ? null : propertyRef.intern();
+ this.referencedPropertyName = propertyRef;
}
public boolean isOptimisticLocked() {
diff --git a/hibernate-core/src/main/java/org/hibernate/mapping/Table.java b/hibernate-core/src/main/java/org/hibernate/mapping/Table.java
index ee638cde90..a032d22029 100644
--- a/hibernate-core/src/main/java/org/hibernate/mapping/Table.java
+++ b/hibernate-core/src/main/java/org/hibernate/mapping/Table.java
@@ -36,6 +36,7 @@ import org.hibernate.HibernateException;
import org.hibernate.MappingException;
import org.hibernate.dialect.Dialect;
import org.hibernate.engine.spi.Mapping;
+import org.hibernate.internal.util.StringHelper;
import org.hibernate.tool.hbm2ddl.ColumnMetadata;
import org.hibernate.tool.hbm2ddl.TableMetadata;
@@ -395,8 +396,6 @@ public class Table implements RelationalModel, Serializable {
Iterator iter = getColumnIterator();
List results = new ArrayList();
- int uniqueIndexInteger = 0;
-
while ( iter.hasNext() ) {
Column column = (Column) iter.next();
@@ -423,9 +422,8 @@ public class Table implements RelationalModel, Serializable {
}
if ( column.isUnique() ) {
- uniqueIndexInteger++;
UniqueKey uk = getOrCreateUniqueKey(
- "UK_" + name + "_" + uniqueIndexInteger);
+ StringHelper.randomFixedLengthHex("UK_"));
uk.addColumn( column );
alter.append( dialect.getUniqueDelegate()
.applyUniqueToColumn( column ) );
@@ -494,7 +492,6 @@ public class Table implements RelationalModel, Serializable {
}
Iterator iter = getColumnIterator();
- int uniqueIndexInteger = 0;
while ( iter.hasNext() ) {
Column col = (Column) iter.next();
@@ -528,9 +525,8 @@ public class Table implements RelationalModel, Serializable {
}
if ( col.isUnique() ) {
- uniqueIndexInteger++;
UniqueKey uk = getOrCreateUniqueKey(
- "uc_" + name + "_" + uniqueIndexInteger);
+ StringHelper.randomFixedLengthHex("UK_"));
uk.addColumn( col );
buf.append( dialect.getUniqueDelegate()
.applyUniqueToColumn( col ) );
@@ -653,7 +649,7 @@ public class Table implements RelationalModel, Serializable {
}
public UniqueKey createUniqueKey(List keyColumns) {
- String keyName = "UK_" + uniqueColumnString( keyColumns.iterator() );
+ String keyName = StringHelper.randomFixedLengthHex("UK_");
UniqueKey uk = getOrCreateUniqueKey( keyName );
uk.addColumns( keyColumns.iterator() );
return uk;
@@ -693,9 +689,7 @@ public class Table implements RelationalModel, Serializable {
fk.setName( keyName );
}
else {
- fk.setName( "FK" + uniqueColumnString( keyColumns.iterator(), referencedEntityName ) );
- //TODO: add referencedClass to disambiguate to FKs on the same
- // columns, pointing to different tables
+ fk.setName( StringHelper.randomFixedLengthHex("FK_") );
}
fk.setTable( this );
foreignKeys.put( key, fk );
@@ -714,22 +708,6 @@ public class Table implements RelationalModel, Serializable {
}
- public String uniqueColumnString(Iterator iterator) {
- return uniqueColumnString( iterator, null );
- }
-
- public String uniqueColumnString(Iterator iterator, String referencedEntityName) {
- int result = 0;
- if ( referencedEntityName != null ) {
- result += referencedEntityName.hashCode();
- }
- while ( iterator.hasNext() ) {
- result += iterator.next().hashCode();
- }
- return ( Integer.toHexString( name.hashCode() ) + Integer.toHexString( result ) ).toUpperCase();
- }
-
-
public String getSchema() {
return schema;
diff --git a/hibernate-core/src/main/resources/org/hibernate/ejb/orm_1_0.xsd b/hibernate-core/src/main/resources/org/hibernate/jpa/orm_1_0.xsd
similarity index 97%
rename from hibernate-core/src/main/resources/org/hibernate/ejb/orm_1_0.xsd
rename to hibernate-core/src/main/resources/org/hibernate/jpa/orm_1_0.xsd
index c21e996c4a..55d3517623 100644
--- a/hibernate-core/src/main/resources/org/hibernate/ejb/orm_1_0.xsd
+++ b/hibernate-core/src/main/resources/org/hibernate/jpa/orm_1_0.xsd
@@ -1,1540 +1,1540 @@
-
-
-
-
-
-
-
-
- @(#)orm_1_0.xsd 1.0 Feb 14 2006
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- The entity-mappings element is the root element of an mapping
- file. It contains the following four types of elements:
-
- 1. The persistence-unit-metadata element contains metadata
- for the entire persistence unit. It is undefined if this element
- occurs in multiple mapping files within the same persistence unit.
-
- 2. The package, schema, catalog and access elements apply to all of
- the entity, mapped-superclass and embeddable elements defined in
- the same file in which they occur.
-
- 3. The sequence-generator, table-generator, named-query,
- named-native-query and sql-result-set-mapping elements are global
- to the persistence unit. It is undefined to have more than one
- sequence-generator or table-generator of the same name in the same
- or different mapping files in a persistence unit. It is also
- undefined to have more than one named-query or named-native-query
- of the same name in the same or different mapping files in a
- persistence unit.
-
- 4. The entity, mapped-superclass and embeddable elements each define
- the mapping information for a managed persistent class. The mapping
- information contained in these elements may be complete or it may
- be partial.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Metadata that applies to the persistence unit and not just to
- the mapping file in which it is contained.
-
- If the xml-mapping-metadata-complete element is specified then
- the complete set of mapping metadata for the persistence unit
- is contained in the XML mapping files for the persistence unit.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- These defaults are applied to the persistence unit as a whole
- unless they are overridden by local annotation or XML
- element settings.
-
- schema - Used as the schema for all tables or secondary tables
- that apply to the persistence unit
- catalog - Used as the catalog for all tables or secondary tables
- that apply to the persistence unit
- access - Used as the access type for all managed classes in
- the persistence unit
- cascade-persist - Adds cascade-persist to the set of cascade options
- in entity relationships of the persistence unit
- entity-listeners - List of default entity listeners to be invoked
- on each entity in the persistence unit.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Defines the settings and mappings for an entity. Is allowed to be
- sparsely populated and used in conjunction with the annotations.
- Alternatively, the metadata-complete attribute can be used to
- indicate that no annotations on the entity class (and its fields
- or properties) are to be processed. If this is the case then
- the defaulting rules for the entity and its subelements will
- be recursively applied.
-
- @Target(TYPE) @Retention(RUNTIME)
- public @interface Entity {
- String name() default "";
- }
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- This element contains the entity field or property mappings.
- It may be sparsely populated to include only a subset of the
- fields or properties. If metadata-complete for the entity is true
- then the remainder of the attributes will be defaulted according
- to the default rules.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- This element determines how the persistence provider accesses the
- state of an entity or embedded object.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- @Target({TYPE}) @Retention(RUNTIME)
- public @interface EntityListeners {
- Class[] value();
- }
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Defines an entity listener to be invoked at lifecycle events
- for the entities that list this listener.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- @Target({METHOD}) @Retention(RUNTIME)
- public @interface PrePersist {}
-
-
-
-
-
-
-
-
-
-
-
-
- @Target({METHOD}) @Retention(RUNTIME)
- public @interface PostPersist {}
-
-
-
-
-
-
-
-
-
-
-
-
- @Target({METHOD}) @Retention(RUNTIME)
- public @interface PreRemove {}
-
-
-
-
-
-
-
-
-
-
-
-
- @Target({METHOD}) @Retention(RUNTIME)
- public @interface PostRemove {}
-
-
-
-
-
-
-
-
-
-
-
-
- @Target({METHOD}) @Retention(RUNTIME)
- public @interface PreUpdate {}
-
-
-
-
-
-
-
-
-
-
-
-
- @Target({METHOD}) @Retention(RUNTIME)
- public @interface PostUpdate {}
-
-
-
-
-
-
-
-
-
-
-
-
- @Target({METHOD}) @Retention(RUNTIME)
- public @interface PostLoad {}
-
-
-
-
-
-
-
-
-
-
-
-
- @Target({}) @Retention(RUNTIME)
- public @interface QueryHint {
- String name();
- String value();
- }
-
-
-
-
-
-
-
-
-
-
-
-
-
- @Target({TYPE}) @Retention(RUNTIME)
- public @interface NamedQuery {
- String name();
- String query();
- QueryHint[] hints() default {};
- }
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- @Target({TYPE}) @Retention(RUNTIME)
- public @interface NamedNativeQuery {
- String name();
- String query();
- QueryHint[] hints() default {};
- Class resultClass() default void.class;
- String resultSetMapping() default ""; //named SqlResultSetMapping
- }
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- @Target({TYPE}) @Retention(RUNTIME)
- public @interface SqlResultSetMapping {
- String name();
- EntityResult[] entities() default {};
- ColumnResult[] columns() default {};
- }
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- @Target({}) @Retention(RUNTIME)
- public @interface EntityResult {
- Class entityClass();
- FieldResult[] fields() default {};
- String discriminatorColumn() default "";
- }
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- @Target({}) @Retention(RUNTIME)
- public @interface FieldResult {
- String name();
- String column();
- }
-
-
-
-
-
-
-
-
-
-
-
-
-
- @Target({}) @Retention(RUNTIME)
- public @interface ColumnResult {
- String name();
- }
-
-
-
-
-
-
-
-
-
-
-
-
- @Target({TYPE}) @Retention(RUNTIME)
- public @interface Table {
- String name() default "";
- String catalog() default "";
- String schema() default "";
- UniqueConstraint[] uniqueConstraints() default {};
- }
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- @Target({TYPE}) @Retention(RUNTIME)
- public @interface SecondaryTable {
- String name();
- String catalog() default "";
- String schema() default "";
- PrimaryKeyJoinColumn[] pkJoinColumns() default {};
- UniqueConstraint[] uniqueConstraints() default {};
- }
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- @Target({}) @Retention(RUNTIME)
- public @interface UniqueConstraint {
- String[] columnNames();
- }
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- @Target({METHOD, FIELD}) @Retention(RUNTIME)
- public @interface Column {
- String name() default "";
- boolean unique() default false;
- boolean nullable() default true;
- boolean insertable() default true;
- boolean updatable() default true;
- String columnDefinition() default "";
- String table() default "";
- int length() default 255;
- int precision() default 0; // decimal precision
- int scale() default 0; // decimal scale
- }
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- @Target({METHOD, FIELD}) @Retention(RUNTIME)
- public @interface JoinColumn {
- String name() default "";
- String referencedColumnName() default "";
- boolean unique() default false;
- boolean nullable() default true;
- boolean insertable() default true;
- boolean updatable() default true;
- String columnDefinition() default "";
- String table() default "";
- }
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- public enum GenerationType { TABLE, SEQUENCE, IDENTITY, AUTO };
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- @Target({TYPE, METHOD, FIELD}) @Retention(RUNTIME)
- public @interface AttributeOverride {
- String name();
- Column column();
- }
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- @Target({TYPE, METHOD, FIELD}) @Retention(RUNTIME)
- public @interface AssociationOverride {
- String name();
- JoinColumn[] joinColumns();
- }
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- @Target({TYPE}) @Retention(RUNTIME)
- public @interface IdClass {
- Class value();
- }
-
-
-
-
-
-
-
-
-
-
-
-
- @Target({METHOD, FIELD}) @Retention(RUNTIME)
- public @interface Id {}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- @Target({METHOD, FIELD}) @Retention(RUNTIME)
- public @interface EmbeddedId {}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- @Target({METHOD, FIELD}) @Retention(RUNTIME)
- public @interface Transient {}
-
-
-
-
-
-
-
-
-
-
-
-
- @Target({METHOD, FIELD}) @Retention(RUNTIME)
- public @interface Version {}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- @Target({METHOD, FIELD}) @Retention(RUNTIME)
- public @interface Basic {
- FetchType fetch() default EAGER;
- boolean optional() default true;
- }
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- public enum FetchType { LAZY, EAGER };
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- @Target({METHOD, FIELD}) @Retention(RUNTIME)
- public @interface Lob {}
-
-
-
-
-
-
-
-
-
-
-
- @Target({METHOD, FIELD}) @Retention(RUNTIME)
- public @interface Temporal {
- TemporalType value();
- }
-
-
-
-
-
-
-
-
-
-
-
-
- public enum TemporalType {
- DATE, // java.sql.Date
- TIME, // java.sql.Time
- TIMESTAMP // java.sql.Timestamp
- }
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- @Target({METHOD, FIELD}) @Retention(RUNTIME)
- public @interface Enumerated {
- EnumType value() default ORDINAL;
- }
-
-
-
-
-
-
-
-
-
-
-
-
- public enum EnumType {
- ORDINAL,
- STRING
- }
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- @Target({METHOD, FIELD}) @Retention(RUNTIME)
- public @interface ManyToOne {
- Class targetEntity() default void.class;
- CascadeType[] cascade() default {};
- FetchType fetch() default EAGER;
- boolean optional() default true;
- }
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- public enum CascadeType { ALL, PERSIST, MERGE, REMOVE, REFRESH};
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- @Target({METHOD, FIELD}) @Retention(RUNTIME)
- public @interface OneToOne {
- Class targetEntity() default void.class;
- CascadeType[] cascade() default {};
- FetchType fetch() default EAGER;
- boolean optional() default true;
- String mappedBy() default "";
- }
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- @Target({METHOD, FIELD}) @Retention(RUNTIME)
- public @interface OneToMany {
- Class targetEntity() default void.class;
- CascadeType[] cascade() default {};
- FetchType fetch() default LAZY;
- String mappedBy() default "";
- }
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- @Target({METHOD, FIELD}) @Retention(RUNTIME)
- public @interface JoinTable {
- String name() default "";
- String catalog() default "";
- String schema() default "";
- JoinColumn[] joinColumns() default {};
- JoinColumn[] inverseJoinColumns() default {};
- UniqueConstraint[] uniqueConstraints() default {};
- }
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- @Target({METHOD, FIELD}) @Retention(RUNTIME)
- public @interface ManyToMany {
- Class targetEntity() default void.class;
- CascadeType[] cascade() default {};
- FetchType fetch() default LAZY;
- String mappedBy() default "";
- }
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- @Target({METHOD, FIELD}) @Retention(RUNTIME)
- public @interface GeneratedValue {
- GenerationType strategy() default AUTO;
- String generator() default "";
- }
-
-
-
-
-
-
-
-
-
-
-
-
-
- @Target({METHOD, FIELD}) @Retention(RUNTIME)
- public @interface MapKey {
- String name() default "";
- }
-
-
-
-
-
-
-
-
-
-
-
-
- @Target({METHOD, FIELD}) @Retention(RUNTIME)
- public @interface OrderBy {
- String value() default "";
- }
-
-
-
-
-
-
-
-
-
-
-
-
- @Target({TYPE}) @Retention(RUNTIME)
- public @interface Inheritance {
- InheritanceType strategy() default SINGLE_TABLE;
- }
-
-
-
-
-
-
-
-
-
-
-
-
- public enum InheritanceType
- { SINGLE_TABLE, JOINED, TABLE_PER_CLASS};
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- @Target({TYPE}) @Retention(RUNTIME)
- public @interface DiscriminatorValue {
- String value();
- }
-
-
-
-
-
-
-
-
-
-
-
-
- public enum DiscriminatorType { STRING, CHAR, INTEGER };
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- @Target({TYPE, METHOD, FIELD}) @Retention(RUNTIME)
- public @interface PrimaryKeyJoinColumn {
- String name() default "";
- String referencedColumnName() default "";
- String columnDefinition() default "";
- }
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- @Target({TYPE}) @Retention(RUNTIME)
- public @interface DiscriminatorColumn {
- String name() default "DTYPE";
- DiscriminatorType discriminatorType() default STRING;
- String columnDefinition() default "";
- int length() default 31;
- }
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Defines the settings and mappings for embeddable objects. Is
- allowed to be sparsely populated and used in conjunction with
- the annotations. Alternatively, the metadata-complete attribute
- can be used to indicate that no annotations are to be processed
- in the class. If this is the case then the defaulting rules will
- be recursively applied.
-
- @Target({TYPE}) @Retention(RUNTIME)
- public @interface Embeddable {}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- @Target({METHOD, FIELD}) @Retention(RUNTIME)
- public @interface Embedded {}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Defines the settings and mappings for a mapped superclass. Is
- allowed to be sparsely populated and used in conjunction with
- the annotations. Alternatively, the metadata-complete attribute
- can be used to indicate that no annotations are to be processed
- If this is the case then the defaulting rules will be recursively
- applied.
-
- @Target(TYPE) @Retention(RUNTIME)
- public @interface MappedSuperclass{}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- @Target({TYPE, METHOD, FIELD}) @Retention(RUNTIME)
- public @interface SequenceGenerator {
- String name();
- String sequenceName() default "";
- int initialValue() default 1;
- int allocationSize() default 50;
- }
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- @Target({TYPE, METHOD, FIELD}) @Retention(RUNTIME)
- public @interface TableGenerator {
- String name();
- String table() default "";
- String catalog() default "";
- String schema() default "";
- String pkColumnName() default "";
- String valueColumnName() default "";
- String pkColumnValue() default "";
- int initialValue() default 0;
- int allocationSize() default 50;
- UniqueConstraint[] uniqueConstraints() default {};
- }
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+ @(#)orm_1_0.xsd 1.0 Feb 14 2006
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ The entity-mappings element is the root element of an mapping
+ file. It contains the following four types of elements:
+
+ 1. The persistence-unit-metadata element contains metadata
+ for the entire persistence unit. It is undefined if this element
+ occurs in multiple mapping files within the same persistence unit.
+
+ 2. The package, schema, catalog and access elements apply to all of
+ the entity, mapped-superclass and embeddable elements defined in
+ the same file in which they occur.
+
+ 3. The sequence-generator, table-generator, named-query,
+ named-native-query and sql-result-set-mapping elements are global
+ to the persistence unit. It is undefined to have more than one
+ sequence-generator or table-generator of the same name in the same
+ or different mapping files in a persistence unit. It is also
+ undefined to have more than one named-query or named-native-query
+ of the same name in the same or different mapping files in a
+ persistence unit.
+
+ 4. The entity, mapped-superclass and embeddable elements each define
+ the mapping information for a managed persistent class. The mapping
+ information contained in these elements may be complete or it may
+ be partial.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Metadata that applies to the persistence unit and not just to
+ the mapping file in which it is contained.
+
+ If the xml-mapping-metadata-complete element is specified then
+ the complete set of mapping metadata for the persistence unit
+ is contained in the XML mapping files for the persistence unit.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ These defaults are applied to the persistence unit as a whole
+ unless they are overridden by local annotation or XML
+ element settings.
+
+ schema - Used as the schema for all tables or secondary tables
+ that apply to the persistence unit
+ catalog - Used as the catalog for all tables or secondary tables
+ that apply to the persistence unit
+ access - Used as the access type for all managed classes in
+ the persistence unit
+ cascade-persist - Adds cascade-persist to the set of cascade options
+ in entity relationships of the persistence unit
+ entity-listeners - List of default entity listeners to be invoked
+ on each entity in the persistence unit.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Defines the settings and mappings for an entity. Is allowed to be
+ sparsely populated and used in conjunction with the annotations.
+ Alternatively, the metadata-complete attribute can be used to
+ indicate that no annotations on the entity class (and its fields
+ or properties) are to be processed. If this is the case then
+ the defaulting rules for the entity and its subelements will
+ be recursively applied.
+
+ @Target(TYPE) @Retention(RUNTIME)
+ public @interface Entity {
+ String name() default "";
+ }
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ This element contains the entity field or property mappings.
+ It may be sparsely populated to include only a subset of the
+ fields or properties. If metadata-complete for the entity is true
+ then the remainder of the attributes will be defaulted according
+ to the default rules.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ This element determines how the persistence provider accesses the
+ state of an entity or embedded object.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ @Target({TYPE}) @Retention(RUNTIME)
+ public @interface EntityListeners {
+ Class[] value();
+ }
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Defines an entity listener to be invoked at lifecycle events
+ for the entities that list this listener.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ @Target({METHOD}) @Retention(RUNTIME)
+ public @interface PrePersist {}
+
+
+
+
+
+
+
+
+
+
+
+
+ @Target({METHOD}) @Retention(RUNTIME)
+ public @interface PostPersist {}
+
+
+
+
+
+
+
+
+
+
+
+
+ @Target({METHOD}) @Retention(RUNTIME)
+ public @interface PreRemove {}
+
+
+
+
+
+
+
+
+
+
+
+
+ @Target({METHOD}) @Retention(RUNTIME)
+ public @interface PostRemove {}
+
+
+
+
+
+
+
+
+
+
+
+
+ @Target({METHOD}) @Retention(RUNTIME)
+ public @interface PreUpdate {}
+
+
+
+
+
+
+
+
+
+
+
+
+ @Target({METHOD}) @Retention(RUNTIME)
+ public @interface PostUpdate {}
+
+
+
+
+
+
+
+
+
+
+
+
+ @Target({METHOD}) @Retention(RUNTIME)
+ public @interface PostLoad {}
+
+
+
+
+
+
+
+
+
+
+
+
+ @Target({}) @Retention(RUNTIME)
+ public @interface QueryHint {
+ String name();
+ String value();
+ }
+
+
+
+
+
+
+
+
+
+
+
+
+
+ @Target({TYPE}) @Retention(RUNTIME)
+ public @interface NamedQuery {
+ String name();
+ String query();
+ QueryHint[] hints() default {};
+ }
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ @Target({TYPE}) @Retention(RUNTIME)
+ public @interface NamedNativeQuery {
+ String name();
+ String query();
+ QueryHint[] hints() default {};
+ Class resultClass() default void.class;
+ String resultSetMapping() default ""; //named SqlResultSetMapping
+ }
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ @Target({TYPE}) @Retention(RUNTIME)
+ public @interface SqlResultSetMapping {
+ String name();
+ EntityResult[] entities() default {};
+ ColumnResult[] columns() default {};
+ }
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ @Target({}) @Retention(RUNTIME)
+ public @interface EntityResult {
+ Class entityClass();
+ FieldResult[] fields() default {};
+ String discriminatorColumn() default "";
+ }
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ @Target({}) @Retention(RUNTIME)
+ public @interface FieldResult {
+ String name();
+ String column();
+ }
+
+
+
+
+
+
+
+
+
+
+
+
+
+ @Target({}) @Retention(RUNTIME)
+ public @interface ColumnResult {
+ String name();
+ }
+
+
+
+
+
+
+
+
+
+
+
+
+ @Target({TYPE}) @Retention(RUNTIME)
+ public @interface Table {
+ String name() default "";
+ String catalog() default "";
+ String schema() default "";
+ UniqueConstraint[] uniqueConstraints() default {};
+ }
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ @Target({TYPE}) @Retention(RUNTIME)
+ public @interface SecondaryTable {
+ String name();
+ String catalog() default "";
+ String schema() default "";
+ PrimaryKeyJoinColumn[] pkJoinColumns() default {};
+ UniqueConstraint[] uniqueConstraints() default {};
+ }
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ @Target({}) @Retention(RUNTIME)
+ public @interface UniqueConstraint {
+ String[] columnNames();
+ }
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ @Target({METHOD, FIELD}) @Retention(RUNTIME)
+ public @interface Column {
+ String name() default "";
+ boolean unique() default false;
+ boolean nullable() default true;
+ boolean insertable() default true;
+ boolean updatable() default true;
+ String columnDefinition() default "";
+ String table() default "";
+ int length() default 255;
+ int precision() default 0; // decimal precision
+ int scale() default 0; // decimal scale
+ }
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ @Target({METHOD, FIELD}) @Retention(RUNTIME)
+ public @interface JoinColumn {
+ String name() default "";
+ String referencedColumnName() default "";
+ boolean unique() default false;
+ boolean nullable() default true;
+ boolean insertable() default true;
+ boolean updatable() default true;
+ String columnDefinition() default "";
+ String table() default "";
+ }
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ public enum GenerationType { TABLE, SEQUENCE, IDENTITY, AUTO };
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ @Target({TYPE, METHOD, FIELD}) @Retention(RUNTIME)
+ public @interface AttributeOverride {
+ String name();
+ Column column();
+ }
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ @Target({TYPE, METHOD, FIELD}) @Retention(RUNTIME)
+ public @interface AssociationOverride {
+ String name();
+ JoinColumn[] joinColumns();
+ }
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ @Target({TYPE}) @Retention(RUNTIME)
+ public @interface IdClass {
+ Class value();
+ }
+
+
+
+
+
+
+
+
+
+
+
+
+ @Target({METHOD, FIELD}) @Retention(RUNTIME)
+ public @interface Id {}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ @Target({METHOD, FIELD}) @Retention(RUNTIME)
+ public @interface EmbeddedId {}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ @Target({METHOD, FIELD}) @Retention(RUNTIME)
+ public @interface Transient {}
+
+
+
+
+
+
+
+
+
+
+
+
+ @Target({METHOD, FIELD}) @Retention(RUNTIME)
+ public @interface Version {}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ @Target({METHOD, FIELD}) @Retention(RUNTIME)
+ public @interface Basic {
+ FetchType fetch() default EAGER;
+ boolean optional() default true;
+ }
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ public enum FetchType { LAZY, EAGER };
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ @Target({METHOD, FIELD}) @Retention(RUNTIME)
+ public @interface Lob {}
+
+
+
+
+
+
+
+
+
+
+
+ @Target({METHOD, FIELD}) @Retention(RUNTIME)
+ public @interface Temporal {
+ TemporalType value();
+ }
+
+
+
+
+
+
+
+
+
+
+
+
+ public enum TemporalType {
+ DATE, // java.sql.Date
+ TIME, // java.sql.Time
+ TIMESTAMP // java.sql.Timestamp
+ }
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ @Target({METHOD, FIELD}) @Retention(RUNTIME)
+ public @interface Enumerated {
+ EnumType value() default ORDINAL;
+ }
+
+
+
+
+
+
+
+
+
+
+
+
+ public enum EnumType {
+ ORDINAL,
+ STRING
+ }
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ @Target({METHOD, FIELD}) @Retention(RUNTIME)
+ public @interface ManyToOne {
+ Class targetEntity() default void.class;
+ CascadeType[] cascade() default {};
+ FetchType fetch() default EAGER;
+ boolean optional() default true;
+ }
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ public enum CascadeType { ALL, PERSIST, MERGE, REMOVE, REFRESH};
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ @Target({METHOD, FIELD}) @Retention(RUNTIME)
+ public @interface OneToOne {
+ Class targetEntity() default void.class;
+ CascadeType[] cascade() default {};
+ FetchType fetch() default EAGER;
+ boolean optional() default true;
+ String mappedBy() default "";
+ }
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ @Target({METHOD, FIELD}) @Retention(RUNTIME)
+ public @interface OneToMany {
+ Class targetEntity() default void.class;
+ CascadeType[] cascade() default {};
+ FetchType fetch() default LAZY;
+ String mappedBy() default "";
+ }
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ @Target({METHOD, FIELD}) @Retention(RUNTIME)
+ public @interface JoinTable {
+ String name() default "";
+ String catalog() default "";
+ String schema() default "";
+ JoinColumn[] joinColumns() default {};
+ JoinColumn[] inverseJoinColumns() default {};
+ UniqueConstraint[] uniqueConstraints() default {};
+ }
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ @Target({METHOD, FIELD}) @Retention(RUNTIME)
+ public @interface ManyToMany {
+ Class targetEntity() default void.class;
+ CascadeType[] cascade() default {};
+ FetchType fetch() default LAZY;
+ String mappedBy() default "";
+ }
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ @Target({METHOD, FIELD}) @Retention(RUNTIME)
+ public @interface GeneratedValue {
+ GenerationType strategy() default AUTO;
+ String generator() default "";
+ }
+
+
+
+
+
+
+
+
+
+
+
+
+
+ @Target({METHOD, FIELD}) @Retention(RUNTIME)
+ public @interface MapKey {
+ String name() default "";
+ }
+
+
+
+
+
+
+
+
+
+
+
+
+ @Target({METHOD, FIELD}) @Retention(RUNTIME)
+ public @interface OrderBy {
+ String value() default "";
+ }
+
+
+
+
+
+
+
+
+
+
+
+
+ @Target({TYPE}) @Retention(RUNTIME)
+ public @interface Inheritance {
+ InheritanceType strategy() default SINGLE_TABLE;
+ }
+
+
+
+
+
+
+
+
+
+
+
+
+ public enum InheritanceType
+ { SINGLE_TABLE, JOINED, TABLE_PER_CLASS};
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ @Target({TYPE}) @Retention(RUNTIME)
+ public @interface DiscriminatorValue {
+ String value();
+ }
+
+
+
+
+
+
+
+
+
+
+
+
+ public enum DiscriminatorType { STRING, CHAR, INTEGER };
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ @Target({TYPE, METHOD, FIELD}) @Retention(RUNTIME)
+ public @interface PrimaryKeyJoinColumn {
+ String name() default "";
+ String referencedColumnName() default "";
+ String columnDefinition() default "";
+ }
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ @Target({TYPE}) @Retention(RUNTIME)
+ public @interface DiscriminatorColumn {
+ String name() default "DTYPE";
+ DiscriminatorType discriminatorType() default STRING;
+ String columnDefinition() default "";
+ int length() default 31;
+ }
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Defines the settings and mappings for embeddable objects. Is
+ allowed to be sparsely populated and used in conjunction with
+ the annotations. Alternatively, the metadata-complete attribute
+ can be used to indicate that no annotations are to be processed
+ in the class. If this is the case then the defaulting rules will
+ be recursively applied.
+
+ @Target({TYPE}) @Retention(RUNTIME)
+ public @interface Embeddable {}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ @Target({METHOD, FIELD}) @Retention(RUNTIME)
+ public @interface Embedded {}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Defines the settings and mappings for a mapped superclass. Is
+ allowed to be sparsely populated and used in conjunction with
+ the annotations. Alternatively, the metadata-complete attribute
+ can be used to indicate that no annotations are to be processed
+ If this is the case then the defaulting rules will be recursively
+ applied.
+
+ @Target(TYPE) @Retention(RUNTIME)
+ public @interface MappedSuperclass{}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ @Target({TYPE, METHOD, FIELD}) @Retention(RUNTIME)
+ public @interface SequenceGenerator {
+ String name();
+ String sequenceName() default "";
+ int initialValue() default 1;
+ int allocationSize() default 50;
+ }
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ @Target({TYPE, METHOD, FIELD}) @Retention(RUNTIME)
+ public @interface TableGenerator {
+ String name();
+ String table() default "";
+ String catalog() default "";
+ String schema() default "";
+ String pkColumnName() default "";
+ String valueColumnName() default "";
+ String pkColumnValue() default "";
+ int initialValue() default 0;
+ int allocationSize() default 50;
+ UniqueConstraint[] uniqueConstraints() default {};
+ }
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/hibernate-core/src/main/resources/org/hibernate/ejb/orm_2_0.xsd b/hibernate-core/src/main/resources/org/hibernate/jpa/orm_2_0.xsd
similarity index 100%
rename from hibernate-core/src/main/resources/org/hibernate/ejb/orm_2_0.xsd
rename to hibernate-core/src/main/resources/org/hibernate/jpa/orm_2_0.xsd
diff --git a/hibernate-entitymanager/src/main/resources/org/hibernate/jpa/orm_2_1.xsd b/hibernate-core/src/main/resources/org/hibernate/jpa/orm_2_1.xsd
similarity index 100%
rename from hibernate-entitymanager/src/main/resources/org/hibernate/jpa/orm_2_1.xsd
rename to hibernate-core/src/main/resources/org/hibernate/jpa/orm_2_1.xsd
diff --git a/hibernate-core/src/main/xjb/orm-bindings.xjb b/hibernate-core/src/main/xjb/orm-bindings.xjb
index 1ed292a425..c25db84fd5 100644
--- a/hibernate-core/src/main/xjb/orm-bindings.xjb
+++ b/hibernate-core/src/main/xjb/orm-bindings.xjb
@@ -6,7 +6,7 @@
jaxb:extensionBindingPrefixes="inheritance"
version="2.1">
-
+
diff --git a/hibernate-core/src/test/java/org/hibernate/metamodel/internal/source/annotations/xml/OrmXmlParserTests.java b/hibernate-core/src/test/java/org/hibernate/metamodel/internal/source/annotations/xml/OrmXmlParserTests.java
index 15a1dd151c..54c94f6e27 100644
--- a/hibernate-core/src/test/java/org/hibernate/metamodel/internal/source/annotations/xml/OrmXmlParserTests.java
+++ b/hibernate-core/src/test/java/org/hibernate/metamodel/internal/source/annotations/xml/OrmXmlParserTests.java
@@ -30,6 +30,7 @@ import org.hibernate.metamodel.MetadataSources;
import org.hibernate.metamodel.internal.MetadataImpl;
import org.hibernate.metamodel.spi.binding.EntityBinding;
import org.hibernate.metamodel.spi.source.MappingException;
+import org.hibernate.testing.FailureExpectedWithNewMetamodel;
import org.hibernate.testing.junit4.BaseUnitTestCase;
import static junit.framework.Assert.assertNotNull;
@@ -58,6 +59,7 @@ public class OrmXmlParserTests extends BaseUnitTestCase {
}
@Test(expected = MappingException.class)
+ @FailureExpectedWithNewMetamodel(message = "JAXB validation is disabled ATM to support both JPA 2.1 and previous orm.xml")
public void testInvalidOrmXmlThrowsException() {
MetadataSources sources = new MetadataSources( new StandardServiceRegistryBuilder().build() );
sources.addResource( "org/hibernate/metamodel/internal/source/annotations/xml/orm-invalid.xml" );
diff --git a/hibernate-core/src/test/java/org/hibernate/metamodel/internal/source/annotations/xml/mocker/AbstractMockerTest.java b/hibernate-core/src/test/java/org/hibernate/metamodel/internal/source/annotations/xml/mocker/AbstractMockerTest.java
index b182c422b5..236cf8fa06 100644
--- a/hibernate-core/src/test/java/org/hibernate/metamodel/internal/source/annotations/xml/mocker/AbstractMockerTest.java
+++ b/hibernate-core/src/test/java/org/hibernate/metamodel/internal/source/annotations/xml/mocker/AbstractMockerTest.java
@@ -39,6 +39,10 @@ import org.jboss.jandex.Indexer;
import org.hibernate.AnnotationException;
import org.hibernate.HibernateException;
import org.hibernate.boot.registry.classloading.spi.ClassLoaderService;
+import org.hibernate.jaxb.internal.JaxbMappingProcessor;
+import org.hibernate.jaxb.spi.JaxbRoot;
+import org.hibernate.jaxb.spi.Origin;
+import org.hibernate.jaxb.spi.SourceType;
import org.hibernate.jaxb.spi.orm.JaxbEntityMappings;
import org.hibernate.service.ServiceRegistry;
import org.hibernate.testing.ServiceRegistryBuilder;
@@ -50,8 +54,9 @@ import static org.junit.Assert.fail;
* @author Strong Liu
*/
public abstract class AbstractMockerTest {
- private static final String ORM1_MAPPING_XSD = "org/hibernate/ejb/orm_1_0.xsd";
- private static final String ORM2_MAPPING_XSD = "org/hibernate/ejb/orm_2_0.xsd";
+ private static final String ORM1_MAPPING_XSD = "org/hibernate/jpa/orm_1_0.xsd";
+ private static final String ORM2_MAPPING_XSD = "org/hibernate/jpa/orm_2_0.xsd";
+ private static final String ORM2_1_MAPPING_XSD = "org/hibernate/jpa/orm_2_1.xsd";
private IndexBuilder indexBuilder;
private Index index;
private ServiceRegistry serviceRegistry;
@@ -69,23 +74,14 @@ public abstract class AbstractMockerTest {
ClassLoaderService classLoaderService = getServiceRegistry().getService( ClassLoaderService.class );
List xmlEntityMappingsList = new ArrayList();
for ( String fileName : mappingFiles ) {
- JaxbEntityMappings entityMappings;
- try {
- entityMappings = XmlHelper.unmarshallXml(
- packagePrefix + fileName, ORM2_MAPPING_XSD, JaxbEntityMappings.class, classLoaderService
- ).getRoot();
- }
- catch ( JAXBException orm2Exception ) {
- // if we cannot parse against orm_2_0.xsd we try orm_1_0.xsd for backwards compatibility
- try {
- entityMappings = XmlHelper.unmarshallXml(
- packagePrefix + fileName, ORM1_MAPPING_XSD, JaxbEntityMappings.class, classLoaderService
- ).getRoot();
- }
- catch ( JAXBException orm1Exception ) {
- throw new AnnotationException( "Unable to parse xml configuration.", orm1Exception );
- }
- }
+ JaxbMappingProcessor processor = new JaxbMappingProcessor( getServiceRegistry() );
+ JaxbRoot jaxbRoot = processor.unmarshal(
+ classLoaderService.locateResourceStream( packagePrefix + fileName ),
+ new Origin( SourceType.FILE, packagePrefix + fileName )
+ );
+ JaxbEntityMappings entityMappings = (JaxbEntityMappings)jaxbRoot.getRoot();
+
+
xmlEntityMappingsList.add( entityMappings );
}
return new EntityMappingsMocker( xmlEntityMappingsList, getIndex(), getServiceRegistry() );
diff --git a/hibernate-core/src/test/java/org/hibernate/test/annotations/index/jpa/AbstractJPAIndexTest.java b/hibernate-core/src/test/java/org/hibernate/test/annotations/index/jpa/AbstractJPAIndexTest.java
new file mode 100644
index 0000000000..b60a5665f3
--- /dev/null
+++ b/hibernate-core/src/test/java/org/hibernate/test/annotations/index/jpa/AbstractJPAIndexTest.java
@@ -0,0 +1,143 @@
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2013 by Red Hat Inc and/or its affiliates or by
+ * third-party contributors as indicated by either @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.test.annotations.index.jpa;
+
+import java.util.Iterator;
+
+import org.junit.Test;
+
+import org.hibernate.internal.util.StringHelper;
+import org.hibernate.mapping.Bag;
+import org.hibernate.mapping.Column;
+import org.hibernate.mapping.Index;
+import org.hibernate.mapping.Join;
+import org.hibernate.mapping.PersistentClass;
+import org.hibernate.mapping.Property;
+import org.hibernate.mapping.Set;
+import org.hibernate.mapping.Table;
+import org.hibernate.mapping.UniqueKey;
+import org.hibernate.testing.FailureExpectedWithNewMetamodel;
+import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * @author Strong Liu
+ */
+
+public abstract class AbstractJPAIndexTest extends BaseCoreFunctionalTestCase {
+ @Test
+ public void testTableIndex() {
+ PersistentClass entity = configuration().getClassMapping( Car.class.getName() );
+ Iterator itr = entity.getTable().getUniqueKeyIterator();
+ assertTrue( itr.hasNext() );
+ UniqueKey uk = (UniqueKey) itr.next();
+ assertFalse( itr.hasNext() );
+ assertTrue( StringHelper.isNotEmpty( uk.getName() ) );
+ assertEquals( 2, uk.getColumnSpan() );
+ Column column = (Column) uk.getColumns().get( 0 );
+ assertEquals( "brand", column.getName() );
+ column = (Column) uk.getColumns().get( 1 );
+ assertEquals( "producer", column.getName() );
+ assertSame( entity.getTable(), uk.getTable() );
+
+
+ itr = entity.getTable().getIndexIterator();
+ assertTrue( itr.hasNext() );
+ Index index = (Index)itr.next();
+ assertFalse( itr.hasNext() );
+ assertEquals( "Car_idx", index.getName() );
+ assertEquals( 1, index.getColumnSpan() );
+ column = index.getColumnIterator().next();
+ assertEquals( "since", column.getName() );
+ assertSame( entity.getTable(), index.getTable() );
+ }
+
+ @Test
+ public void testSecondaryTableIndex(){
+ PersistentClass entity = configuration().getClassMapping( Car.class.getName() );
+
+ Join join = (Join)entity.getJoinIterator().next();
+ Iterator itr = join.getTable().getIndexIterator();
+ assertTrue( itr.hasNext() );
+ Index index = itr.next();
+ assertFalse( itr.hasNext() );
+ assertTrue( "index name is not generated", StringHelper.isNotEmpty( index.getName() ) );
+ assertEquals( 2, index.getColumnSpan() );
+ Iterator columnIterator = index.getColumnIterator();
+ Column column = columnIterator.next();
+ assertEquals( "dealer_name", column.getName() );
+ column = columnIterator.next();
+ assertEquals( "rate", column.getName() );
+ assertSame( join.getTable(), index.getTable() );
+
+ }
+
+ @Test
+ public void testCollectionTableIndex(){
+ PersistentClass entity = configuration().getClassMapping( Car.class.getName() );
+ Property property = entity.getProperty( "otherDealers" );
+ Set set = (Set)property.getValue();
+ Table collectionTable = set.getCollectionTable();
+
+ Iterator itr = collectionTable.getIndexIterator();
+ assertTrue( itr.hasNext() );
+ Index index = itr.next();
+ assertFalse( itr.hasNext() );
+ assertTrue( "index name is not generated", StringHelper.isNotEmpty( index.getName() ) );
+ assertEquals( 1, index.getColumnSpan() );
+ Iterator columnIterator = index.getColumnIterator();
+ Column column = columnIterator.next();
+ assertEquals( "name", column.getName() );
+ assertSame( collectionTable, index.getTable() );
+
+ }
+
+ @Test
+ public void testJoinTableIndex(){
+ PersistentClass entity = configuration().getClassMapping( Importer.class.getName() );
+ Property property = entity.getProperty( "cars" );
+ Bag set = (Bag)property.getValue();
+ Table collectionTable = set.getCollectionTable();
+
+ Iterator itr = collectionTable.getIndexIterator();
+ assertTrue( itr.hasNext() );
+ Index index = itr.next();
+ assertFalse( itr.hasNext() );
+ assertTrue( "index name is not generated", StringHelper.isNotEmpty( index.getName() ) );
+ assertEquals( 1, index.getColumnSpan() );
+ Iterator columnIterator = index.getColumnIterator();
+ Column column = columnIterator.next();
+ assertEquals( "importers_id", column.getName() );
+ assertSame( collectionTable, index.getTable() );
+ }
+
+// @Test
+// public void testTableGeneratorIndex(){
+// //todo
+// }
+}
diff --git a/hibernate-core/src/test/java/org/hibernate/test/annotations/index/jpa/Car.java b/hibernate-core/src/test/java/org/hibernate/test/annotations/index/jpa/Car.java
index a0bea61957..d67522af78 100644
--- a/hibernate-core/src/test/java/org/hibernate/test/annotations/index/jpa/Car.java
+++ b/hibernate-core/src/test/java/org/hibernate/test/annotations/index/jpa/Car.java
@@ -23,9 +23,20 @@
*/
package org.hibernate.test.annotations.index.jpa;
+import java.util.List;
+import java.util.Set;
+import javax.persistence.AttributeOverride;
+import javax.persistence.AttributeOverrides;
+import javax.persistence.CascadeType;
+import javax.persistence.CollectionTable;
+import javax.persistence.Column;
+import javax.persistence.ElementCollection;
+import javax.persistence.Embedded;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Index;
+import javax.persistence.ManyToMany;
+import javax.persistence.SecondaryTable;
import javax.persistence.Table;
@@ -33,13 +44,85 @@ import javax.persistence.Table;
* @author Strong Liu
*/
@Entity
-@Table( indexes = {@Index( unique = true, columnList = "brand, producer")
-, @Index( name = "Car_idx", columnList = "since DESC")})
+@Table(indexes = {
+ @Index(unique = true, columnList = "brand, producer")
+ , @Index(name = "Car_idx", columnList = "since DESC")
+})
+@SecondaryTable(name = "T_DEALER", indexes = @Index(columnList = "dealer_name ASC, rate DESC"))
public class Car {
@Id
- long id;
- String brand;
- String producer;
- long since;
+ private long id;
+ private String brand;
+ private String producer;
+ private long since;
+ @AttributeOverrides({
+ @AttributeOverride(name = "name", column = @Column(name = "dealer_name", table = "T_DEALER")),
+ @AttributeOverride(name = "rate", column = @Column(table = "T_DEALER"))
+ })
+ @Embedded
+ private Dealer dealer;
+ @ElementCollection
+ @CollectionTable(name = "CAR_DEALTERS", indexes = @Index(columnList = "name"))
+ private Set otherDealers;
+
+
+ @ManyToMany(cascade = CascadeType.ALL, mappedBy = "cars")
+ private List importers;
+
+ public String getBrand() {
+ return brand;
+ }
+
+ public void setBrand(String brand) {
+ this.brand = brand;
+ }
+
+ public Dealer getDealer() {
+ return dealer;
+ }
+
+ public void setDealer(Dealer dealer) {
+ this.dealer = dealer;
+ }
+
+ public long getId() {
+ return id;
+ }
+
+ public void setId(long id) {
+ this.id = id;
+ }
+
+ public List getImporters() {
+ return importers;
+ }
+
+ public void setImporters(List importers) {
+ this.importers = importers;
+ }
+
+ public Set getOtherDealers() {
+ return otherDealers;
+ }
+
+ public void setOtherDealers(Set otherDealers) {
+ this.otherDealers = otherDealers;
+ }
+
+ public String getProducer() {
+ return producer;
+ }
+
+ public void setProducer(String producer) {
+ this.producer = producer;
+ }
+
+ public long getSince() {
+ return since;
+ }
+
+ public void setSince(long since) {
+ this.since = since;
+ }
}
diff --git a/hibernate-core/src/test/java/org/hibernate/test/annotations/index/jpa/Dealer.java b/hibernate-core/src/test/java/org/hibernate/test/annotations/index/jpa/Dealer.java
index 3c01d5f5f1..309bf19a3b 100644
--- a/hibernate-core/src/test/java/org/hibernate/test/annotations/index/jpa/Dealer.java
+++ b/hibernate-core/src/test/java/org/hibernate/test/annotations/index/jpa/Dealer.java
@@ -23,11 +23,30 @@
*/
package org.hibernate.test.annotations.index.jpa;
-import javax.persistence.Entity;
+import java.io.Serializable;
+import javax.persistence.Embeddable;
/**
* @author Strong Liu
*/
-@Entity
-public class Dealer {
+@Embeddable
+public class Dealer implements Serializable {
+ private String name;
+ private long rate;
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public long getRate() {
+ return rate;
+ }
+
+ public void setRate(long rate) {
+ this.rate = rate;
+ }
}
diff --git a/hibernate-core/src/test/java/org/hibernate/test/annotations/index/jpa/Importer.java b/hibernate-core/src/test/java/org/hibernate/test/annotations/index/jpa/Importer.java
new file mode 100644
index 0000000000..378ec7ecc1
--- /dev/null
+++ b/hibernate-core/src/test/java/org/hibernate/test/annotations/index/jpa/Importer.java
@@ -0,0 +1,70 @@
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2013 by Red Hat Inc and/or its affiliates or by
+ * third-party contributors as indicated by either @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.test.annotations.index.jpa;
+
+import java.util.List;
+import javax.persistence.CascadeType;
+import javax.persistence.Entity;
+import javax.persistence.Id;
+import javax.persistence.Index;
+import javax.persistence.JoinTable;
+import javax.persistence.ManyToMany;
+
+/**
+ * @author Strong Liu
+ */
+@Entity
+public class Importer {
+ @Id
+ private long id;
+
+ private String name;
+ @ManyToMany(cascade = CascadeType.ALL)
+ @JoinTable( name = "CAR_IMPORTER",indexes = @Index(columnList = "importers_id"))
+ private List cars;
+
+ public List getCars() {
+ return cars;
+ }
+
+ public void setCars(List cars) {
+ this.cars = cars;
+ }
+
+ public long getId() {
+ return id;
+ }
+
+ public void setId(long id) {
+ this.id = id;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+}
diff --git a/hibernate-core/src/test/java/org/hibernate/test/annotations/index/jpa/IndexTest.java b/hibernate-core/src/test/java/org/hibernate/test/annotations/index/jpa/IndexTest.java
index 297f21e08c..845ab495bd 100644
--- a/hibernate-core/src/test/java/org/hibernate/test/annotations/index/jpa/IndexTest.java
+++ b/hibernate-core/src/test/java/org/hibernate/test/annotations/index/jpa/IndexTest.java
@@ -23,144 +23,21 @@
*/
package org.hibernate.test.annotations.index.jpa;
-import java.util.Iterator;
-import org.junit.Test;
-
-import org.hibernate.internal.util.StringHelper;
-import org.hibernate.mapping.Bag;
-import org.hibernate.mapping.Column;
-import org.hibernate.mapping.Index;
-import org.hibernate.mapping.Join;
-import org.hibernate.mapping.PersistentClass;
-import org.hibernate.mapping.Property;
-import org.hibernate.mapping.Set;
-import org.hibernate.mapping.Table;
-import org.hibernate.mapping.UniqueKey;
-import org.hibernate.test.annotations.embedded.Address;
-import org.hibernate.test.annotations.embedded.AddressType;
-import org.hibernate.test.annotations.embedded.Book;
-import org.hibernate.test.annotations.embedded.Person;
-import org.hibernate.test.annotations.embedded.Summary;
-import org.hibernate.test.annotations.embedded.WealthyPerson;
-import org.hibernate.test.event.collection.detached.Alias;
import org.hibernate.testing.FailureExpectedWithNewMetamodel;
-import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertSame;
-import static org.junit.Assert.assertTrue;
/**
* @author Strong Liu
*/
@FailureExpectedWithNewMetamodel
-public class IndexTest extends BaseCoreFunctionalTestCase {
+public class IndexTest extends AbstractJPAIndexTest {
@Override
protected Class>[] getAnnotatedClasses() {
- return new Class[] { Car.class,
- Book.class,
- Summary.class,
- WealthyPerson.class,
- Person.class,
- AddressType.class,
- Address.class,
- Alias.class,
- org.hibernate.test.event.collection.detached.Character.class
+ return new Class[] {
+ Car.class,
+ Dealer.class,
+ Importer.class
};
}
- @Test
- public void testTableIndex() {
- PersistentClass entity = configuration().getClassMapping( Car.class.getName() );
- Iterator itr = entity.getTable().getUniqueKeyIterator();
- assertTrue( itr.hasNext() );
- UniqueKey uk = (UniqueKey) itr.next();
- assertFalse( itr.hasNext() );
- assertTrue( StringHelper.isNotEmpty( uk.getName() ) );
- assertEquals( 2, uk.getColumnSpan() );
- Column column = (Column) uk.getColumns().get( 0 );
- assertEquals( "brand", column.getName() );
- column = (Column) uk.getColumns().get( 1 );
- assertEquals( "producer", column.getName() );
- assertSame( entity.getTable(), uk.getTable() );
-
-
- itr = entity.getTable().getIndexIterator();
- assertTrue( itr.hasNext() );
- Index index = (Index)itr.next();
- assertFalse( itr.hasNext() );
- assertEquals( "Car_idx", index.getName() );
- assertEquals( 1, index.getColumnSpan() );
- column = index.getColumnIterator().next();
- assertEquals( "since", column.getName() );
- assertSame( entity.getTable(), index.getTable() );
- }
-
- @Test
- public void testSecondaryTableIndex(){
- PersistentClass entity = configuration().getClassMapping( Book.class.getName() );
-
- Join join = (Join)entity.getJoinIterator().next();
- Iterator itr = join.getTable().getIndexIterator();
- assertTrue( itr.hasNext() );
- Index index = itr.next();
- assertFalse( itr.hasNext() );
- assertTrue( "index name is not generated", StringHelper.isNotEmpty( index.getName() ) );
- assertEquals( 2, index.getColumnSpan() );
- Iterator columnIterator = index.getColumnIterator();
- Column column = columnIterator.next();
- assertEquals( "summ_size", column.getName() );
- column = columnIterator.next();
- assertEquals( "text", column.getName() );
- assertSame( join.getTable(), index.getTable() );
-
- }
-
- @Test
- public void testCollectionTableIndex(){
- PersistentClass entity = configuration().getClassMapping( WealthyPerson.class.getName() );
- Property property = entity.getProperty( "explicitVacationHomes" );
- Set set = (Set)property.getValue();
- Table collectionTable = set.getCollectionTable();
-
- Iterator itr = collectionTable.getIndexIterator();
- assertTrue( itr.hasNext() );
- Index index = itr.next();
- assertFalse( itr.hasNext() );
- assertTrue( "index name is not generated", StringHelper.isNotEmpty( index.getName() ) );
- assertEquals( 2, index.getColumnSpan() );
- Iterator columnIterator = index.getColumnIterator();
- Column column = columnIterator.next();
- assertEquals( "countryName", column.getName() );
- column = columnIterator.next();
- assertEquals( "type_id", column.getName() );
- assertSame( collectionTable, index.getTable() );
-
- }
-
- @Test
- public void testJoinTableIndex(){
- PersistentClass entity = configuration().getClassMapping( Alias.class.getName() );
- Property property = entity.getProperty( "characters" );
- Bag set = (Bag)property.getValue();
- Table collectionTable = set.getCollectionTable();
-
- Iterator itr = collectionTable.getIndexIterator();
- assertTrue( itr.hasNext() );
- Index index = itr.next();
- assertFalse( itr.hasNext() );
- assertTrue( "index name is not generated", StringHelper.isNotEmpty( index.getName() ) );
- assertEquals( 1, index.getColumnSpan() );
- Iterator columnIterator = index.getColumnIterator();
- Column column = columnIterator.next();
- assertEquals( "characters_id", column.getName() );
- assertSame( collectionTable, index.getTable() );
- }
-
-// @Test
- public void testTableGeneratorIndex(){
- //todo
- }
}
diff --git a/hibernate-core/src/test/java/org/hibernate/test/annotations/index/jpa/OrmXmlIndexTest.java b/hibernate-core/src/test/java/org/hibernate/test/annotations/index/jpa/OrmXmlIndexTest.java
new file mode 100644
index 0000000000..2772b5b8aa
--- /dev/null
+++ b/hibernate-core/src/test/java/org/hibernate/test/annotations/index/jpa/OrmXmlIndexTest.java
@@ -0,0 +1,15 @@
+package org.hibernate.test.annotations.index.jpa;
+
+
+import org.hibernate.testing.FailureExpectedWithNewMetamodel;
+
+/**
+ * @author Strong Liu
+ */
+@FailureExpectedWithNewMetamodel
+public class OrmXmlIndexTest extends AbstractJPAIndexTest {
+ @Override
+ protected String[] getXmlFiles() {
+ return new String[] { "org/hibernate/test/annotations/index/jpa/orm-index.xml" };
+ }
+}
diff --git a/hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/NonExistentOrmVersionTest.java b/hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/NonExistentOrmVersionTest.java
index 59702bab9b..285a7bd0ef 100644
--- a/hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/NonExistentOrmVersionTest.java
+++ b/hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/NonExistentOrmVersionTest.java
@@ -25,14 +25,16 @@ package org.hibernate.test.annotations.xml.ejb3;
import java.io.InputStream;
+import org.hibernate.InvalidMappingException;
+import org.hibernate.cfg.Configuration;
+import org.hibernate.internal.util.xml.UnsupportedOrmXsdVersionException;
+
import org.junit.Test;
-import org.hibernate.MappingException;
-import org.hibernate.cfg.Configuration;
import org.hibernate.testing.TestForIssue;
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
-import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
@TestForIssue(jiraKey = "HHH-6271")
public class NonExistentOrmVersionTest extends BaseCoreFunctionalTestCase {
@@ -45,14 +47,11 @@ public class NonExistentOrmVersionTest extends BaseCoreFunctionalTestCase {
InputStream is = Thread.currentThread().getContextClassLoader().getResourceAsStream( xmlFileName );
config.addInputStream( is );
config.buildMappings();
+ fail( "Expecting failure due to unsupported xsd version" );
}
- catch ( MappingException mappingException ) {
- Throwable cause = mappingException.getCause();
- assertTrue(
- cause.getMessage().contains(
- "Value '3.0' of attribute 'version' of element 'entity-mappings' is not valid"
- )
- );
+ catch ( InvalidMappingException expected ) {
+ }
+ catch ( UnsupportedOrmXsdVersionException expected ) {
}
}
}
diff --git a/hibernate-core/src/test/java/org/hibernate/test/constraint/ConstraintTest.java b/hibernate-core/src/test/java/org/hibernate/test/constraint/ConstraintTest.java
index a80db3e4fc..2a0f1beaa5 100644
--- a/hibernate-core/src/test/java/org/hibernate/test/constraint/ConstraintTest.java
+++ b/hibernate-core/src/test/java/org/hibernate/test/constraint/ConstraintTest.java
@@ -20,57 +20,103 @@
*/
package org.hibernate.test.constraint;
-import javax.persistence.Entity;
-import javax.persistence.GeneratedValue;
-import javax.persistence.Id;
-import javax.persistence.Table;
-
-import org.junit.Test;
-
-import org.hibernate.metamodel.spi.relational.Column;
-import org.hibernate.test.util.SchemaUtil;
-import org.hibernate.testing.TestForIssue;
-import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
-
+import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
-/**
- * HHH-7797 re-wrote the way dialects handle unique constraints. Test
- * variations of unique & not null to ensure the constraints are created
- * correctly for each dialect.
- *
- * @author Brett Meyer
- */
-@TestForIssue( jiraKey = "HHH-7797" )
+import java.util.Iterator;
+
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.Id;
+import javax.persistence.OneToOne;
+import javax.persistence.Table;
+import javax.persistence.UniqueConstraint;
+
+import org.junit.Test;
+
+import org.hibernate.mapping.Column;
+import org.hibernate.mapping.ForeignKey;
+import org.hibernate.mapping.UniqueKey;
+import org.hibernate.testing.FailureExpectedWithNewMetamodel;
+import org.hibernate.testing.TestForIssue;
+import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
+
+@FailureExpectedWithNewMetamodel
public class ConstraintTest extends BaseCoreFunctionalTestCase {
+ private static final int MAX_NAME_LENGTH = 30;
+
+ private static final String EXPLICIT_FK_NAME = "fk_explicit";
+
+ private static final String EXPLICIT_UK_NAME = "uk_explicit";
+
@Override
protected Class>[] getAnnotatedClasses() {
return new Class>[] {
- Entity1.class
+ DataPoint.class, DataPoint2.class
};
}
@Test
- public void testConstraints() {
-
- Column column = SchemaUtil.getColumn( Entity1.class, "foo1", metadata() );
+ @TestForIssue( jiraKey = "HHH-7797" )
+ public void testUniqueConstraints() {
+ Column column = (Column) configuration().getClassMapping( DataPoint.class.getName() )
+ .getProperty( "foo1" ).getColumnIterator().next();
assertFalse( column.isNullable() );
assertTrue( column.isUnique() );
- column = SchemaUtil.getColumn( Entity1.class, "foo2", metadata() );
+ column = (Column) configuration().getClassMapping( DataPoint.class.getName() )
+ .getProperty( "foo2" ).getColumnIterator().next();
assertTrue( column.isNullable() );
assertTrue( column.isUnique() );
- column = SchemaUtil.getColumn( Entity1.class, "id", metadata() );
+ column = (Column) configuration().getClassMapping( DataPoint.class.getName() )
+ .getProperty( "id" ).getColumnIterator().next();
assertFalse( column.isNullable() );
assertTrue( column.isUnique() );
}
+ @Test
+ @TestForIssue( jiraKey = "HHH-1904" )
+ public void testConstraintNameLength() {
+ Iterator tableItr = configuration().getTableMappings();
+ while (tableItr.hasNext()) {
+ org.hibernate.mapping.Table table = tableItr.next();
+
+ Iterator fkItr = table.getForeignKeyIterator();
+ while (fkItr.hasNext()) {
+ ForeignKey fk = (ForeignKey) fkItr.next();
+ assertTrue( fk.getName().length() <= MAX_NAME_LENGTH );
+
+ // ensure the randomly generated constraint name doesn't
+ // happen if explicitly given
+ Column column = fk.getColumn( 0 );
+ if ( column.getName().equals( "explicit" ) ) {
+ assertEquals( fk.getName(), EXPLICIT_FK_NAME );
+ }
+ }
+
+ Iterator ukItr = table.getUniqueKeyIterator();
+ while (ukItr.hasNext()) {
+ UniqueKey uk = (UniqueKey) ukItr.next();
+ assertTrue( uk.getName().length() <= MAX_NAME_LENGTH );
+
+ // ensure the randomly generated constraint name doesn't
+ // happen if explicitly given
+ Column column = uk.getColumn( 0 );
+ if ( column.getName().equals( "explicit" ) ) {
+ assertEquals( uk.getName(), EXPLICIT_UK_NAME );
+ }
+ }
+ }
+ }
+
@Entity
- @Table( name = "Entity1" )
- public static class Entity1 {
+ @Table( name = "DataPoint", uniqueConstraints = {
+ @UniqueConstraint( name = EXPLICIT_UK_NAME, columnNames = { "explicit" } )
+ } )
+ public static class DataPoint {
@Id
@GeneratedValue
@javax.persistence.Column( nullable = false, unique = true)
@@ -81,5 +127,22 @@ public class ConstraintTest extends BaseCoreFunctionalTestCase {
@javax.persistence.Column( nullable = true, unique = true)
public String foo2;
+
+ public String explicit;
+ }
+
+ @Entity
+ @Table( name = "DataPoint2" )
+ public static class DataPoint2 {
+ @Id
+ @GeneratedValue
+ public long id;
+
+ @OneToOne
+ public DataPoint dp;
+
+ @OneToOne
+ @org.hibernate.annotations.ForeignKey(name = EXPLICIT_FK_NAME)
+ public DataPoint explicit;
}
}
\ No newline at end of file
diff --git a/hibernate-core/src/test/java/org/hibernate/test/hqlfetchscroll/HQLScrollFetchTest.java b/hibernate-core/src/test/java/org/hibernate/test/hqlfetchscroll/HQLScrollFetchTest.java
index 2bdfefb256..e2a7d65bda 100644
--- a/hibernate-core/src/test/java/org/hibernate/test/hqlfetchscroll/HQLScrollFetchTest.java
+++ b/hibernate-core/src/test/java/org/hibernate/test/hqlfetchscroll/HQLScrollFetchTest.java
@@ -12,6 +12,7 @@ import org.hibernate.Hibernate;
import org.hibernate.ScrollableResults;
import org.hibernate.Session;
import org.hibernate.Transaction;
+import org.hibernate.dialect.DB2Dialect;
import org.hibernate.dialect.H2Dialect;
import org.hibernate.dialect.Oracle8iDialect;
import org.hibernate.dialect.SQLServerDialect;
@@ -42,7 +43,7 @@ public class HQLScrollFetchTest extends BaseCoreFunctionalTestCase {
}
@Test
- @SkipForDialect( { SQLServerDialect.class, Oracle8iDialect.class, H2Dialect.class } )
+ @SkipForDialect( { SQLServerDialect.class, Oracle8iDialect.class, H2Dialect.class, DB2Dialect.class } )
public void testScroll() {
Session s = openSession();
ScrollableResults results = s.createQuery( QUERY ).scroll();
diff --git a/hibernate-core/src/test/java/org/hibernate/test/querycache/StringCompositeKey.java b/hibernate-core/src/test/java/org/hibernate/test/querycache/StringCompositeKey.java
index 531c103836..01024f0b38 100644
--- a/hibernate-core/src/test/java/org/hibernate/test/querycache/StringCompositeKey.java
+++ b/hibernate-core/src/test/java/org/hibernate/test/querycache/StringCompositeKey.java
@@ -1,6 +1,8 @@
package org.hibernate.test.querycache;
import java.io.Serializable;
+
+import javax.persistence.Column;
import javax.persistence.Embeddable;
@Embeddable
@@ -8,13 +10,20 @@ public class StringCompositeKey implements Serializable {
private static final long serialVersionUID = 1L;
- private String substation;
+ private String substation;
private String deviceType;
private String device;
+
+ private String analog;
- public String getSubstation() {
+ // For some dialects, the sum of a primary key column lengths cannot
+ // be larger than 255 (DB2). Restrict them to a sufficiently
+ // small size. See HHH-8085.
+
+ @Column( length = 50 )
+ public String getSubstation() {
return substation;
}
@@ -22,6 +31,7 @@ public class StringCompositeKey implements Serializable {
this.substation = substation;
}
+ @Column( length = 50 )
public String getDeviceType() {
return deviceType;
}
@@ -30,6 +40,7 @@ public class StringCompositeKey implements Serializable {
this.deviceType = deviceType;
}
+ @Column( length = 50 )
public String getDevice() {
return device;
}
@@ -38,6 +49,7 @@ public class StringCompositeKey implements Serializable {
this.device = device;
}
+ @Column( length = 50 )
public String getAnalog() {
return analog;
}
@@ -45,6 +57,4 @@ public class StringCompositeKey implements Serializable {
public void setAnalog(String analog) {
this.analog = analog;
}
-
- private String analog;
}
\ No newline at end of file
diff --git a/hibernate-core/src/test/resources/org/hibernate/test/annotations/index/jpa/orm-index.xml b/hibernate-core/src/test/resources/org/hibernate/test/annotations/index/jpa/orm-index.xml
new file mode 100644
index 0000000000..39726f6356
--- /dev/null
+++ b/hibernate-core/src/test/resources/org/hibernate/test/annotations/index/jpa/orm-index.xml
@@ -0,0 +1,67 @@
+
+
+
+ org.hibernate.test.annotations.index.jpa
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/hibernate-entitymanager/src/main/java/org/hibernate/ejb/packaging/NamedInputStream.java b/hibernate-entitymanager/src/main/java/org/hibernate/ejb/packaging/NamedInputStream.java
index 7141f55f98..733455bf7e 100644
--- a/hibernate-entitymanager/src/main/java/org/hibernate/ejb/packaging/NamedInputStream.java
+++ b/hibernate-entitymanager/src/main/java/org/hibernate/ejb/packaging/NamedInputStream.java
@@ -26,10 +26,12 @@ package org.hibernate.ejb.packaging;
import java.io.InputStream;
/**
- * @deprecated Use {@link org.hibernate.jpa.packaging.spi.NamedInputStream} instead
+ * @deprecated Doubly deprecated actually :) Moved to {@link org.hibernate.jpa.boot.spi.NamedInputStream}
+ * due to package renaming (org.hibernate.ejb -> org.hibernate.jpa). But also, the role fulfilled by this class
+ * was moved to the new {@link org.hibernate.jpa.boot.spi.InputStreamAccess} contract.
*/
@Deprecated
-public class NamedInputStream extends org.hibernate.jpa.packaging.spi.NamedInputStream {
+public class NamedInputStream extends org.hibernate.jpa.boot.spi.NamedInputStream {
public NamedInputStream(String name, InputStream stream) {
super( name, stream );
}
diff --git a/hibernate-entitymanager/src/main/java/org/hibernate/ejb/packaging/Scanner.java b/hibernate-entitymanager/src/main/java/org/hibernate/ejb/packaging/Scanner.java
index 3a2cd4e46a..a452e66495 100644
--- a/hibernate-entitymanager/src/main/java/org/hibernate/ejb/packaging/Scanner.java
+++ b/hibernate-entitymanager/src/main/java/org/hibernate/ejb/packaging/Scanner.java
@@ -24,8 +24,8 @@
package org.hibernate.ejb.packaging;
/**
- * @deprecated Use {@link org.hibernate.jpa.packaging.spi.Scanner} instead
+ * @deprecated Use {@link org.hibernate.jpa.boot.scan.spi.Scanner} instead
*/
@Deprecated
-public interface Scanner extends org.hibernate.jpa.packaging.spi.Scanner {
+public interface Scanner extends org.hibernate.jpa.boot.scan.spi.Scanner {
}
diff --git a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/packaging/internal/JarVisitorFactory.java b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/boot/archive/internal/ArchiveHelper.java
similarity index 63%
rename from hibernate-entitymanager/src/main/java/org/hibernate/jpa/packaging/internal/JarVisitorFactory.java
rename to hibernate-entitymanager/src/main/java/org/hibernate/jpa/boot/archive/internal/ArchiveHelper.java
index 45ca7f8e1b..76caf4db9c 100644
--- a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/packaging/internal/JarVisitorFactory.java
+++ b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/boot/archive/internal/ArchiveHelper.java
@@ -1,8 +1,10 @@
/*
- * Copyright (c) 2009, Red Hat Middleware LLC or third-party contributors as
+ * 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 Middleware LLC.
+ * 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
@@ -19,29 +21,26 @@
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
-package org.hibernate.jpa.packaging.internal;
+package org.hibernate.jpa.boot.archive.internal;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
-import java.net.URISyntaxException;
import java.net.URL;
import java.util.LinkedList;
import java.util.List;
-import org.hibernate.internal.util.StringHelper;
-import org.hibernate.jpa.internal.EntityManagerMessageLogger;
import org.jboss.logging.Logger;
+import org.hibernate.jpa.boot.archive.spi.ArchiveException;
+
/**
* @author Emmanuel Bernard
- * @author Brett Meyer
+ * @author Steve Ebersole
*/
-public class JarVisitorFactory {
-
- private static final EntityManagerMessageLogger LOG = Logger.getMessageLogger(EntityManagerMessageLogger.class,
- JarVisitorFactory.class.getName());
+public class ArchiveHelper {
+ private static final Logger log = Logger.getLogger( ArchiveHelper.class );
/**
* Get the JAR URL of the JAR containing the given entry
@@ -51,7 +50,6 @@ public class JarVisitorFactory {
* @param entry file known to be in the JAR
* @return the JAR URL
* @throws IllegalArgumentException if none URL is found
- * TODO move to a ScannerHelper service?
*/
public static URL getJarURLFromURLEntry(URL url, String entry) throws IllegalArgumentException {
URL jarUrl;
@@ -106,7 +104,7 @@ public class JarVisitorFactory {
"Unable to determine JAR Url from " + url + ". Cause: " + e.getMessage()
);
}
- LOG.trace("JAR URL from URL Entry: " + url + " >> " + jarUrl);
+ log.trace("JAR URL from URL Entry: " + url + " >> " + jarUrl);
return jarUrl;
}
@@ -114,7 +112,6 @@ public class JarVisitorFactory {
* get the URL from a given path string
*
* @throws IllegalArgumentException is something goes wrong
- * TODO move to a ScannerHelper service?
*/
public static URL getURLFromPath(String jarPath) {
URL jarUrl;
@@ -134,70 +131,40 @@ public class JarVisitorFactory {
return jarUrl;
}
- /**
- * Get a JarVisitor to the jar jarPath
applying the given filters
- *
- * Method used in a non-managed environment
- *
- * @throws IllegalArgumentException if the jarPath is incorrect
- */
- public static JarVisitor getVisitor(String jarPath, Filter[] filters) throws IllegalArgumentException {
- File file = new File( jarPath );
- if ( file.isFile() ) {
- return new InputStreamZippedJarVisitor( jarPath, filters );
+ public static String unqualifiedJarFileName(URL jarUrl) {
+ // todo : weak algorithm subject to AOOBE
+ String fileName = jarUrl.getFile();
+ int exclamation = fileName.lastIndexOf( "!" );
+ if (exclamation != -1) {
+ fileName = fileName.substring( 0, exclamation );
}
- else {
- return new ExplodedJarVisitor( jarPath, filters );
+
+ int slash = fileName.lastIndexOf( "/" );
+ if ( slash != -1 ) {
+ fileName = fileName.substring(
+ fileName.lastIndexOf( "/" ) + 1,
+ fileName.length()
+ );
+ }
+
+ if ( fileName.length() > 4 && fileName.endsWith( "ar" ) && fileName.charAt( fileName.length() - 4 ) == '.' ) {
+ fileName = fileName.substring( 0, fileName.length() - 4 );
+ }
+
+ return fileName;
+ }
+
+ public static byte[] getBytesFromInputStreamSafely(InputStream inputStream) {
+ try {
+ return getBytesFromInputStream( inputStream );
+ }
+ catch (IOException e) {
+ throw new ArchiveException( "Unable to extract bytes from InputStream", e );
}
}
- /**
- * Build a JarVisitor on the given JAR URL applying the given filters
- *
- * @throws IllegalArgumentException if the URL is malformed
- */
- public static JarVisitor getVisitor(URL jarUrl, Filter[] filters) throws IllegalArgumentException {
- return getVisitor( jarUrl, filters, "" );
- }
-
- public static JarVisitor getVisitor(URL jarUrl, Filter[] filters, String entry) throws IllegalArgumentException {
- String protocol = jarUrl.getProtocol();
- if ( "jar".equals( protocol ) ) {
- return new JarProtocolVisitor( jarUrl, filters, entry );
- }
- else if ( StringHelper.isEmpty( protocol ) || "file".equals( protocol ) || "vfszip".equals( protocol ) || "vfsfile".equals( protocol ) ) {
- File file;
- try {
- final String filePart = jarUrl.getFile();
- if ( filePart != null && filePart.indexOf( ' ' ) != -1 ) {
- //unescaped (from the container), keep as is
- file = new File( jarUrl.getFile() );
- }
- else {
- file = new File( jarUrl.toURI().getSchemeSpecificPart() );
- }
- }
- catch (URISyntaxException e) {
- throw new IllegalArgumentException(
- "Unable to visit JAR " + jarUrl + ". Cause: " + e.getMessage(), e
- );
- }
-
- if ( file.isDirectory() ) {
- return new ExplodedJarVisitor( jarUrl, filters, entry );
- }
- else {
- return new FileZippedJarVisitor( jarUrl, filters, entry );
- }
- }
- else {
- //let's assume the url can return the jar as a zip stream
- return new InputStreamZippedJarVisitor( jarUrl, filters, entry );
- }
- }
-
- // Optimized by HHH-7835
public static byte[] getBytesFromInputStream(InputStream inputStream) throws IOException {
+ // Optimized by HHH-7835
int size;
List data = new LinkedList();
int bufferSize = 4096;
diff --git a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/boot/archive/internal/ExplodedArchiveDescriptor.java b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/boot/archive/internal/ExplodedArchiveDescriptor.java
new file mode 100644
index 0000000000..50a64a1a2f
--- /dev/null
+++ b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/boot/archive/internal/ExplodedArchiveDescriptor.java
@@ -0,0 +1,212 @@
+/*
+ * 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.jpa.boot.archive.internal;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.util.Enumeration;
+import java.util.jar.JarFile;
+import java.util.zip.ZipEntry;
+
+import org.jboss.logging.Logger;
+
+import org.hibernate.jpa.boot.archive.spi.AbstractArchiveDescriptor;
+import org.hibernate.jpa.boot.archive.spi.ArchiveContext;
+import org.hibernate.jpa.boot.archive.spi.ArchiveDescriptorFactory;
+import org.hibernate.jpa.boot.archive.spi.ArchiveEntry;
+import org.hibernate.jpa.boot.archive.spi.ArchiveException;
+import org.hibernate.jpa.boot.internal.FileInputStreamAccess;
+import org.hibernate.jpa.boot.spi.InputStreamAccess;
+import org.hibernate.jpa.internal.EntityManagerMessageLogger;
+
+/**
+ * @author Steve Ebersole
+ */
+public class ExplodedArchiveDescriptor extends AbstractArchiveDescriptor {
+ private static final EntityManagerMessageLogger LOG = Logger.getMessageLogger(
+ EntityManagerMessageLogger.class,
+ ExplodedArchiveDescriptor.class.getName()
+ );
+
+ public ExplodedArchiveDescriptor(
+ ArchiveDescriptorFactory archiveDescriptorFactory,
+ URL archiveUrl,
+ String entryBasePrefix) {
+ super( archiveDescriptorFactory, archiveUrl, entryBasePrefix );
+ }
+
+ @Override
+ public void visitArchive(ArchiveContext context) {
+ final File rootDirectory = resolveRootDirectory();
+ if ( rootDirectory == null ) {
+ return;
+ }
+
+ if ( rootDirectory.isDirectory() ) {
+ processDirectory( rootDirectory, null, context );
+ }
+ else {
+ //assume zipped file
+ processZippedRoot( rootDirectory, context );
+ }
+ }
+
+ private File resolveRootDirectory() {
+ final File archiveUrlDirectory;
+ try {
+ final String filePart = getArchiveUrl().getFile();
+ if ( filePart != null && filePart.indexOf( ' ' ) != -1 ) {
+ //unescaped (from the container), keep as is
+ archiveUrlDirectory = new File( filePart );
+ }
+ else {
+ archiveUrlDirectory = new File( getArchiveUrl().toURI().getSchemeSpecificPart() );
+ }
+ }
+ catch (URISyntaxException e) {
+ LOG.malformedUrl( getArchiveUrl(), e );
+ return null;
+ }
+
+ if ( !archiveUrlDirectory.exists() ) {
+ LOG.explodedJarDoesNotExist( getArchiveUrl() );
+ return null;
+ }
+ if ( !archiveUrlDirectory.isDirectory() ) {
+ LOG.explodedJarNotDirectory( getArchiveUrl() );
+ return null;
+ }
+
+ final String entryBase = getEntryBasePrefix();
+ if ( entryBase != null && entryBase.length() > 0 && ! "/".equals( entryBase ) ) {
+ return new File( archiveUrlDirectory, entryBase );
+ }
+ else {
+ return archiveUrlDirectory;
+ }
+ }
+
+ private void processDirectory(
+ File directory,
+ String path,
+ ArchiveContext context) {
+ if ( directory == null ) {
+ return;
+ }
+
+ final File[] files = directory.listFiles();
+ if ( files == null ) {
+ return;
+ }
+
+ path = path == null ? "" : path + "/";
+ for ( final File localFile : files ) {
+ if ( !localFile.exists() ) {
+ // should never happen conceptually, but...
+ continue;
+ }
+
+ if ( localFile.isDirectory() ) {
+ processDirectory( localFile, path + localFile.getName(), context );
+ continue;
+ }
+
+ final String name = localFile.getAbsolutePath();
+ final String relativeName = path + localFile.getName();
+ final InputStreamAccess inputStreamAccess = new FileInputStreamAccess( name, localFile );
+
+ final ArchiveEntry entry = new ArchiveEntry() {
+ @Override
+ public String getName() {
+ return name;
+ }
+
+ @Override
+ public String getNameWithinArchive() {
+ return relativeName;
+ }
+
+ @Override
+ public InputStreamAccess getStreamAccess() {
+ return inputStreamAccess;
+ }
+ };
+
+ context.obtainArchiveEntryHandler( entry ).handleEntry( entry, context );
+ }
+ }
+
+ private void processZippedRoot(File rootFile, ArchiveContext context) {
+ try {
+ final JarFile jarFile = new JarFile(rootFile);
+ final Enumeration extends ZipEntry> entries = jarFile.entries();
+ while ( entries.hasMoreElements() ) {
+ final ZipEntry zipEntry = entries.nextElement();
+ if ( zipEntry.isDirectory() ) {
+ continue;
+ }
+
+ final String name = extractName( zipEntry );
+ final String relativeName = extractRelativeName( zipEntry );
+ final InputStreamAccess inputStreamAccess;
+ try {
+ inputStreamAccess = buildByteBasedInputStreamAccess( name, jarFile.getInputStream( zipEntry ) );
+ }
+ catch (IOException e) {
+ throw new ArchiveException(
+ String.format(
+ "Unable to access stream from jar file [%s] for entry [%s]",
+ jarFile.getName(),
+ zipEntry.getName()
+ )
+ );
+ }
+
+ final ArchiveEntry entry = new ArchiveEntry() {
+ @Override
+ public String getName() {
+ return name;
+ }
+
+ @Override
+ public String getNameWithinArchive() {
+ return relativeName;
+ }
+
+ @Override
+ public InputStreamAccess getStreamAccess() {
+ return inputStreamAccess;
+ }
+ };
+ context.obtainArchiveEntryHandler( entry ).handleEntry( entry, context );
+ }
+ }
+ catch (IOException e) {
+ throw new ArchiveException( "Error accessing jar file [" + rootFile.getAbsolutePath() + "]", e );
+ }
+ }
+
+}
diff --git a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/boot/archive/internal/JarFileBasedArchiveDescriptor.java b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/boot/archive/internal/JarFileBasedArchiveDescriptor.java
new file mode 100644
index 0000000000..d601d69ae2
--- /dev/null
+++ b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/boot/archive/internal/JarFileBasedArchiveDescriptor.java
@@ -0,0 +1,193 @@
+/*
+ * 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.jpa.boot.archive.internal;
+
+import java.io.BufferedInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.util.Enumeration;
+import java.util.jar.JarFile;
+import java.util.jar.JarInputStream;
+import java.util.zip.ZipEntry;
+
+import org.jboss.logging.Logger;
+
+import org.hibernate.jpa.boot.archive.spi.AbstractArchiveDescriptor;
+import org.hibernate.jpa.boot.archive.spi.ArchiveContext;
+import org.hibernate.jpa.boot.archive.spi.ArchiveDescriptorFactory;
+import org.hibernate.jpa.boot.archive.spi.ArchiveEntry;
+import org.hibernate.jpa.boot.archive.spi.ArchiveEntryHandler;
+import org.hibernate.jpa.boot.archive.spi.ArchiveException;
+import org.hibernate.jpa.internal.EntityManagerMessageLogger;
+import org.hibernate.jpa.boot.spi.InputStreamAccess;
+
+/**
+ * An ArchiveDescriptor implementation leveraging the {@link JarFile} API for processing.
+ *
+ * @author Steve Ebersole
+ */
+public class JarFileBasedArchiveDescriptor extends AbstractArchiveDescriptor {
+ private static final EntityManagerMessageLogger LOG = Logger.getMessageLogger(
+ EntityManagerMessageLogger.class,
+ JarFileBasedArchiveDescriptor.class.getName()
+ );
+
+ public JarFileBasedArchiveDescriptor(
+ ArchiveDescriptorFactory archiveDescriptorFactory,
+ URL archiveUrl,
+ String entry) {
+ super( archiveDescriptorFactory, archiveUrl, entry );
+ }
+
+ @Override
+ public void visitArchive(ArchiveContext context) {
+ final JarFile jarFile = resolveJarFileReference();
+ if ( jarFile == null ) {
+ return;
+ }
+
+ final Enumeration extends ZipEntry> zipEntries = jarFile.entries();
+ while ( zipEntries.hasMoreElements() ) {
+ final ZipEntry zipEntry = zipEntries.nextElement();
+ final String entryName = extractName( zipEntry );
+
+ if ( getEntryBasePrefix() != null && ! entryName.startsWith( getEntryBasePrefix() ) ) {
+ continue;
+ }
+ if ( zipEntry.isDirectory() ) {
+ continue;
+ }
+
+ if ( entryName.equals( getEntryBasePrefix() ) ) {
+ // exact match, might be a nested jar entry (ie from jar:file:..../foo.ear!/bar.jar)
+ //
+ // This algorithm assumes that the zipped file is only the URL root (including entry), not
+ // just any random entry
+ try {
+ InputStream is = new BufferedInputStream( jarFile.getInputStream( zipEntry ) );
+ try {
+ final JarInputStream jarInputStream = new JarInputStream( is );
+ ZipEntry subZipEntry = jarInputStream.getNextEntry();
+ while ( subZipEntry != null ) {
+ if ( ! subZipEntry.isDirectory() ) {
+
+ final String name = extractName( subZipEntry );
+ final String relativeName = extractRelativeName( subZipEntry );
+ final InputStreamAccess inputStreamAccess
+ = buildByteBasedInputStreamAccess( name, jarInputStream );
+
+ final ArchiveEntry entry = new ArchiveEntry() {
+ @Override
+ public String getName() {
+ return name;
+ }
+
+ @Override
+ public String getNameWithinArchive() {
+ return relativeName;
+ }
+
+ @Override
+ public InputStreamAccess getStreamAccess() {
+ return inputStreamAccess;
+ }
+ };
+
+ final ArchiveEntryHandler entryHandler = context.obtainArchiveEntryHandler( entry );
+ entryHandler.handleEntry( entry, context );
+ }
+
+ subZipEntry = jarInputStream.getNextEntry();
+ }
+ }
+ finally {
+ is.close();
+ }
+ }
+ catch (Exception e) {
+ throw new ArchiveException( "Error accessing JarFile entry [" + zipEntry.getName() + "]", e );
+ }
+ }
+ else {
+ final String name = extractName( zipEntry );
+ final String relativeName = extractRelativeName( zipEntry );
+ final InputStreamAccess inputStreamAccess;
+ try {
+ inputStreamAccess = buildByteBasedInputStreamAccess( name, jarFile.getInputStream( zipEntry ) );
+ }
+ catch (IOException e) {
+ throw new ArchiveException(
+ String.format(
+ "Unable to access stream from jar file [%s] for entry [%s]",
+ jarFile.getName(),
+ zipEntry.getName()
+ )
+ );
+ }
+
+ final ArchiveEntry entry = new ArchiveEntry() {
+ @Override
+ public String getName() {
+ return name;
+ }
+
+ @Override
+ public String getNameWithinArchive() {
+ return relativeName;
+ }
+
+ @Override
+ public InputStreamAccess getStreamAccess() {
+ return inputStreamAccess;
+ }
+ };
+
+ final ArchiveEntryHandler entryHandler = context.obtainArchiveEntryHandler( entry );
+ entryHandler.handleEntry( entry, context );
+ }
+ }
+ }
+
+ private JarFile resolveJarFileReference() {
+ try {
+ String filePart = getArchiveUrl().getFile();
+ if ( filePart != null && filePart.indexOf( ' ' ) != -1 ) {
+ // unescaped (from the container), keep as is
+ return new JarFile( getArchiveUrl().getFile() );
+ }
+ else {
+ return new JarFile( getArchiveUrl().toURI().getSchemeSpecificPart() );
+ }
+ }
+ catch (IOException e) {
+ LOG.unableToFindFile( getArchiveUrl(), e );
+ }
+ catch (URISyntaxException e) {
+ LOG.malformedUrlWarning( getArchiveUrl(), e );
+ }
+ return null;
+ }
+}
diff --git a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/boot/archive/internal/JarInputStreamBasedArchiveDescriptor.java b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/boot/archive/internal/JarInputStreamBasedArchiveDescriptor.java
new file mode 100644
index 0000000000..3b7b338535
--- /dev/null
+++ b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/boot/archive/internal/JarInputStreamBasedArchiveDescriptor.java
@@ -0,0 +1,168 @@
+/*
+ * 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.jpa.boot.archive.internal;
+
+import java.io.IOException;
+import java.net.URL;
+import java.util.jar.JarEntry;
+import java.util.jar.JarInputStream;
+import java.util.zip.ZipEntry;
+
+import org.jboss.logging.Logger;
+
+import org.hibernate.jpa.boot.archive.spi.AbstractArchiveDescriptor;
+import org.hibernate.jpa.boot.archive.spi.ArchiveContext;
+import org.hibernate.jpa.boot.archive.spi.ArchiveDescriptorFactory;
+import org.hibernate.jpa.boot.archive.spi.ArchiveEntry;
+import org.hibernate.jpa.boot.archive.spi.ArchiveException;
+import org.hibernate.jpa.boot.spi.InputStreamAccess;
+import org.hibernate.jpa.internal.EntityManagerMessageLogger;
+
+/**
+ * An ArchiveDescriptor implementation that works on archives accessible through a {@link java.util.jar.JarInputStream}.
+ * NOTE : This is less efficient implementation than {@link JarFileBasedArchiveDescriptor}
+ *
+ * @author Emmanuel Bernard
+ * @author Steve Ebersole
+ */
+public class JarInputStreamBasedArchiveDescriptor extends AbstractArchiveDescriptor {
+ private static final EntityManagerMessageLogger LOG = Logger.getMessageLogger(
+ EntityManagerMessageLogger.class,
+ JarInputStreamBasedArchiveDescriptor.class.getName()
+ );
+
+ public JarInputStreamBasedArchiveDescriptor(
+ ArchiveDescriptorFactory archiveDescriptorFactory,
+ URL url,
+ String entry) {
+ super( archiveDescriptorFactory, url, entry );
+ }
+
+ @Override
+ public void visitArchive(ArchiveContext context) {
+ final JarInputStream jarInputStream;
+ try {
+ jarInputStream = new JarInputStream( getArchiveUrl().openStream() );
+ }
+ catch (Exception e) {
+ //really should catch IOException but Eclipse is buggy and raise NPE...
+ LOG.unableToFindFile( getArchiveUrl(), e );
+ return;
+ }
+
+ try {
+ JarEntry jarEntry;
+ while ( ( jarEntry = jarInputStream.getNextJarEntry() ) != null ) {
+ String jarEntryName = jarEntry.getName();
+ if ( getEntryBasePrefix() != null && ! jarEntryName.startsWith( getEntryBasePrefix() ) ) {
+ continue;
+ }
+
+ if ( jarEntry.isDirectory() ) {
+ continue;
+ }
+
+ if ( jarEntryName.equals( getEntryBasePrefix() ) ) {
+ // exact match, might be a nested jar entry (ie from jar:file:..../foo.ear!/bar.jar)
+ //
+ // This algorithm assumes that the zipped file is only the URL root (including entry), not
+ // just any random entry
+ try {
+ final JarInputStream subJarInputStream = new JarInputStream( jarInputStream );
+ try {
+ ZipEntry subZipEntry = jarInputStream.getNextEntry();
+ while (subZipEntry != null) {
+ if ( ! subZipEntry.isDirectory() ) {
+ final String subName = extractName( subZipEntry );
+ final InputStreamAccess inputStreamAccess
+ = buildByteBasedInputStreamAccess( subName, subJarInputStream );
+
+ final ArchiveEntry entry = new ArchiveEntry() {
+ @Override
+ public String getName() {
+ return subName;
+ }
+
+ @Override
+ public String getNameWithinArchive() {
+ return subName;
+ }
+
+ @Override
+ public InputStreamAccess getStreamAccess() {
+ return inputStreamAccess;
+ }
+ };
+
+ context.obtainArchiveEntryHandler( entry ).handleEntry( entry, context );
+ }
+ subZipEntry = jarInputStream.getNextJarEntry();
+ }
+ }
+ finally {
+ subJarInputStream.close();
+ }
+ }
+ catch (Exception e) {
+ throw new ArchiveException( "Error accessing nested jar", e );
+ }
+ }
+ else {
+ final String entryName = extractName( jarEntry );
+ final InputStreamAccess inputStreamAccess
+ = buildByteBasedInputStreamAccess( entryName, jarInputStream );
+
+ final String relativeName = extractRelativeName( jarEntry );
+
+ final ArchiveEntry entry = new ArchiveEntry() {
+ @Override
+ public String getName() {
+ return entryName;
+ }
+
+ @Override
+ public String getNameWithinArchive() {
+ return relativeName;
+ }
+
+ @Override
+ public InputStreamAccess getStreamAccess() {
+ return inputStreamAccess;
+ }
+ };
+
+ context.obtainArchiveEntryHandler( entry ).handleEntry( entry, context );
+ }
+ }
+
+ jarInputStream.close();
+ }
+ catch (IOException ioe) {
+ throw new ArchiveException(
+ String.format( "Error accessing JarInputStream [%s]", getArchiveUrl() ),
+ ioe
+ );
+ }
+ }
+}
diff --git a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/boot/archive/internal/JarProtocolArchiveDescriptor.java b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/boot/archive/internal/JarProtocolArchiveDescriptor.java
new file mode 100644
index 0000000000..4eaa7d8748
--- /dev/null
+++ b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/boot/archive/internal/JarProtocolArchiveDescriptor.java
@@ -0,0 +1,71 @@
+/*
+ * 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.jpa.boot.archive.internal;
+
+import java.net.URL;
+
+import org.hibernate.annotations.common.AssertionFailure;
+import org.hibernate.jpa.boot.archive.spi.ArchiveContext;
+import org.hibernate.jpa.boot.archive.spi.ArchiveDescriptor;
+import org.hibernate.jpa.boot.archive.spi.ArchiveDescriptorFactory;
+
+/**
+ * An ArchiveDescriptor implementation for handling archives whose url reported a JAR protocol (i.e., jar://).
+ *
+ * @author Steve Ebersole
+ */
+public class JarProtocolArchiveDescriptor implements ArchiveDescriptor {
+ private final ArchiveDescriptor delegateDescriptor;
+
+ public JarProtocolArchiveDescriptor(
+ ArchiveDescriptorFactory archiveDescriptorFactory,
+ URL url,
+ String incomingEntry) {
+ if ( incomingEntry != null && incomingEntry.length() > 0 ) {
+ throw new IllegalArgumentException( "jar:jar: not supported: " + url );
+ }
+
+ final String urlFile = url.getFile();
+ final int subEntryIndex = urlFile.lastIndexOf( "!" );
+ if ( subEntryIndex == -1 ) {
+ throw new AssertionFailure( "JAR URL does not contain '!/' :" + url );
+ }
+
+ final String subEntry;
+ if ( subEntryIndex + 1 >= urlFile.length() ) {
+ subEntry = "";
+ }
+ else {
+ subEntry = urlFile.substring( subEntryIndex + 1 );
+ }
+
+ URL fileUrl = archiveDescriptorFactory.getJarURLFromURLEntry( url, subEntry );
+ delegateDescriptor = archiveDescriptorFactory.buildArchiveDescriptor( fileUrl, subEntry );
+ }
+
+ @Override
+ public void visitArchive(ArchiveContext context) {
+ delegateDescriptor.visitArchive( context );
+ }
+}
diff --git a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/boot/archive/internal/StandardArchiveDescriptorFactory.java b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/boot/archive/internal/StandardArchiveDescriptorFactory.java
new file mode 100644
index 0000000000..e502570140
--- /dev/null
+++ b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/boot/archive/internal/StandardArchiveDescriptorFactory.java
@@ -0,0 +1,105 @@
+/*
+ * 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.jpa.boot.archive.internal;
+
+import java.io.File;
+import java.net.URISyntaxException;
+import java.net.URL;
+
+import org.hibernate.internal.util.StringHelper;
+import org.hibernate.jpa.boot.archive.spi.ArchiveDescriptor;
+import org.hibernate.jpa.boot.archive.spi.ArchiveDescriptorFactory;
+
+/**
+ * @author Emmanuel Bernard
+ * @author Steve Ebersole
+ */
+public class StandardArchiveDescriptorFactory implements ArchiveDescriptorFactory {
+ public static final StandardArchiveDescriptorFactory INSTANCE = new StandardArchiveDescriptorFactory();
+
+ @Override
+ public ArchiveDescriptor buildArchiveDescriptor(URL url) {
+ return buildArchiveDescriptor( url, "" );
+ }
+
+ @Override
+ public ArchiveDescriptor buildArchiveDescriptor(URL url, String entry) {
+ final String protocol = url.getProtocol();
+ if ( "jar".equals( protocol ) ) {
+ return new JarProtocolArchiveDescriptor( this, url, entry );
+ }
+ else if ( StringHelper.isEmpty( protocol )
+ || "file".equals( protocol )
+ || "vfszip".equals( protocol )
+ || "vfsfile".equals( protocol ) ) {
+ final File file;
+ try {
+ final String filePart = url.getFile();
+ if ( filePart != null && filePart.indexOf( ' ' ) != -1 ) {
+ //unescaped (from the container), keep as is
+ file = new File( url.getFile() );
+ }
+ else {
+ file = new File( url.toURI().getSchemeSpecificPart() );
+ }
+
+ if ( ! file.exists() ) {
+ throw new IllegalArgumentException(
+ String.format(
+ "File [%s] referenced by given URL [%s] does not exist",
+ filePart,
+ url.toExternalForm()
+ )
+ );
+ }
+ }
+ catch (URISyntaxException e) {
+ throw new IllegalArgumentException(
+ "Unable to visit JAR " + url + ". Cause: " + e.getMessage(), e
+ );
+ }
+
+ if ( file.isDirectory() ) {
+ return new ExplodedArchiveDescriptor( this, url, entry );
+ }
+ else {
+ return new JarFileBasedArchiveDescriptor( this, url, entry );
+ }
+ }
+ else {
+ //let's assume the url can return the jar as a zip stream
+ return new JarInputStreamBasedArchiveDescriptor( this, url, entry );
+ }
+ }
+
+ @Override
+ public URL getJarURLFromURLEntry(URL url, String entry) throws IllegalArgumentException {
+ return ArchiveHelper.getJarURLFromURLEntry( url, entry );
+ }
+
+ @Override
+ public URL getURLFromPath(String jarPath) {
+ return ArchiveHelper.getURLFromPath( jarPath );
+ }
+}
diff --git a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/boot/archive/spi/AbstractArchiveDescriptor.java b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/boot/archive/spi/AbstractArchiveDescriptor.java
new file mode 100644
index 0000000000..00f92c6a0b
--- /dev/null
+++ b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/boot/archive/spi/AbstractArchiveDescriptor.java
@@ -0,0 +1,92 @@
+/*
+ * 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.jpa.boot.archive.spi;
+
+import java.io.InputStream;
+import java.net.URL;
+import java.util.zip.ZipEntry;
+
+import org.hibernate.internal.util.StringHelper;
+import org.hibernate.jpa.boot.internal.ByteArrayInputStreamAccess;
+import org.hibernate.jpa.boot.archive.internal.ArchiveHelper;
+import org.hibernate.jpa.boot.spi.InputStreamAccess;
+
+/**
+ * @author Steve Ebersole
+ */
+public abstract class AbstractArchiveDescriptor implements ArchiveDescriptor {
+ private final ArchiveDescriptorFactory archiveDescriptorFactory;
+ private final URL archiveUrl;
+ private final String entryBasePrefix;
+
+ protected AbstractArchiveDescriptor(
+ ArchiveDescriptorFactory archiveDescriptorFactory,
+ URL archiveUrl,
+ String entryBasePrefix) {
+ this.archiveDescriptorFactory = archiveDescriptorFactory;
+ this.archiveUrl = archiveUrl;
+ this.entryBasePrefix = normalizeEntryBasePrefix( entryBasePrefix );
+ }
+
+ private static String normalizeEntryBasePrefix(String entryBasePrefix) {
+ if ( StringHelper.isEmpty( entryBasePrefix ) || entryBasePrefix.length() == 1 ) {
+ return null;
+ }
+
+ return entryBasePrefix.startsWith( "/" ) ? entryBasePrefix.substring( 1 ) : entryBasePrefix;
+ }
+
+ protected ArchiveDescriptorFactory getArchiveDescriptorFactory() {
+ return archiveDescriptorFactory;
+ }
+
+ protected URL getArchiveUrl() {
+ return archiveUrl;
+ }
+
+ protected String getEntryBasePrefix() {
+ return entryBasePrefix;
+ }
+
+ protected String extractRelativeName(ZipEntry zipEntry) {
+ final String entryName = extractName( zipEntry );
+ return entryBasePrefix == null ? entryName : entryName.substring( entryBasePrefix.length() );
+ }
+
+ protected String extractName(ZipEntry zipEntry) {
+ return normalizePathName( zipEntry.getName() );
+ }
+
+ protected String normalizePathName(String pathName) {
+ return pathName.startsWith( "/" ) ? pathName.substring( 1 ) : pathName;
+ }
+
+ protected InputStreamAccess buildByteBasedInputStreamAccess(final String name, InputStream inputStream) {
+ // because of how jar InputStreams work we need to extract the bytes immediately. However, we
+ // do delay the creation of the ByteArrayInputStreams until needed
+ final byte[] bytes = ArchiveHelper.getBytesFromInputStreamSafely( inputStream );
+ return new ByteArrayInputStreamAccess( name, bytes );
+ }
+
+}
diff --git a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/boot/archive/spi/ArchiveContext.java b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/boot/archive/spi/ArchiveContext.java
new file mode 100644
index 0000000000..8674cc6bb5
--- /dev/null
+++ b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/boot/archive/spi/ArchiveContext.java
@@ -0,0 +1,37 @@
+/*
+ * 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.jpa.boot.archive.spi;
+
+import org.hibernate.jpa.boot.spi.PersistenceUnitDescriptor;
+
+/**
+* @author Steve Ebersole
+*/
+public interface ArchiveContext {
+ public PersistenceUnitDescriptor getPersistenceUnitDescriptor();
+
+ public boolean isRootUrl();
+
+ public ArchiveEntryHandler obtainArchiveEntryHandler(ArchiveEntry entry);
+}
diff --git a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/packaging/internal/Filter.java b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/boot/archive/spi/ArchiveDescriptor.java
similarity index 67%
rename from hibernate-entitymanager/src/main/java/org/hibernate/jpa/packaging/internal/Filter.java
rename to hibernate-entitymanager/src/main/java/org/hibernate/jpa/boot/archive/spi/ArchiveDescriptor.java
index 0d16548108..b9d07dee0d 100644
--- a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/packaging/internal/Filter.java
+++ b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/boot/archive/spi/ArchiveDescriptor.java
@@ -1,8 +1,10 @@
/*
- * Copyright (c) 2009, Red Hat Middleware LLC or third-party contributors as
+ * 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 Middleware LLC.
+ * 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
@@ -19,22 +21,14 @@
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
-package org.hibernate.jpa.packaging.internal;
-
+package org.hibernate.jpa.boot.archive.spi;
/**
- * Filter used when searching elements in a JAR
+ * Contract for visiting an archive, which might be a jar, a zip, an exploded directory, etc.
*
+ * @author Steve Ebersole
* @author Emmanuel Bernard
*/
-public abstract class Filter {
- private boolean retrieveStream;
-
- protected Filter(boolean retrieveStream) {
- this.retrieveStream = retrieveStream;
- }
-
- public boolean getStream() {
- return retrieveStream;
- }
+public interface ArchiveDescriptor {
+ public void visitArchive(ArchiveContext archiveContext);
}
diff --git a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/packaging/internal/FileFilter.java b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/boot/archive/spi/ArchiveDescriptorFactory.java
similarity index 58%
rename from hibernate-entitymanager/src/main/java/org/hibernate/jpa/packaging/internal/FileFilter.java
rename to hibernate-entitymanager/src/main/java/org/hibernate/jpa/boot/archive/spi/ArchiveDescriptorFactory.java
index 8c8575be3f..441b531b25 100644
--- a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/packaging/internal/FileFilter.java
+++ b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/boot/archive/spi/ArchiveDescriptorFactory.java
@@ -1,8 +1,10 @@
/*
- * Copyright (c) 2009, Red Hat Middleware LLC or third-party contributors as
+ * 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 Middleware LLC.
+ * 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
@@ -19,25 +21,19 @@
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
-package org.hibernate.jpa.packaging.internal;
+package org.hibernate.jpa.boot.archive.spi;
+import java.net.URL;
/**
- * Filter use to match a file by its name
+ * Contract for building ArchiveDescriptor instances.
*
- * @author Emmanuel Bernard
+ * @author Steve Ebersole
*/
-public abstract class FileFilter extends Filter {
+public interface ArchiveDescriptorFactory {
+ public ArchiveDescriptor buildArchiveDescriptor(URL url);
+ public ArchiveDescriptor buildArchiveDescriptor(URL jarUrl, String entry);
- /**
- * @param retrieveStream Give back an open stream to the matching element or not
- */
- public FileFilter(boolean retrieveStream) {
- super( retrieveStream );
- }
-
- /**
- * Return true if the fully qualified file name match
- */
- public abstract boolean accept(String name);
- }
\ No newline at end of file
+ public URL getJarURLFromURLEntry(URL url, String entry) throws IllegalArgumentException;
+ public URL getURLFromPath(String jarPath);
+}
diff --git a/hibernate-core/src/main/java/org/hibernate/internal/util/xml/Origin.java b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/boot/archive/spi/ArchiveEntry.java
similarity index 63%
rename from hibernate-core/src/main/java/org/hibernate/internal/util/xml/Origin.java
rename to hibernate-entitymanager/src/main/java/org/hibernate/jpa/boot/archive/spi/ArchiveEntry.java
index 805cdd8168..7d7e9185e0 100644
--- a/hibernate-core/src/main/java/org/hibernate/internal/util/xml/Origin.java
+++ b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/boot/archive/spi/ArchiveEntry.java
@@ -1,7 +1,7 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
- * Copyright (c) 2010, Red Hat Inc. or third-party contributors as
+ * 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.
@@ -21,29 +21,35 @@
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
-package org.hibernate.internal.util.xml;
+package org.hibernate.jpa.boot.archive.spi;
-import java.io.Serializable;
+import org.hibernate.jpa.boot.spi.InputStreamAccess;
/**
- * Describes the origin of an xml document
+ * Represent an entry in the archive.
*
* @author Steve Ebersole
*/
-public interface Origin extends Serializable {
+public interface ArchiveEntry {
/**
- * Retrieve the type of origin. This is not a discrete set, but might be somethign like
- * {@code file} for file protocol URLs, or {@code resource} for classpath resource lookups.
+ * Get the entry's name
*
- * @return The origin type.
- */
- public String getType();
-
- /**
- * The name of the document origin. Interpretation is relative to the type, but might be the
- * resource name or file URL.
- *
- * @return The name.
+ * @return
*/
public String getName();
+
+ /**
+ * Get the relative name of the entry within the archive. Typically what we are looking for here is
+ * the ClassLoader resource lookup name.
+ *
+ * @return
+ */
+ public String getNameWithinArchive();
+
+ /**
+ * Get access to the stream for the entry
+ *
+ * @return
+ */
+ public InputStreamAccess getStreamAccess();
}
diff --git a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/boot/archive/spi/ArchiveEntryHandler.java b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/boot/archive/spi/ArchiveEntryHandler.java
new file mode 100644
index 0000000000..3fce3402c0
--- /dev/null
+++ b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/boot/archive/spi/ArchiveEntryHandler.java
@@ -0,0 +1,33 @@
+/*
+ * 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.jpa.boot.archive.spi;
+
+/**
+ * Handler for archive entries, based on the classified type of the entry
+ *
+ * @author Steve Ebersole
+ */
+public interface ArchiveEntryHandler {
+ public void handleEntry(ArchiveEntry entry, ArchiveContext context);
+}
diff --git a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/packaging/internal/ClassFilter.java b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/boot/archive/spi/ArchiveException.java
similarity index 63%
rename from hibernate-entitymanager/src/main/java/org/hibernate/jpa/packaging/internal/ClassFilter.java
rename to hibernate-entitymanager/src/main/java/org/hibernate/jpa/boot/archive/spi/ArchiveException.java
index 6ea6dc08bb..1257502318 100644
--- a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/packaging/internal/ClassFilter.java
+++ b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/boot/archive/spi/ArchiveException.java
@@ -1,8 +1,10 @@
/*
- * Copyright (c) 2009, Red Hat Middleware LLC or third-party contributors as
+ * 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 Middleware LLC.
+ * 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
@@ -19,20 +21,19 @@
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
-package org.hibernate.jpa.packaging.internal;
+package org.hibernate.jpa.boot.archive.spi;
+import org.hibernate.HibernateException;
/**
- * Filter on class elements
- *
- * @author Emmanuel Bernard
- * @see JavaElementFilter
+ * @author Steve Ebersole
*/
-public abstract class ClassFilter extends JavaElementFilter {
- /**
- * @see JavaElementFilter#JavaElementFilter(boolean, Class[])
- */
- protected ClassFilter(boolean retrieveStream, Class[] annotations) {
- super( retrieveStream, annotations );
+public class ArchiveException extends HibernateException {
+ public ArchiveException(String message) {
+ super( message );
}
-}
\ No newline at end of file
+
+ public ArchiveException(String message, Throwable root) {
+ super( message, root );
+ }
+}
diff --git a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/boot/internal/ByteArrayInputStreamAccess.java b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/boot/internal/ByteArrayInputStreamAccess.java
new file mode 100644
index 0000000000..8b949206ce
--- /dev/null
+++ b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/boot/internal/ByteArrayInputStreamAccess.java
@@ -0,0 +1,60 @@
+/*
+ * 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.jpa.boot.internal;
+
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+
+import org.hibernate.jpa.boot.spi.InputStreamAccess;
+import org.hibernate.jpa.boot.spi.NamedInputStream;
+
+/**
+ * An InputStreamAccess implementation based on a byte array
+ *
+ * @author Steve Ebersole
+ */
+public class ByteArrayInputStreamAccess implements InputStreamAccess {
+ private final String name;
+ private final byte[] bytes;
+
+ public ByteArrayInputStreamAccess(String name, byte[] bytes) {
+ this.name = name;
+ this.bytes = bytes;
+ }
+
+ @Override
+ public String getStreamName() {
+ return name;
+ }
+
+ @Override
+ public InputStream accessInputStream() {
+ return new ByteArrayInputStream( bytes );
+ }
+
+ @Override
+ public NamedInputStream asNamedInputStream() {
+ return new NamedInputStream( getStreamName(), accessInputStream() );
+ }
+}
diff --git a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/packaging/internal/Entry.java b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/boot/internal/ClassDescriptorImpl.java
similarity index 53%
rename from hibernate-entitymanager/src/main/java/org/hibernate/jpa/packaging/internal/Entry.java
rename to hibernate-entitymanager/src/main/java/org/hibernate/jpa/boot/internal/ClassDescriptorImpl.java
index 584bfcb15c..f8d15c1419 100644
--- a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/packaging/internal/Entry.java
+++ b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/boot/internal/ClassDescriptorImpl.java
@@ -1,8 +1,10 @@
/*
- * Copyright (c) 2009, Red Hat Middleware LLC or third-party contributors as
+ * 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 Middleware LLC.
+ * 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
@@ -19,44 +21,48 @@
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
-package org.hibernate.jpa.packaging.internal;
-import java.io.InputStream;
+package org.hibernate.jpa.boot.internal;
+
+import org.hibernate.jpa.boot.spi.ClassDescriptor;
+import org.hibernate.jpa.boot.spi.InputStreamAccess;
/**
- * Represent a JAR entry
- * Contains a name and an optional Input stream to the entry
- *
- * @author Emmanuel Bernard
+ * @author Steve Ebersole
*/
-public class Entry {
- private String name;
- private InputStream is;
+public class ClassDescriptorImpl implements ClassDescriptor {
+ private final String name;
+ private final InputStreamAccess streamAccess;
- public Entry(String name, InputStream is) {
+ public ClassDescriptorImpl(String name, InputStreamAccess streamAccess) {
this.name = name;
- this.is = is;
+ this.streamAccess = streamAccess;
}
+ @Override
public String getName() {
return name;
}
- public InputStream getInputStream() {
- return is;
+ @Override
+ public InputStreamAccess getStreamAccess() {
+ return streamAccess;
}
+ @Override
public boolean equals(Object o) {
- if ( this == o ) return true;
- if ( o == null || getClass() != o.getClass() ) return false;
+ if ( this == o ) {
+ return true;
+ }
+ if ( o == null || getClass() != o.getClass() ) {
+ return false;
+ }
- final Entry entry = (Entry) o;
-
- if ( !name.equals( entry.name ) ) return false;
-
- return true;
+ ClassDescriptorImpl that = (ClassDescriptorImpl) o;
+ return name.equals( that.name );
}
+ @Override
public int hashCode() {
return name.hashCode();
}
-}
\ No newline at end of file
+}
diff --git a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/boot/internal/EntityManagerFactoryBuilderImpl.java b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/boot/internal/EntityManagerFactoryBuilderImpl.java
index fcf6f01d2a..f57d43652f 100644
--- a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/boot/internal/EntityManagerFactoryBuilderImpl.java
+++ b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/boot/internal/EntityManagerFactoryBuilderImpl.java
@@ -23,12 +23,17 @@
*/
package org.hibernate.jpa.boot.internal;
+import javax.persistence.AttributeConverter;
+import javax.persistence.EntityManagerFactory;
+import javax.persistence.EntityNotFoundException;
+import javax.persistence.PersistenceException;
+import javax.persistence.spi.PersistenceUnitTransactionType;
+import javax.sql.DataSource;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.Serializable;
-import java.lang.annotation.Annotation;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
@@ -42,18 +47,18 @@ import java.util.Properties;
import java.util.Set;
import java.util.StringTokenizer;
-import javax.persistence.AttributeConverter;
-import javax.persistence.Converter;
-import javax.persistence.Embeddable;
-import javax.persistence.Entity;
-import javax.persistence.EntityManagerFactory;
-import javax.persistence.EntityNotFoundException;
-import javax.persistence.MappedSuperclass;
-import javax.persistence.PersistenceException;
-import javax.persistence.spi.PersistenceUnitTransactionType;
-import javax.sql.DataSource;
+import org.jboss.jandex.AnnotationInstance;
+import org.jboss.jandex.ClassInfo;
+import org.jboss.jandex.CompositeIndex;
+import org.jboss.jandex.DotName;
+import org.jboss.jandex.Index;
+import org.jboss.jandex.IndexView;
+import org.jboss.jandex.Indexer;
+
+import org.jboss.logging.Logger;
import org.hibernate.Interceptor;
+import org.hibernate.InvalidMappingException;
import org.hibernate.MappingException;
import org.hibernate.MappingNotFoundException;
import org.hibernate.SessionFactory;
@@ -86,29 +91,29 @@ import org.hibernate.jpa.boot.spi.IntegratorProvider;
import org.hibernate.jpa.boot.spi.JpaUnifiedSettingsBuilder;
import org.hibernate.jpa.boot.spi.PersistenceUnitDescriptor;
import org.hibernate.jpa.event.spi.JpaIntegrator;
-import org.hibernate.jpa.internal.schemagen.JpaSchemaGenerator;
import org.hibernate.jpa.internal.EntityManagerFactoryImpl;
import org.hibernate.jpa.internal.EntityManagerMessageLogger;
+import org.hibernate.jpa.internal.schemagen.JpaSchemaGenerator;
import org.hibernate.jpa.internal.util.LogHelper;
import org.hibernate.jpa.internal.util.PersistenceUnitTransactionTypeHelper;
-import org.hibernate.jpa.packaging.internal.NativeScanner;
-import org.hibernate.jpa.packaging.spi.NamedInputStream;
-import org.hibernate.jpa.packaging.spi.Scanner;
+import org.hibernate.jpa.boot.scan.internal.StandardScanOptions;
+import org.hibernate.jpa.boot.scan.internal.StandardScanner;
+import org.hibernate.jpa.boot.spi.ClassDescriptor;
+import org.hibernate.jpa.boot.spi.InputStreamAccess;
+import org.hibernate.jpa.boot.spi.MappingFileDescriptor;
+import org.hibernate.jpa.boot.spi.NamedInputStream;
+import org.hibernate.jpa.boot.spi.PackageDescriptor;
+import org.hibernate.jpa.boot.scan.spi.ScanOptions;
+import org.hibernate.jpa.boot.scan.spi.ScanResult;
+import org.hibernate.jpa.boot.scan.spi.Scanner;
import org.hibernate.jpa.spi.IdentifierGeneratorStrategyProvider;
+import org.hibernate.metamodel.MetadataSources;
import org.hibernate.metamodel.internal.source.annotations.util.JPADotNames;
import org.hibernate.metamodel.internal.source.annotations.util.JandexHelper;
import org.hibernate.proxy.EntityNotFoundDelegate;
import org.hibernate.secure.internal.JACCConfiguration;
import org.hibernate.service.ServiceRegistry;
import org.hibernate.service.spi.ServiceRegistryImplementor;
-import org.jboss.jandex.AnnotationInstance;
-import org.jboss.jandex.ClassInfo;
-import org.jboss.jandex.CompositeIndex;
-import org.jboss.jandex.DotName;
-import org.jboss.jandex.Index;
-import org.jboss.jandex.IndexView;
-import org.jboss.jandex.Indexer;
-import org.jboss.logging.Logger;
/**
* @author Steve Ebersole
@@ -203,13 +208,14 @@ public class EntityManagerFactoryBuilderImpl implements EntityManagerFactoryBuil
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Next we do a preliminary pass at metadata processing, which involves:
// 1) scanning
- ScanResult scanResult = scan( bootstrapServiceRegistry );
+ final ScanResult scanResult = scan( bootstrapServiceRegistry );
+ final DeploymentResources deploymentResources = buildDeploymentResources( scanResult, bootstrapServiceRegistry );
// 2) building a Jandex index
- Set collectedManagedClassNames = collectManagedClassNames( scanResult );
- IndexView jandexIndex = locateOrBuildJandexIndex( collectedManagedClassNames, scanResult.getPackageNames(), bootstrapServiceRegistry );
+ final IndexView jandexIndex = locateOrBuildJandexIndex( deploymentResources );
// 3) building "metadata sources" to keep for later to use in building the SessionFactory
- metadataSources = prepareMetadataSources( jandexIndex, collectedManagedClassNames, scanResult, bootstrapServiceRegistry );
+ metadataSources = prepareMetadataSources( jandexIndex, deploymentResources, bootstrapServiceRegistry );
+ // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
withValidatorFactory( configurationValues.get( AvailableSettings.VALIDATION_FACTORY ) );
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -221,6 +227,241 @@ public class EntityManagerFactoryBuilderImpl implements EntityManagerFactoryBuil
}
}
+ private static interface DeploymentResources {
+ public Iterable getClassDescriptors();
+ public Iterable getPackageDescriptors();
+ public Iterable getMappingFileDescriptors();
+ }
+
+ private DeploymentResources buildDeploymentResources(
+ ScanResult scanResult,
+ BootstrapServiceRegistry bootstrapServiceRegistry) {
+
+ // mapping files ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+ final ArrayList mappingFileDescriptors = new ArrayList();
+
+ final Set nonLocatedMappingFileNames = new HashSet();
+ final List explicitMappingFileNames = persistenceUnit.getMappingFileNames();
+ if ( explicitMappingFileNames != null ) {
+ nonLocatedMappingFileNames.addAll( explicitMappingFileNames );
+ }
+
+ for ( MappingFileDescriptor mappingFileDescriptor : scanResult.getLocatedMappingFiles() ) {
+ mappingFileDescriptors.add( mappingFileDescriptor );
+ nonLocatedMappingFileNames.remove( mappingFileDescriptor.getName() );
+ }
+
+ for ( String name : nonLocatedMappingFileNames ) {
+ MappingFileDescriptor descriptor = buildMappingFileDescriptor( name, bootstrapServiceRegistry );
+ mappingFileDescriptors.add( descriptor );
+ }
+
+
+ // classes and packages ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+ final HashMap classDescriptorMap = new HashMap();
+ final HashMap packageDescriptorMap = new HashMap();
+
+ for ( ClassDescriptor classDescriptor : scanResult.getLocatedClasses() ) {
+ classDescriptorMap.put( classDescriptor.getName(), classDescriptor );
+ }
+
+ for ( PackageDescriptor packageDescriptor : scanResult.getLocatedPackages() ) {
+ packageDescriptorMap.put( packageDescriptor.getName(), packageDescriptor );
+ }
+
+ final List explicitClassNames = persistenceUnit.getManagedClassNames();
+ if ( explicitClassNames != null ) {
+ for ( String explicitClassName : explicitClassNames ) {
+ // IMPL NOTE : explicitClassNames can contain class or package names!!!
+ if ( classDescriptorMap.containsKey( explicitClassName ) ) {
+ continue;
+ }
+ if ( packageDescriptorMap.containsKey( explicitClassName ) ) {
+ continue;
+ }
+
+ // try it as a class name first...
+ final String classFileName = explicitClassName.replace( '.', '/' ) + ".class";
+ final URL classFileUrl = bootstrapServiceRegistry.getService( ClassLoaderService.class )
+ .locateResource( classFileName );
+ if ( classFileUrl != null ) {
+ classDescriptorMap.put(
+ explicitClassName,
+ new ClassDescriptorImpl( explicitClassName, new UrlInputStreamAccess( classFileUrl ) )
+ );
+ continue;
+ }
+
+ // otherwise, try it as a package name
+ final String packageInfoFileName = explicitClassName.replace( '.', '/' ) + "/package-info.class";
+ final URL packageInfoFileUrl = bootstrapServiceRegistry.getService( ClassLoaderService.class )
+ .locateResource( packageInfoFileName );
+ if ( packageInfoFileUrl != null ) {
+ packageDescriptorMap.put(
+ explicitClassName,
+ new PackageDescriptorImpl( explicitClassName, new UrlInputStreamAccess( packageInfoFileUrl ) )
+ );
+ continue;
+ }
+
+ LOG.debugf(
+ "Unable to resolve class [%s] named in persistence unit [%s]",
+ explicitClassName,
+ persistenceUnit.getName()
+ );
+ }
+ }
+
+ return new DeploymentResources() {
+ @Override
+ public Iterable getClassDescriptors() {
+ return classDescriptorMap.values();
+ }
+
+ @Override
+ public Iterable getPackageDescriptors() {
+ return packageDescriptorMap.values();
+ }
+
+ @Override
+ public Iterable getMappingFileDescriptors() {
+ return mappingFileDescriptors;
+ }
+ };
+ }
+
+ private MappingFileDescriptor buildMappingFileDescriptor(
+ String name,
+ BootstrapServiceRegistry bootstrapServiceRegistry) {
+ final URL url = bootstrapServiceRegistry.getService( ClassLoaderService.class ).locateResource( name );
+ if ( url == null ) {
+ throw persistenceException( "Unable to resolve named mapping-file [" + name + "]" );
+ }
+
+ return new MappingFileDescriptorImpl( name, new UrlInputStreamAccess( url ) );
+ }
+
+ // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ // temporary!
+ @SuppressWarnings("unchecked")
+ public Map getConfigurationValues() {
+ return Collections.unmodifiableMap( configurationValues );
+ }
+
+ public Configuration getHibernateConfiguration() {
+ return hibernateConfiguration;
+ }
+ // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+
+ @SuppressWarnings("unchecked")
+ private MetadataSources prepareMetadataSources(
+ IndexView jandexIndex,
+ DeploymentResources deploymentResources,
+ BootstrapServiceRegistry bootstrapServiceRegistry) {
+ // todo : this needs to tie into the metamodel branch...
+ MetadataSources metadataSources = new MetadataSources();
+
+ for ( ClassDescriptor classDescriptor : deploymentResources.getClassDescriptors() ) {
+ final String className = classDescriptor.getName();
+ final ClassInfo classInfo = jandexIndex.getClassByName( DotName.createSimple( className ) );
+ if ( classInfo == null ) {
+ // Not really sure what this means. Most likely it is explicitly listed in the persistence unit,
+ // but mapped via mapping file. Anyway assume its a mapping class...
+ metadataSources.annotatedMappingClassNames.add( className );
+ continue;
+ }
+
+ // logic here assumes an entity is not also a converter...
+ AnnotationInstance converterAnnotation = JandexHelper.getSingleAnnotation(
+ classInfo.annotations(),
+ JPADotNames.CONVERTER
+ );
+ if ( converterAnnotation != null ) {
+ metadataSources.converterDescriptors.add(
+ new MetadataSources.ConverterDescriptor(
+ className,
+ JandexHelper.getValue( converterAnnotation, "autoApply", boolean.class )
+ )
+ );
+ }
+ else {
+ metadataSources.annotatedMappingClassNames.add( className );
+ }
+ }
+
+ for ( PackageDescriptor packageDescriptor : deploymentResources.getPackageDescriptors() ) {
+ metadataSources.packageNames.add( packageDescriptor.getName() );
+ }
+
+ for ( MappingFileDescriptor mappingFileDescriptor : deploymentResources.getMappingFileDescriptors() ) {
+ metadataSources.namedMappingFileInputStreams.add( mappingFileDescriptor.getStreamAccess().asNamedInputStream() );
+ }
+
+ final String explicitHbmXmls = (String) configurationValues.remove( AvailableSettings.HBXML_FILES );
+ if ( explicitHbmXmls != null ) {
+ metadataSources.mappingFileResources.addAll( Arrays.asList( StringHelper.split( ", ", explicitHbmXmls ) ) );
+ }
+
+ final List explicitOrmXml = (List) configurationValues.remove( AvailableSettings.XML_FILE_NAMES );
+ if ( explicitOrmXml != null ) {
+ metadataSources.mappingFileResources.addAll( explicitOrmXml );
+ }
+
+ return metadataSources;
+ }
+
+ private IndexView locateOrBuildJandexIndex(DeploymentResources deploymentResources) {
+ // for now create a whole new Index to work with, eventually we need to:
+ // 1) accept an Index as an incoming config value
+ // 2) pass that Index along to the metamodel code...
+ IndexView jandexIndex = (IndexView) configurationValues.get( JANDEX_INDEX );
+ if ( jandexIndex == null ) {
+ jandexIndex = buildJandexIndex( deploymentResources );
+ }
+ return jandexIndex;
+ }
+
+ private IndexView buildJandexIndex(DeploymentResources deploymentResources) {
+ Indexer indexer = new Indexer();
+
+ for ( ClassDescriptor classDescriptor : deploymentResources.getClassDescriptors() ) {
+ indexStream( indexer, classDescriptor.getStreamAccess() );
+ }
+
+ for ( PackageDescriptor packageDescriptor : deploymentResources.getPackageDescriptors() ) {
+ indexStream( indexer, packageDescriptor.getStreamAccess() );
+ }
+
+ // for now we just skip entities defined in (1) orm.xml files and (2) hbm.xml files. this part really needs
+ // metamodel branch...
+
+ // for now, we also need to wrap this in a CompositeIndex until Jandex is updated to use a common interface
+ // between the 2...
+ return indexer.complete();
+ }
+
+ private void indexStream(Indexer indexer, InputStreamAccess streamAccess) {
+ try {
+ InputStream stream = streamAccess.accessInputStream();
+ try {
+ indexer.index( stream );
+ }
+ finally {
+ try {
+ stream.close();
+ }
+ catch (Exception ignore) {
+ }
+ }
+ }
+ catch ( IOException e ) {
+ throw persistenceException( "Unable to index from stream " + streamAccess.getStreamName(), e );
+ }
+ }
+
/**
* Builds the {@link BootstrapServiceRegistry} used to eventually build the {@link org.hibernate.boot.registry.StandardServiceRegistryBuilder}; mainly
* used here during instantiation to define class-loading behavior.
@@ -360,7 +601,7 @@ public class EntityManagerFactoryBuilderImpl implements EntityManagerFactoryBuil
= (JaxbHibernateConfiguration.JaxbSessionFactory.JaxbClassCache) cacheDeclaration;
cacheRegionDefinitions.add(
new CacheRegionDefinition(
- CacheRegionDefinition.CacheRegionType.ENTITY,
+ CacheRegionDefinition.CacheType.ENTITY,
jaxbClassCache.getClazz(),
jaxbClassCache.getUsage().value(),
jaxbClassCache.getRegion(),
@@ -373,7 +614,7 @@ public class EntityManagerFactoryBuilderImpl implements EntityManagerFactoryBuil
= (JaxbHibernateConfiguration.JaxbSessionFactory.JaxbCollectionCache) cacheDeclaration;
cacheRegionDefinitions.add(
new CacheRegionDefinition(
- CacheRegionDefinition.CacheRegionType.COLLECTION,
+ CacheRegionDefinition.CacheType.COLLECTION,
jaxbCollectionCache.getCollection(),
jaxbCollectionCache.getUsage().value(),
jaxbCollectionCache.getRegion(),
@@ -398,98 +639,6 @@ public class EntityManagerFactoryBuilderImpl implements EntityManagerFactoryBuil
}
}
-
- // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- // temporary!
- @SuppressWarnings("unchecked")
- public Map getConfigurationValues() {
- return Collections.unmodifiableMap( configurationValues );
- }
-
- public Configuration getHibernateConfiguration() {
- return hibernateConfiguration;
- }
- // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-
- @SuppressWarnings("unchecked")
- private MetadataSources prepareMetadataSources(
- IndexView jandexIndex,
- Set collectedManagedClassNames,
- ScanResult scanResult,
- BootstrapServiceRegistry bootstrapServiceRegistry) {
- // todo : this needs to tie into the metamodel branch...
- MetadataSources metadataSources = new MetadataSources();
-
- for ( String className : collectedManagedClassNames ) {
- final ClassInfo classInfo = jandexIndex.getClassByName( DotName.createSimple( className ) );
- if ( classInfo == null ) {
- // Not really sure what this means. Most likely it is explicitly listed in the persistence unit,
- // but mapped via mapping file. Anyway assume its a mapping class...
- metadataSources.annotatedMappingClassNames.add( className );
- continue;
- }
-
- // logic here assumes an entity is not also a converter...
- AnnotationInstance converterAnnotation = JandexHelper.getSingleAnnotation(
- classInfo.annotations(),
- JPADotNames.CONVERTER
- );
- if ( converterAnnotation != null ) {
- metadataSources.converterDescriptors.add(
- new MetadataSources.ConverterDescriptor(
- className,
- JandexHelper.getValue( converterAnnotation, "autoApply", boolean.class )
- )
- );
- }
- else {
- metadataSources.annotatedMappingClassNames.add( className );
- }
- }
-
- metadataSources.packageNames.addAll( scanResult.getPackageNames() );
-
- metadataSources.namedMappingFileInputStreams.addAll( scanResult.getHbmFiles() );
-
- metadataSources.mappingFileResources.addAll( scanResult.getMappingFiles() );
- final String explicitHbmXmls = (String) configurationValues.remove( AvailableSettings.HBXML_FILES );
- if ( explicitHbmXmls != null ) {
- metadataSources.mappingFileResources.addAll( Arrays.asList( StringHelper.split( ", ", explicitHbmXmls ) ) );
- }
- final List explicitOrmXml = (List) configurationValues.remove( AvailableSettings.XML_FILE_NAMES );
- if ( explicitOrmXml != null ) {
- metadataSources.mappingFileResources.addAll( explicitOrmXml );
- }
-
- return metadataSources;
- }
-
- private Set collectManagedClassNames(ScanResult scanResult) {
- Set collectedNames = new HashSet();
- if ( persistenceUnit.getManagedClassNames() != null ) {
- collectedNames.addAll( persistenceUnit.getManagedClassNames() );
- }
- collectedNames.addAll( scanResult.getManagedClassNames() );
- return collectedNames;
- }
-
- private IndexView locateOrBuildJandexIndex(
- Set collectedManagedClassNames,
- List packageNames,
- BootstrapServiceRegistry bootstrapServiceRegistry) {
- // for now create a whole new Index to work with, eventually we need to:
- // 1) accept an Index as an incoming config value
- // 2) pass that Index along to the metamodel code...
- //
- // (1) is mocked up here, but JBoss AS does not currently pass in any Index to use...
- IndexView jandexIndex = (IndexView) configurationValues.get( JANDEX_INDEX );
- if ( jandexIndex == null ) {
- jandexIndex = buildJandexIndex( collectedManagedClassNames, packageNames, bootstrapServiceRegistry );
- }
- return jandexIndex;
- }
-
private IndexView buildJandexIndex(Set classNamesSource, List packageNames, BootstrapServiceRegistry bootstrapServiceRegistry) {
Indexer indexer = new Indexer();
@@ -551,11 +700,11 @@ public class EntityManagerFactoryBuilderImpl implements EntityManagerFactoryBuil
}
}
- private void addCacheRegionDefinition(String role, String value, CacheRegionDefinition.CacheRegionType cacheType) {
+ private void addCacheRegionDefinition(String role, String value, CacheRegionDefinition.CacheType cacheType) {
final StringTokenizer params = new StringTokenizer( value, ";, " );
if ( !params.hasMoreTokens() ) {
StringBuilder error = new StringBuilder( "Illegal usage of " );
- if ( cacheType == CacheRegionDefinition.CacheRegionType.ENTITY ) {
+ if ( cacheType == CacheRegionDefinition.CacheType.ENTITY ) {
error.append( AvailableSettings.CLASS_CACHE_PREFIX )
.append( ": " )
.append( AvailableSettings.CLASS_CACHE_PREFIX );
@@ -579,7 +728,7 @@ public class EntityManagerFactoryBuilderImpl implements EntityManagerFactoryBuil
region = params.nextToken();
}
boolean lazyProperty = true;
- if ( cacheType == CacheRegionDefinition.CacheRegionType.ENTITY ) {
+ if ( cacheType == CacheRegionDefinition.CacheType.ENTITY ) {
if ( params.hasMoreTokens() ) {
lazyProperty = "all".equalsIgnoreCase( params.nextToken() );
}
@@ -594,37 +743,24 @@ public class EntityManagerFactoryBuilderImpl implements EntityManagerFactoryBuil
@SuppressWarnings("unchecked")
private ScanResult scan(BootstrapServiceRegistry bootstrapServiceRegistry) {
- Scanner scanner = locateOrBuildScanner( bootstrapServiceRegistry );
- ScanningContext scanningContext = new ScanningContext();
+ final Scanner scanner = locateOrBuildScanner( bootstrapServiceRegistry );
+ final ScanOptions scanOptions = determineScanOptions();
- final ScanResult scanResult = new ScanResult();
- if ( persistenceUnit.getMappingFileNames() != null ) {
- scanResult.getMappingFiles().addAll( persistenceUnit.getMappingFileNames() );
- }
+ return scanner.scan( persistenceUnit, scanOptions );
+ }
- // dunno, but the old code did it...
- scanningContext.setSearchOrm( ! scanResult.getMappingFiles().contains( META_INF_ORM_XML ) );
-
- if ( persistenceUnit.getJarFileUrls() != null ) {
- prepareAutoDetectionSettings( scanningContext, false );
- for ( URL jar : persistenceUnit.getJarFileUrls() ) {
- scanningContext.setUrl( jar );
- scanInContext( scanner, scanningContext, scanResult );
- }
- }
-
- prepareAutoDetectionSettings( scanningContext, persistenceUnit.isExcludeUnlistedClasses() );
- scanningContext.setUrl( persistenceUnit.getPersistenceUnitRootUrl() );
- scanInContext( scanner, scanningContext, scanResult );
-
- return scanResult;
+ private ScanOptions determineScanOptions() {
+ return new StandardScanOptions(
+ (String) configurationValues.get( AvailableSettings.AUTODETECTION ),
+ persistenceUnit.isExcludeUnlistedClasses()
+ );
}
@SuppressWarnings("unchecked")
private Scanner locateOrBuildScanner(BootstrapServiceRegistry bootstrapServiceRegistry) {
final Object value = configurationValues.remove( AvailableSettings.SCANNER );
if ( value == null ) {
- return new NativeScanner();
+ return new StandardScanner();
}
if ( Scanner.class.isInstance( value ) ) {
@@ -660,91 +796,6 @@ public class EntityManagerFactoryBuilderImpl implements EntityManagerFactoryBuil
}
}
- private void prepareAutoDetectionSettings(ScanningContext context, boolean excludeUnlistedClasses) {
- final String detectionSetting = (String) configurationValues.get( AvailableSettings.AUTODETECTION );
-
- if ( detectionSetting == null ) {
- if ( excludeUnlistedClasses ) {
- context.setDetectClasses( false );
- context.setDetectHbmFiles( false );
- }
- else {
- context.setDetectClasses( true );
- context.setDetectHbmFiles( true );
- }
- }
- else {
- for ( String token : StringHelper.split( ", ", detectionSetting ) ) {
- if ( "class".equalsIgnoreCase( token ) ) {
- context.setDetectClasses( true );
- }
- if ( "hbm".equalsIgnoreCase( token ) ) {
- context.setDetectClasses( true );
- }
- }
- }
- }
-
- private void scanInContext(
- Scanner scanner,
- ScanningContext scanningContext,
- ScanResult scanResult) {
- if ( scanningContext.getUrl() == null ) {
- // not sure i like just ignoring this being null, but this is exactly what the old code does...
- LOG.containerProvidingNullPersistenceUnitRootUrl();
- return;
- }
- if ( scanningContext.getUrl().getProtocol().equalsIgnoreCase( "bundle" ) ) {
- // TODO: Is there a way to scan the root bundle URL in OSGi containers?
- // Although the URL provides a stream handler that works for finding
- // resources in a specific Bundle, the root one does not work.
- return;
- }
-
- try {
- if ( scanningContext.isDetectClasses() ) {
- Set matchingPackages = scanner.getPackagesInJar( scanningContext.url, new HashSet>(0) );
- for ( Package pkg : matchingPackages ) {
- scanResult.getPackageNames().add( pkg.getName() );
- }
-
- Set> annotationsToLookFor = new HashSet>();
- annotationsToLookFor.add( Entity.class );
- annotationsToLookFor.add( MappedSuperclass.class );
- annotationsToLookFor.add( Embeddable.class );
- annotationsToLookFor.add( Converter.class );
- Set> matchingClasses = scanner.getClassesInJar( scanningContext.url, annotationsToLookFor );
- for ( Class> clazz : matchingClasses ) {
- scanResult.getManagedClassNames().add( clazz.getName() );
- }
- }
-
- Set patterns = new HashSet();
- if ( scanningContext.isSearchOrm() ) {
- patterns.add( META_INF_ORM_XML );
- }
- if ( scanningContext.isDetectHbmFiles() ) {
- patterns.add( "**/*.hbm.xml" );
- }
- if ( ! scanResult.getMappingFiles().isEmpty() ) {
- patterns.addAll( scanResult.getMappingFiles() );
- }
- if ( patterns.size() != 0 ) {
- Set files = scanner.getFilesInJar( scanningContext.getUrl(), patterns );
- for ( NamedInputStream file : files ) {
- scanResult.getHbmFiles().add( file );
- scanResult.getMappingFiles().remove( file.getName() );
- }
- }
- }
- catch (PersistenceException e ) {
- throw e;
- }
- catch ( RuntimeException e ) {
- throw persistenceException( "error trying to scan url: " + scanningContext.getUrl().toString(), e );
- }
- }
-
@Override
public EntityManagerFactoryBuilder withValidatorFactory(Object validatorFactory) {
this.validatorFactory = validatorFactory;
@@ -886,14 +937,14 @@ public class EntityManagerFactoryBuilderImpl implements EntityManagerFactoryBuil
addCacheRegionDefinition(
keyString.substring( AvailableSettings.CLASS_CACHE_PREFIX.length() + 1 ),
(String) entry.getValue(),
- CacheRegionDefinition.CacheRegionType.ENTITY
+ CacheRegionDefinition.CacheType.ENTITY
);
}
else if ( keyString.startsWith( AvailableSettings.COLLECTION_CACHE_PREFIX ) ) {
addCacheRegionDefinition(
keyString.substring( AvailableSettings.COLLECTION_CACHE_PREFIX.length() + 1 ),
(String) entry.getValue(),
- CacheRegionDefinition.CacheRegionType.COLLECTION
+ CacheRegionDefinition.CacheType.COLLECTION
);
}
else if ( keyString.startsWith( AvailableSettings.JACC_PREFIX )
@@ -1006,30 +1057,30 @@ public class EntityManagerFactoryBuilderImpl implements EntityManagerFactoryBuil
if ( jaccDefinitions != null ) {
for ( JaccDefinition jaccDefinition : jaccDefinitions ) {
- JACCConfiguration jaccCfg = new JACCConfiguration( jaccDefinition.getContextId() );
+ JACCConfiguration jaccCfg = new JACCConfiguration( jaccDefinition.contextId );
jaccCfg.addPermission(
- jaccDefinition.getRole(),
- jaccDefinition.getClazz(),
- jaccDefinition.getActions()
+ jaccDefinition.role,
+ jaccDefinition.clazz,
+ jaccDefinition.actions
);
}
}
if ( cacheRegionDefinitions != null ) {
for ( CacheRegionDefinition cacheRegionDefinition : cacheRegionDefinitions ) {
- if ( cacheRegionDefinition.getRegionType() == CacheRegionDefinition.CacheRegionType.ENTITY ) {
+ if ( cacheRegionDefinition.cacheType == CacheRegionDefinition.CacheType.ENTITY ) {
cfg.setCacheConcurrencyStrategy(
- cacheRegionDefinition.getRole(),
- cacheRegionDefinition.getUsage(),
- cacheRegionDefinition.getRegion(),
- cacheRegionDefinition.isCacheLazy()
+ cacheRegionDefinition.role,
+ cacheRegionDefinition.usage,
+ cacheRegionDefinition.region,
+ cacheRegionDefinition.cacheLazy
);
}
else {
cfg.setCollectionCacheConcurrencyStrategy(
- cacheRegionDefinition.getRole(),
- cacheRegionDefinition.getUsage(),
- cacheRegionDefinition.getRegion()
+ cacheRegionDefinition.role,
+ cacheRegionDefinition.usage,
+ cacheRegionDefinition.region
);
}
}
@@ -1116,14 +1167,28 @@ public class EntityManagerFactoryBuilderImpl implements EntityManagerFactoryBuil
//addInputStream has the responsibility to close the stream
cfg.addInputStream( new BufferedInputStream( namedInputStream.getStream() ) );
}
- catch (MappingException me) {
- //try our best to give the file name
- if ( StringHelper.isEmpty( namedInputStream.getName() ) ) {
- throw me;
+ catch ( InvalidMappingException e ) {
+ // try our best to give the file name
+ if ( StringHelper.isNotEmpty( namedInputStream.getName() ) ) {
+ throw new InvalidMappingException(
+ "Error while parsing file: " + namedInputStream.getName(),
+ e.getType(),
+ e.getPath(),
+ e
+ );
}
else {
+ throw e;
+ }
+ }
+ catch (MappingException me) {
+ // try our best to give the file name
+ if ( StringHelper.isNotEmpty( namedInputStream.getName() ) ) {
throw new MappingException("Error while parsing file: " + namedInputStream.getName(), me );
}
+ else {
+ throw me;
+ }
}
}
for ( String packageName : metadataSources.packageNames ) {
@@ -1162,65 +1227,39 @@ public class EntityManagerFactoryBuilderImpl implements EntityManagerFactoryBuil
return "[PersistenceUnit: " + persistenceUnit.getName() + "] ";
}
- public static class ScanningContext {
- private URL url;
- private boolean detectClasses;
- private boolean detectHbmFiles;
- private boolean searchOrm;
+ public static class CacheRegionDefinition {
+ public static enum CacheType { ENTITY, COLLECTION }
- public URL getUrl() {
- return url;
- }
+ public final CacheType cacheType;
+ public final String role;
+ public final String usage;
+ public final String region;
+ public final boolean cacheLazy;
- public void setUrl(URL url) {
- this.url = url;
- }
-
- public boolean isDetectClasses() {
- return detectClasses;
- }
-
- public void setDetectClasses(boolean detectClasses) {
- this.detectClasses = detectClasses;
- }
-
- public boolean isDetectHbmFiles() {
- return detectHbmFiles;
- }
-
- public void setDetectHbmFiles(boolean detectHbmFiles) {
- this.detectHbmFiles = detectHbmFiles;
- }
-
- public boolean isSearchOrm() {
- return searchOrm;
- }
-
- public void setSearchOrm(boolean searchOrm) {
- this.searchOrm = searchOrm;
+ public CacheRegionDefinition(
+ CacheType cacheType,
+ String role,
+ String usage,
+ String region, boolean cacheLazy) {
+ this.cacheType = cacheType;
+ this.role = role;
+ this.usage = usage;
+ this.region = region;
+ this.cacheLazy = cacheLazy;
}
}
- private static class ScanResult {
- private final List managedClassNames = new ArrayList();
- private final List packageNames = new ArrayList();
- private final List hbmFiles = new ArrayList();
- private final List mappingFiles = new ArrayList();
+ public static class JaccDefinition {
+ public final String contextId;
+ public final String role;
+ public final String clazz;
+ public final String actions;
- public List getManagedClassNames() {
- return managedClassNames;
- }
-
- public List getPackageNames() {
- return packageNames;
- }
-
- public List getHbmFiles() {
- return hbmFiles;
- }
-
- public List getMappingFiles() {
- return mappingFiles;
+ public JaccDefinition(String contextId, String role, String clazz, String actions) {
+ this.contextId = contextId;
+ this.role = role;
+ this.clazz = clazz;
+ this.actions = actions;
}
}
diff --git a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/boot/internal/FileInputStreamAccess.java b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/boot/internal/FileInputStreamAccess.java
new file mode 100644
index 0000000000..7d9294364a
--- /dev/null
+++ b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/boot/internal/FileInputStreamAccess.java
@@ -0,0 +1,77 @@
+/*
+ * 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.jpa.boot.internal;
+
+import java.io.BufferedInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.InputStream;
+
+import org.hibernate.HibernateException;
+import org.hibernate.jpa.boot.archive.spi.ArchiveException;
+import org.hibernate.jpa.boot.spi.InputStreamAccess;
+import org.hibernate.jpa.boot.spi.NamedInputStream;
+
+/**
+ * An InputStreamAccess implementation based on a File reference
+ *
+ * @author Steve Ebersole
+ */
+public class FileInputStreamAccess implements InputStreamAccess {
+ private final String name;
+ private final File file;
+
+ public FileInputStreamAccess(String name, File file) {
+ this.name = name;
+ this.file = file;
+ if ( ! file.exists() ) {
+ throw new HibernateException( "File must exist : " + file.getAbsolutePath() );
+ }
+ }
+
+ @Override
+ public String getStreamName() {
+ return name;
+ }
+
+ @Override
+ public InputStream accessInputStream() {
+ try {
+ return new BufferedInputStream( new FileInputStream( file ) );
+ }
+ catch (FileNotFoundException e) {
+ // should never ever ever happen, but...
+ throw new ArchiveException(
+ "File believed to exist based on File.exists threw error when passed to FileInputStream ctor",
+ e
+ );
+ }
+ }
+
+ @Override
+ public NamedInputStream asNamedInputStream() {
+ return new NamedInputStream( getStreamName(), accessInputStream() );
+ }
+}
diff --git a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/boot/internal/MappingFileDescriptorImpl.java b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/boot/internal/MappingFileDescriptorImpl.java
new file mode 100644
index 0000000000..1a073c4002
--- /dev/null
+++ b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/boot/internal/MappingFileDescriptorImpl.java
@@ -0,0 +1,73 @@
+/*
+ * 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.jpa.boot.internal;
+
+import org.hibernate.jpa.boot.spi.InputStreamAccess;
+import org.hibernate.jpa.boot.spi.MappingFileDescriptor;
+
+/**
+ * @author Steve Ebersole
+ */
+public class MappingFileDescriptorImpl implements MappingFileDescriptor {
+ private final String name;
+ private final InputStreamAccess streamAccess;
+
+ public MappingFileDescriptorImpl(String name, InputStreamAccess streamAccess) {
+ this.name = name;
+ this.streamAccess = streamAccess;
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+
+ @Override
+ public InputStreamAccess getStreamAccess() {
+ return streamAccess;
+ }
+
+// @Override
+// public boolean equals(Object o) {
+// if ( this == o ) {
+// return true;
+// }
+// if ( o == null || getClass() != o.getClass() ) {
+// return false;
+// }
+//
+// MappingFileDescriptorImpl that = (MappingFileDescriptorImpl) o;
+//
+// return name.equals( that.name )
+// && streamAccess.getStreamName().equals( that.streamAccess.getStreamName() );
+//
+// }
+//
+// @Override
+// public int hashCode() {
+// int result = name.hashCode();
+// result = 31 * result + streamAccess.getStreamName().hashCode();
+// return result;
+// }
+}
diff --git a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/boot/internal/PackageDescriptorImpl.java b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/boot/internal/PackageDescriptorImpl.java
new file mode 100644
index 0000000000..c40eb48786
--- /dev/null
+++ b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/boot/internal/PackageDescriptorImpl.java
@@ -0,0 +1,68 @@
+/*
+ * 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.jpa.boot.internal;
+
+import org.hibernate.jpa.boot.spi.InputStreamAccess;
+import org.hibernate.jpa.boot.spi.PackageDescriptor;
+
+/**
+ * @author Steve Ebersole
+ */
+public class PackageDescriptorImpl implements PackageDescriptor {
+ private final String name;
+ private final InputStreamAccess streamAccess;
+
+ public PackageDescriptorImpl(String name, InputStreamAccess streamAccess) {
+ this.name = name;
+ this.streamAccess = streamAccess;
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+
+ @Override
+ public InputStreamAccess getStreamAccess() {
+ return streamAccess;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if ( this == o ) {
+ return true;
+ }
+ if ( o == null || getClass() != o.getClass() ) {
+ return false;
+ }
+
+ PackageDescriptorImpl that = (PackageDescriptorImpl) o;
+ return name.equals( that.name );
+ }
+
+ @Override
+ public int hashCode() {
+ return name.hashCode();
+ }
+}
diff --git a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/boot/internal/PersistenceXmlParser.java b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/boot/internal/PersistenceXmlParser.java
index d593a4f191..0e89e3d937 100644
--- a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/boot/internal/PersistenceXmlParser.java
+++ b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/boot/internal/PersistenceXmlParser.java
@@ -54,8 +54,8 @@ import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
import org.hibernate.jpa.AvailableSettings;
+import org.hibernate.jpa.boot.archive.internal.ArchiveHelper;
import org.hibernate.jpa.internal.EntityManagerMessageLogger;
-import org.hibernate.jpa.packaging.internal.JarVisitorFactory;
import org.hibernate.jpa.internal.util.ConfigurationHelper;
import org.hibernate.internal.util.StringHelper;
import org.hibernate.boot.registry.classloading.internal.ClassLoaderServiceImpl;
@@ -121,7 +121,7 @@ public class PersistenceXmlParser {
final Element element = (Element) children.item( i );
final String tag = element.getTagName();
if ( tag.equals( "persistence-unit" ) ) {
- final URL puRootUrl = JarVisitorFactory.getJarURLFromURLEntry( xmlUrl, "/META-INF/persistence.xml" );
+ final URL puRootUrl = ArchiveHelper.getJarURLFromURLEntry( xmlUrl, "/META-INF/persistence.xml" );
ParsedPersistenceXmlDescriptor persistenceUnit = new ParsedPersistenceXmlDescriptor( puRootUrl );
bindPersistenceUnit( persistenceUnit, element );
@@ -214,7 +214,7 @@ public class PersistenceXmlParser {
persistenceUnit.addMappingFiles( extractContent( element ) );
}
else if ( tag.equals( "jar-file" ) ) {
- persistenceUnit.addJarFileUrl( JarVisitorFactory.getURLFromPath( extractContent( element ) ) );
+ persistenceUnit.addJarFileUrl( ArchiveHelper.getURLFromPath( extractContent( element ) ) );
}
else if ( tag.equals( "exclude-unlisted-classes" ) ) {
persistenceUnit.setExcludeUnlistedClasses( true );
diff --git a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/boot/internal/UrlInputStreamAccess.java b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/boot/internal/UrlInputStreamAccess.java
new file mode 100644
index 0000000000..4281201381
--- /dev/null
+++ b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/boot/internal/UrlInputStreamAccess.java
@@ -0,0 +1,62 @@
+/*
+ * 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.jpa.boot.internal;
+
+import java.io.InputStream;
+import java.net.URL;
+
+import org.hibernate.HibernateException;
+import org.hibernate.jpa.boot.spi.InputStreamAccess;
+import org.hibernate.jpa.boot.spi.NamedInputStream;
+
+/**
+ * @author Steve Ebersole
+ */
+public class UrlInputStreamAccess implements InputStreamAccess {
+ private final URL url;
+
+ public UrlInputStreamAccess(URL url) {
+ this.url = url;
+ }
+
+ @Override
+ public String getStreamName() {
+ return url.toExternalForm();
+ }
+
+ @Override
+ public InputStream accessInputStream() {
+ try {
+ return url.openStream();
+ }
+ catch (Exception e) {
+ throw new HibernateException( "Could not open url stream : " + url.toExternalForm() );
+ }
+ }
+
+ @Override
+ public NamedInputStream asNamedInputStream() {
+ return new NamedInputStream( getStreamName(), accessInputStream() );
+ }
+}
diff --git a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/boot/scan/internal/StandardScanOptions.java b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/boot/scan/internal/StandardScanOptions.java
new file mode 100644
index 0000000000..e2dcf9e154
--- /dev/null
+++ b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/boot/scan/internal/StandardScanOptions.java
@@ -0,0 +1,67 @@
+/*
+ * 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.jpa.boot.scan.internal;
+
+import org.hibernate.jpa.boot.scan.spi.ScanOptions;
+
+/**
+ * @author Steve Ebersole
+ */
+public class StandardScanOptions implements ScanOptions {
+ private final boolean detectClassesInRoot;
+ private final boolean detectClassesInNonRoot;
+ private final boolean detectHibernateMappingFiles;
+
+ public StandardScanOptions() {
+ this( "hbm,class", false );
+ }
+
+ public StandardScanOptions(String explicitDetectionSetting, boolean persistenceUnitExcludeUnlistedClassesValue) {
+ if ( explicitDetectionSetting == null ) {
+ detectHibernateMappingFiles = true;
+ detectClassesInRoot = ! persistenceUnitExcludeUnlistedClassesValue;
+ detectClassesInNonRoot = true;
+ }
+ else {
+ detectHibernateMappingFiles = explicitDetectionSetting.contains( "hbm" );
+ detectClassesInRoot = explicitDetectionSetting.contains( "class" );
+ detectClassesInNonRoot = detectClassesInRoot;
+ }
+ }
+
+ @Override
+ public boolean canDetectUnlistedClassesInRoot() {
+ return detectClassesInRoot;
+ }
+
+ @Override
+ public boolean canDetectUnlistedClassesInNonRoot() {
+ return detectClassesInNonRoot;
+ }
+
+ @Override
+ public boolean canDetectHibernateMappingFiles() {
+ return detectHibernateMappingFiles;
+ }
+}
diff --git a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/boot/scan/internal/StandardScanner.java b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/boot/scan/internal/StandardScanner.java
new file mode 100644
index 0000000000..6db4050a0e
--- /dev/null
+++ b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/boot/scan/internal/StandardScanner.java
@@ -0,0 +1,40 @@
+/*
+ * 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.jpa.boot.scan.internal;
+
+import org.hibernate.jpa.boot.archive.internal.StandardArchiveDescriptorFactory;
+import org.hibernate.jpa.boot.scan.spi.AbstractScannerImpl;
+
+/**
+ * Standard implementation of the Scanner contract, supporting typical archive walking support where
+ * the urls we are processing can be treated using normal file handling.
+ *
+ * @author Steve Ebersole
+ * @author Emmanuel Bernard
+ */
+public class StandardScanner extends AbstractScannerImpl {
+ public StandardScanner() {
+ super( StandardArchiveDescriptorFactory.INSTANCE );
+ }
+}
diff --git a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/boot/scan/spi/AbstractJavaArtifactArchiveEntryHandler.java b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/boot/scan/spi/AbstractJavaArtifactArchiveEntryHandler.java
new file mode 100644
index 0000000000..c8547ebf14
--- /dev/null
+++ b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/boot/scan/spi/AbstractJavaArtifactArchiveEntryHandler.java
@@ -0,0 +1,67 @@
+/*
+ * 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.jpa.boot.scan.spi;
+
+import org.hibernate.jpa.boot.archive.spi.ArchiveContext;
+import org.hibernate.jpa.boot.archive.spi.ArchiveEntryHandler;
+
+/**
+ * Base class for commonality between handling class file entries and handling package-info file entries.
+ *
+ * @author Steve Ebersole
+ */
+public abstract class AbstractJavaArtifactArchiveEntryHandler implements ArchiveEntryHandler {
+ private final ScanOptions scanOptions;
+
+ protected AbstractJavaArtifactArchiveEntryHandler(ScanOptions scanOptions) {
+ this.scanOptions = scanOptions;
+ }
+
+ /**
+ * Check to see if the incoming name (class/package name) is either:
+ * - explicitly listed in a {@code } entry within the {@code }
+ * - whether the scan options indicate that we are allowed to detect this entry
+ *
+ *
+ * @param context Information about the archive. Mainly whether it is the root of the PU
+ * @param name The class/package name
+ *
+ * @return {@code true} if the named class/package is either detectable or explicitly listed; {@code false}
+ * otherwise.
+ */
+ protected boolean isListedOrDetectable(ArchiveContext context, String name) {
+ // IMPL NOTE : protect the isExplicitlyListed call unless needed, since it can take time in a PU
+ // with lots of listed classes. The other conditions are simple boolean flag checks.
+ if ( context.isRootUrl() ) {
+ return scanOptions.canDetectUnlistedClassesInRoot() || isExplicitlyListed( context, name );
+ }
+ else {
+ return scanOptions.canDetectUnlistedClassesInNonRoot() || isExplicitlyListed( context, name );
+ }
+ }
+
+ private boolean isExplicitlyListed(ArchiveContext context, String name) {
+ return context.getPersistenceUnitDescriptor().getManagedClassNames().contains( name );
+ }
+}
diff --git a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/boot/scan/spi/AbstractScannerImpl.java b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/boot/scan/spi/AbstractScannerImpl.java
new file mode 100644
index 0000000000..da5af94f25
--- /dev/null
+++ b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/boot/scan/spi/AbstractScannerImpl.java
@@ -0,0 +1,302 @@
+/*
+ * 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.jpa.boot.scan.spi;
+
+import java.net.URL;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import org.hibernate.jpa.boot.archive.spi.ArchiveContext;
+import org.hibernate.jpa.boot.archive.spi.ArchiveDescriptor;
+import org.hibernate.jpa.boot.archive.spi.ArchiveDescriptorFactory;
+import org.hibernate.jpa.boot.archive.spi.ArchiveEntry;
+import org.hibernate.jpa.boot.archive.spi.ArchiveEntryHandler;
+import org.hibernate.jpa.boot.internal.ClassDescriptorImpl;
+import org.hibernate.jpa.boot.internal.MappingFileDescriptorImpl;
+import org.hibernate.jpa.boot.internal.PackageDescriptorImpl;
+import org.hibernate.jpa.boot.spi.ClassDescriptor;
+import org.hibernate.jpa.boot.spi.MappingFileDescriptor;
+import org.hibernate.jpa.boot.spi.PackageDescriptor;
+import org.hibernate.jpa.boot.spi.PersistenceUnitDescriptor;
+
+/**
+ * @author Steve Ebersole
+ */
+public abstract class AbstractScannerImpl implements Scanner {
+ private final ArchiveDescriptorFactory archiveDescriptorFactory;
+ private final Map archiveDescriptorCache = new HashMap();
+
+ protected AbstractScannerImpl(ArchiveDescriptorFactory archiveDescriptorFactory) {
+ this.archiveDescriptorFactory = archiveDescriptorFactory;
+ }
+
+ @Override
+ public ScanResult scan(PersistenceUnitDescriptor persistenceUnit, ScanOptions scanOptions) {
+ final ResultCollector resultCollector = new ResultCollector( scanOptions );
+
+ if ( persistenceUnit.getJarFileUrls() != null ) {
+ for ( URL url : persistenceUnit.getJarFileUrls() ) {
+ final ArchiveDescriptor descriptor = buildArchiveDescriptor( url, false, scanOptions );
+ final ArchiveContext context = buildArchiveContext( persistenceUnit, false, resultCollector );
+ descriptor.visitArchive( context );
+ }
+ }
+
+ if ( persistenceUnit.getPersistenceUnitRootUrl() != null ) {
+ final ArchiveDescriptor descriptor = buildArchiveDescriptor( persistenceUnit.getPersistenceUnitRootUrl(), true, scanOptions );
+ final ArchiveContext context = buildArchiveContext( persistenceUnit, false, resultCollector );
+ descriptor.visitArchive( context );
+ }
+
+ return ScanResultImpl.from( resultCollector );
+ }
+
+ private ArchiveContext buildArchiveContext(
+ PersistenceUnitDescriptor persistenceUnit,
+ boolean isRoot,
+ ArchiveEntryHandlers entryHandlers) {
+ return new ArchiveContextImpl( persistenceUnit, isRoot, entryHandlers );
+ }
+
+ protected static interface ArchiveEntryHandlers {
+ public ArchiveEntryHandler getClassFileHandler();
+ public ArchiveEntryHandler getPackageInfoHandler();
+ public ArchiveEntryHandler getFileHandler();
+ }
+
+ private ArchiveDescriptor buildArchiveDescriptor(URL url, boolean isRootUrl, ScanOptions scanOptions) {
+ final ArchiveDescriptor descriptor;
+ final ArchiveDescriptorInfo descriptorInfo = archiveDescriptorCache.get( url );
+ if ( descriptorInfo == null ) {
+ descriptor = archiveDescriptorFactory.buildArchiveDescriptor( url );
+ archiveDescriptorCache.put(
+ url,
+ new ArchiveDescriptorInfo( descriptor, isRootUrl, scanOptions )
+ );
+ }
+ else {
+ validateReuse( descriptorInfo, isRootUrl, scanOptions );
+ descriptor = descriptorInfo.archiveDescriptor;
+ }
+ return descriptor;
+ }
+
+ public static class ResultCollector
+ implements ArchiveEntryHandlers,
+ PackageInfoArchiveEntryHandler.Callback,
+ ClassFileArchiveEntryHandler.Callback,
+ NonClassFileArchiveEntryHandler.Callback {
+ private final ClassFileArchiveEntryHandler classFileHandler;
+ private final PackageInfoArchiveEntryHandler packageInfoHandler;
+ private final NonClassFileArchiveEntryHandler fileHandler;
+
+ private final Set packageDescriptorSet = new HashSet();
+ private final Set classDescriptorSet = new HashSet();
+ private final Set mappingFileSet = new HashSet();
+
+ public ResultCollector(ScanOptions scanOptions) {
+ this.classFileHandler = new ClassFileArchiveEntryHandler( scanOptions, this );
+ this.packageInfoHandler = new PackageInfoArchiveEntryHandler( scanOptions, this );
+ this.fileHandler = new NonClassFileArchiveEntryHandler( scanOptions, this );
+ }
+
+ @Override
+ public ArchiveEntryHandler getClassFileHandler() {
+ return classFileHandler;
+ }
+
+ @Override
+ public ArchiveEntryHandler getPackageInfoHandler() {
+ return packageInfoHandler;
+ }
+
+ @Override
+ public ArchiveEntryHandler getFileHandler() {
+ return fileHandler;
+ }
+
+ @Override
+ public void locatedPackage(PackageDescriptor packageDescriptor) {
+ if ( PackageDescriptorImpl.class.isInstance( packageDescriptor ) ) {
+ packageDescriptorSet.add( packageDescriptor );
+ }
+ else {
+ // to make sure we have proper equals/hashcode
+ packageDescriptorSet.add(
+ new PackageDescriptorImpl(
+ packageDescriptor.getName(),
+ packageDescriptor.getStreamAccess()
+ )
+ );
+ }
+ }
+
+ @Override
+ public void locatedClass(ClassDescriptor classDescriptor) {
+ if ( ClassDescriptorImpl.class.isInstance( classDescriptor ) ) {
+ classDescriptorSet.add( classDescriptor );
+ }
+ else {
+ // to make sure we have proper equals/hashcode
+ classDescriptorSet.add(
+ new ClassDescriptorImpl(
+ classDescriptor.getName(),
+ classDescriptor.getStreamAccess()
+ )
+ );
+ }
+ }
+
+ @Override
+ public void locatedMappingFile(MappingFileDescriptor mappingFileDescriptor) {
+ if ( MappingFileDescriptorImpl.class.isInstance( mappingFileDescriptor ) ) {
+ mappingFileSet.add( mappingFileDescriptor );
+ }
+ else {
+ // to make sure we have proper equals/hashcode
+ mappingFileSet.add(
+ new MappingFileDescriptorImpl(
+ mappingFileDescriptor.getName(),
+ mappingFileDescriptor.getStreamAccess()
+ )
+ );
+ }
+ }
+
+ public Set getPackageDescriptorSet() {
+ return packageDescriptorSet;
+ }
+
+ public Set getClassDescriptorSet() {
+ return classDescriptorSet;
+ }
+
+ public Set getMappingFileSet() {
+ return mappingFileSet;
+ }
+ }
+
+ private static class ArchiveDescriptorInfo {
+ private final ArchiveDescriptor archiveDescriptor;
+ private final boolean isRoot;
+ private final ScanOptions scanOptions;
+
+ private ArchiveDescriptorInfo(
+ ArchiveDescriptor archiveDescriptor,
+ boolean isRoot,
+ ScanOptions scanOptions) {
+ this.archiveDescriptor = archiveDescriptor;
+ this.isRoot = isRoot;
+ this.scanOptions = scanOptions;
+ }
+ }
+
+ protected void validateReuse(ArchiveDescriptorInfo descriptor, boolean root, ScanOptions options) {
+ // is it really reasonable that a single url be processed multiple times?
+ // for now, throw an exception, mainly because I am interested in situations where this might happen
+ throw new IllegalStateException( "ArchiveDescriptor reused; can URLs be processed multiple times?" );
+ }
+
+ public static class ArchiveContextImpl implements ArchiveContext {
+ private final PersistenceUnitDescriptor persistenceUnitDescriptor;
+ private final boolean isRootUrl;
+ private final ArchiveEntryHandlers entryHandlers;
+
+ public ArchiveContextImpl(
+ PersistenceUnitDescriptor persistenceUnitDescriptor,
+ boolean isRootUrl,
+ ArchiveEntryHandlers entryHandlers) {
+ this.persistenceUnitDescriptor = persistenceUnitDescriptor;
+ this.isRootUrl = isRootUrl;
+ this.entryHandlers = entryHandlers;
+ }
+
+ @Override
+ public PersistenceUnitDescriptor getPersistenceUnitDescriptor() {
+ return persistenceUnitDescriptor;
+ }
+
+ @Override
+ public boolean isRootUrl() {
+ return isRootUrl;
+ }
+
+ @Override
+ public ArchiveEntryHandler obtainArchiveEntryHandler(ArchiveEntry entry) {
+ final String nameWithinArchive = entry.getNameWithinArchive();
+
+ if ( nameWithinArchive.endsWith( "package-info.class" ) ) {
+ return entryHandlers.getPackageInfoHandler();
+ }
+ else if ( nameWithinArchive.endsWith( ".class" ) ) {
+ return entryHandlers.getClassFileHandler();
+ }
+ else {
+ return entryHandlers.getFileHandler();
+ }
+ }
+ }
+
+ private static class ScanResultImpl implements ScanResult {
+ private final Set packageDescriptorSet;
+ private final Set classDescriptorSet;
+ private final Set mappingFileSet;
+
+ private ScanResultImpl(
+ Set packageDescriptorSet,
+ Set classDescriptorSet,
+ Set mappingFileSet) {
+ this.packageDescriptorSet = packageDescriptorSet;
+ this.classDescriptorSet = classDescriptorSet;
+ this.mappingFileSet = mappingFileSet;
+ }
+
+ private static ScanResult from(ResultCollector resultCollector) {
+ return new ScanResultImpl(
+ Collections.unmodifiableSet( resultCollector.packageDescriptorSet ),
+ Collections.unmodifiableSet( resultCollector.classDescriptorSet ),
+ Collections.unmodifiableSet( resultCollector.mappingFileSet )
+ );
+ }
+
+ @Override
+ public Set getLocatedPackages() {
+ return packageDescriptorSet;
+ }
+
+ @Override
+ public Set getLocatedClasses() {
+ return classDescriptorSet;
+ }
+
+ @Override
+ public Set getLocatedMappingFiles() {
+ return mappingFileSet;
+ }
+ }
+
+}
diff --git a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/boot/scan/spi/ClassFileArchiveEntryHandler.java b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/boot/scan/spi/ClassFileArchiveEntryHandler.java
new file mode 100644
index 0000000000..33c61005b7
--- /dev/null
+++ b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/boot/scan/spi/ClassFileArchiveEntryHandler.java
@@ -0,0 +1,125 @@
+/*
+ * 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.jpa.boot.scan.spi;
+
+import javax.persistence.Converter;
+import javax.persistence.Embeddable;
+import javax.persistence.Entity;
+import javax.persistence.MappedSuperclass;
+import java.io.DataInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+import javassist.bytecode.AnnotationsAttribute;
+import javassist.bytecode.ClassFile;
+
+import org.hibernate.jpa.boot.archive.spi.ArchiveContext;
+import org.hibernate.jpa.boot.archive.spi.ArchiveEntry;
+import org.hibernate.jpa.boot.archive.spi.ArchiveException;
+import org.hibernate.jpa.boot.internal.ClassDescriptorImpl;
+import org.hibernate.jpa.boot.spi.ClassDescriptor;
+
+/**
+ * Defines handling and filtering for class file entries within an archive
+ *
+ * @author Steve Ebersole
+ */
+public class ClassFileArchiveEntryHandler extends AbstractJavaArtifactArchiveEntryHandler {
+ private final Callback callback;
+
+ /**
+ * Contract for the thing interested in being notified about accepted class descriptors.
+ */
+ public static interface Callback {
+ public void locatedClass(ClassDescriptor classDescriptor);
+ }
+
+ public ClassFileArchiveEntryHandler(ScanOptions scanOptions, Callback callback) {
+ super( scanOptions );
+ this.callback = callback;
+ }
+
+ @Override
+ public void handleEntry(ArchiveEntry entry, ArchiveContext context) {
+ final ClassFile classFile = toClassFile( entry );
+ final ClassDescriptor classDescriptor = toClassDescriptor( classFile, entry );
+
+ if ( ! isListedOrDetectable( context, classDescriptor.getName() ) ) {
+ return;
+ }
+
+ // we are only interested in classes with certain annotations, so see if the ClassDescriptor
+ // represents a class which contains any of those annotations
+ if ( ! containsClassAnnotationsOfInterest( classFile ) ) {
+ return;
+ }
+
+ notifyMatchedClass( classDescriptor );
+ }
+
+ private ClassFile toClassFile(ArchiveEntry entry) {
+ final InputStream inputStream = entry.getStreamAccess().accessInputStream();
+ final DataInputStream dataInputStream = new DataInputStream( inputStream );
+ try {
+ return new ClassFile( dataInputStream );
+ }
+ catch (IOException e) {
+ throw new ArchiveException( "Could not build ClassFile" );
+ }
+ finally {
+ try {
+ dataInputStream.close();
+ }
+ catch (Exception ignore) {
+ }
+
+ try {
+ inputStream.close();
+ }
+ catch (IOException ignore) {
+ }
+ }
+ }
+
+ @SuppressWarnings("SimplifiableIfStatement")
+ private boolean containsClassAnnotationsOfInterest(ClassFile cf) {
+ final AnnotationsAttribute visibleAnnotations = (AnnotationsAttribute) cf.getAttribute( AnnotationsAttribute.visibleTag );
+ if ( visibleAnnotations == null ) {
+ return false;
+ }
+
+ return visibleAnnotations.getAnnotation( Entity.class.getName() ) != null
+ || visibleAnnotations.getAnnotation( MappedSuperclass.class.getName() ) != null
+ || visibleAnnotations.getAnnotation( Embeddable.class.getName() ) != null
+ || visibleAnnotations.getAnnotation( Converter.class.getName() ) != null;
+ }
+
+ protected ClassDescriptor toClassDescriptor(ClassFile classFile, ArchiveEntry entry) {
+ return new ClassDescriptorImpl( classFile.getName(), entry.getStreamAccess() );
+ }
+
+ protected final void notifyMatchedClass(ClassDescriptor classDescriptor) {
+ callback.locatedClass( classDescriptor );
+ }
+}
diff --git a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/boot/scan/spi/NonClassFileArchiveEntryHandler.java b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/boot/scan/spi/NonClassFileArchiveEntryHandler.java
new file mode 100644
index 0000000000..5e6fccb2fb
--- /dev/null
+++ b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/boot/scan/spi/NonClassFileArchiveEntryHandler.java
@@ -0,0 +1,87 @@
+/*
+ * 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.jpa.boot.scan.spi;
+
+import org.hibernate.jpa.boot.archive.spi.ArchiveContext;
+import org.hibernate.jpa.boot.archive.spi.ArchiveEntry;
+import org.hibernate.jpa.boot.archive.spi.ArchiveEntryHandler;
+import org.hibernate.jpa.boot.internal.MappingFileDescriptorImpl;
+import org.hibernate.jpa.boot.spi.MappingFileDescriptor;
+
+/**
+ * Defines handling and filtering for all non-class file (package-info is also a class file...) entries within an archive
+ *
+ * @author Steve Ebersole
+ */
+public class NonClassFileArchiveEntryHandler implements ArchiveEntryHandler {
+ private final ScanOptions scanOptions;
+ private final Callback callback;
+
+ /**
+ * Contract for the thing interested in being notified about accepted mapping file descriptors.
+ */
+ public static interface Callback {
+ public void locatedMappingFile(MappingFileDescriptor mappingFileDescriptor);
+ }
+
+ public NonClassFileArchiveEntryHandler(ScanOptions scanOptions, Callback callback) {
+ this.scanOptions = scanOptions;
+ this.callback = callback;
+ }
+
+ @Override
+ public void handleEntry(ArchiveEntry entry, ArchiveContext context) {
+ if ( acceptAsMappingFile( entry, context) ) {
+ notifyMatchedMappingFile( entry );
+ }
+ }
+
+ @SuppressWarnings("SimplifiableIfStatement")
+ private boolean acceptAsMappingFile(ArchiveEntry entry, ArchiveContext context) {
+ if ( entry.getName().endsWith( "hbm.xml" ) ) {
+ return scanOptions.canDetectHibernateMappingFiles();
+ }
+
+ // todo : should really do this case-insensitively
+ if ( entry.getName().endsWith( "META-INF/orm.xml" ) ) {
+ if ( context.getPersistenceUnitDescriptor().getMappingFileNames().contains( "META-INF/orm.xml" ) ) {
+ // if the user explicitly listed META-INF/orm.xml, only except the root one
+ //
+ // not sure why exactly, but this is what the old code does
+ return context.isRootUrl();
+ }
+ return true;
+ }
+
+ return context.getPersistenceUnitDescriptor().getMappingFileNames().contains( entry.getNameWithinArchive() );
+ }
+
+ protected final void notifyMatchedMappingFile(ArchiveEntry entry) {
+ callback.locatedMappingFile( toMappingFileDescriptor( entry ) );
+ }
+
+ protected MappingFileDescriptor toMappingFileDescriptor(ArchiveEntry entry) {
+ return new MappingFileDescriptorImpl( entry.getNameWithinArchive(), entry.getStreamAccess() );
+ }
+}
diff --git a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/boot/scan/spi/PackageInfoArchiveEntryHandler.java b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/boot/scan/spi/PackageInfoArchiveEntryHandler.java
new file mode 100644
index 0000000000..d824ef015e
--- /dev/null
+++ b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/boot/scan/spi/PackageInfoArchiveEntryHandler.java
@@ -0,0 +1,79 @@
+/*
+ * 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.jpa.boot.scan.spi;
+
+import org.hibernate.jpa.boot.archive.spi.ArchiveContext;
+import org.hibernate.jpa.boot.archive.spi.ArchiveEntry;
+import org.hibernate.jpa.boot.internal.PackageDescriptorImpl;
+import org.hibernate.jpa.boot.spi.PackageDescriptor;
+
+import static java.io.File.separatorChar;
+
+/**
+ * Defines handling and filtering for package-info file entries within an archive
+ *
+ * @author Steve Ebersole
+ */
+public class PackageInfoArchiveEntryHandler extends AbstractJavaArtifactArchiveEntryHandler {
+ private final Callback callback;
+
+ /**
+ * Contract for the thing interested in being notified about accepted package-info descriptors.
+ */
+ public static interface Callback {
+ public void locatedPackage(PackageDescriptor packageDescriptor);
+ }
+
+ public PackageInfoArchiveEntryHandler(ScanOptions scanOptions, Callback callback) {
+ super( scanOptions );
+ this.callback = callback;
+ }
+
+ @Override
+ public void handleEntry(ArchiveEntry entry, ArchiveContext context) {
+ if ( entry.getNameWithinArchive().equals( "package-info.class" ) ) {
+ // the old code skipped package-info in the root package/dir...
+ return;
+ }
+
+ if ( ! isListedOrDetectable( context, entry.getName() ) ) {
+ // the package is not explicitly listed, and we are not allowed to detect it.
+ return;
+ }
+
+ notifyMatchedPackage( toPackageDescriptor( entry ) );
+ }
+
+ protected PackageDescriptor toPackageDescriptor(ArchiveEntry entry) {
+ final String packageInfoFilePath = entry.getNameWithinArchive();
+ final String packageName = packageInfoFilePath.substring( 0, packageInfoFilePath.lastIndexOf( '/' ) )
+ .replace( separatorChar, '.' );
+
+ return new PackageDescriptorImpl( packageName, entry.getStreamAccess() );
+ }
+
+ protected final void notifyMatchedPackage(PackageDescriptor packageDescriptor) {
+ callback.locatedPackage( packageDescriptor );
+ }
+}
diff --git a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/packaging/internal/PackageFilter.java b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/boot/scan/spi/ScanOptions.java
similarity index 63%
rename from hibernate-entitymanager/src/main/java/org/hibernate/jpa/packaging/internal/PackageFilter.java
rename to hibernate-entitymanager/src/main/java/org/hibernate/jpa/boot/scan/spi/ScanOptions.java
index d8ded44656..a5ec564a8d 100644
--- a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/packaging/internal/PackageFilter.java
+++ b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/boot/scan/spi/ScanOptions.java
@@ -1,8 +1,10 @@
/*
- * Copyright (c) 2009, Red Hat Middleware LLC or third-party contributors as
+ * 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 Middleware LLC.
+ * 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
@@ -19,20 +21,14 @@
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
-package org.hibernate.jpa.packaging.internal;
-
+package org.hibernate.jpa.boot.scan.spi;
/**
- * Filter on pachage element
- *
- * @author Emmanuel Bernard
- * @see JavaElementFilter
+ * @author Steve Ebersole
*/
-public abstract class PackageFilter extends JavaElementFilter {
- /**
- * @see JavaElementFilter#JavaElementFilter(boolean, Class[])
- */
- protected PackageFilter(boolean retrieveStream, Class[] annotations) {
- super( retrieveStream, annotations );
- }
-}
\ No newline at end of file
+public interface ScanOptions {
+ public boolean canDetectUnlistedClassesInRoot();
+ public boolean canDetectUnlistedClassesInNonRoot();
+
+ public boolean canDetectHibernateMappingFiles();
+}
diff --git a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/boot/scan/spi/ScanResult.java b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/boot/scan/spi/ScanResult.java
new file mode 100644
index 0000000000..13e0fa02f9
--- /dev/null
+++ b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/boot/scan/spi/ScanResult.java
@@ -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.jpa.boot.scan.spi;
+
+import java.util.Set;
+
+import org.hibernate.jpa.boot.spi.ClassDescriptor;
+import org.hibernate.jpa.boot.spi.MappingFileDescriptor;
+import org.hibernate.jpa.boot.spi.PackageDescriptor;
+
+/**
+ * Defines the result of scanning
+ *
+ * @author Steve Ebersole
+ */
+public interface ScanResult {
+ public Set getLocatedPackages();
+ public Set getLocatedClasses();
+ public Set getLocatedMappingFiles();
+}
diff --git a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/packaging/internal/JarVisitor.java b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/boot/scan/spi/Scanner.java
similarity index 53%
rename from hibernate-entitymanager/src/main/java/org/hibernate/jpa/packaging/internal/JarVisitor.java
rename to hibernate-entitymanager/src/main/java/org/hibernate/jpa/boot/scan/spi/Scanner.java
index cbb829ee3e..d57b54cb76 100644
--- a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/packaging/internal/JarVisitor.java
+++ b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/boot/scan/spi/Scanner.java
@@ -1,8 +1,10 @@
/*
- * Copyright (c) 2009, Red Hat Middleware LLC or third-party contributors as
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2012, 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 Middleware LLC.
+ * 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
@@ -19,28 +21,26 @@
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
-package org.hibernate.jpa.packaging.internal;
-import java.io.IOException;
-import java.util.Set;
+package org.hibernate.jpa.boot.scan.spi;
+
+import org.hibernate.jpa.boot.spi.PersistenceUnitDescriptor;
/**
+ * Defines the contract for Hibernate to be able to scan for classes, packages and resources inside a
+ * persistence unit.
+ *
* @author Emmanuel Bernard
+ * @author Steve Ebersole
*/
-public interface JarVisitor {
+public interface Scanner {
/**
- * Get the unqualified Jar name (ie wo path and wo extension)
+ * Perform the scanning against the described persistence unit using the defined options, and return the scan
+ * results.
*
- * @return the unqualified jar name.
- */
- String getUnqualifiedJarName();
-
- Filter[] getFilters();
-
- /**
- * Return the matching entries for each filter in the same order the filter where passed
+ * @param persistenceUnit THe description of the persistence unit.
+ * @param options The scan options
*
- * @return array of Set of JarVisitor.Entry
- * @throws java.io.IOException if something went wrong
+ * @return The scan results.
*/
- Set[] getMatchingEntries() throws IOException;
+ public ScanResult scan(PersistenceUnitDescriptor persistenceUnit, ScanOptions options);
}
diff --git a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/boot/spi/ClassDescriptor.java b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/boot/spi/ClassDescriptor.java
new file mode 100644
index 0000000000..c04e57d9c0
--- /dev/null
+++ b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/boot/spi/ClassDescriptor.java
@@ -0,0 +1,34 @@
+/*
+ * 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.jpa.boot.spi;
+
+/**
+ * Defines the result of scanning a persistence unit for classes.
+ *
+ * @author Steve Ebersole
+ */
+public interface ClassDescriptor {
+ public String getName();
+ public InputStreamAccess getStreamAccess();
+}
diff --git a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/boot/spi/InputStreamAccess.java b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/boot/spi/InputStreamAccess.java
new file mode 100644
index 0000000000..cb51b1ada5
--- /dev/null
+++ b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/boot/spi/InputStreamAccess.java
@@ -0,0 +1,52 @@
+/*
+ * 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.jpa.boot.spi;
+
+import java.io.InputStream;
+
+/**
+ * Contract for building InputStreams, especially in on-demand situations
+ *
+ * @author Steve Ebersole
+ */
+public interface InputStreamAccess {
+ /**
+ * Get the name of the resource backing the stream
+ *
+ * @return The backing resource name
+ */
+ public String getStreamName();
+
+ /**
+ * Get access to the stream. Can be called multiple times, a different stream instance should be returned each time.
+ *
+ * @return The stream
+ */
+ public InputStream accessInputStream();
+
+ /**
+ * @deprecated Needed until we can remove NamedInputStream
+ */
+ public NamedInputStream asNamedInputStream();
+}
diff --git a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/boot/spi/MappingFileDescriptor.java b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/boot/spi/MappingFileDescriptor.java
new file mode 100644
index 0000000000..5dfec7b9cb
--- /dev/null
+++ b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/boot/spi/MappingFileDescriptor.java
@@ -0,0 +1,32 @@
+/*
+ * 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.jpa.boot.spi;
+
+/**
+ * @author Steve Ebersole
+ */
+public interface MappingFileDescriptor {
+ public String getName();
+ public InputStreamAccess getStreamAccess();
+}
diff --git a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/packaging/spi/NamedInputStream.java b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/boot/spi/NamedInputStream.java
similarity index 80%
rename from hibernate-entitymanager/src/main/java/org/hibernate/jpa/packaging/spi/NamedInputStream.java
rename to hibernate-entitymanager/src/main/java/org/hibernate/jpa/boot/spi/NamedInputStream.java
index b0dfe020ac..fd6abed28f 100644
--- a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/packaging/spi/NamedInputStream.java
+++ b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/boot/spi/NamedInputStream.java
@@ -21,34 +21,33 @@
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
-package org.hibernate.jpa.packaging.spi;
+package org.hibernate.jpa.boot.spi;
+
import java.io.InputStream;
/**
+ * Bundles together a stream and the name that was used to locate it. The name is often useful for logging.
+ *
+ * @deprecated Use {@link org.hibernate.jpa.boot.spi.InputStreamAccess} instead.
+ *
* @author Emmanuel Bernard
+ * @author Steve Ebersole
*/
+@Deprecated
public class NamedInputStream {
+ private final String name;
+ private final InputStream stream;
+
public NamedInputStream(String name, InputStream stream) {
this.name = name;
this.stream = stream;
}
- private String name;
- private InputStream stream;
-
public InputStream getStream() {
return stream;
}
- public void setStream(InputStream stream) {
- this.stream = stream;
- }
-
public String getName() {
return name;
}
-
- public void setName(String name) {
- this.name = name;
- }
}
diff --git a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/boot/spi/PackageDescriptor.java b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/boot/spi/PackageDescriptor.java
new file mode 100644
index 0000000000..101e516575
--- /dev/null
+++ b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/boot/spi/PackageDescriptor.java
@@ -0,0 +1,34 @@
+/*
+ * 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.jpa.boot.spi;
+
+/**
+ * Defines the result of scanning a persistence unit for packages.
+ *
+ * @author Steve Ebersole
+ */
+public interface PackageDescriptor {
+ public String getName();
+ public InputStreamAccess getStreamAccess();
+}
diff --git a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/packaging/internal/AbstractJarVisitor.java b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/packaging/internal/AbstractJarVisitor.java
deleted file mode 100644
index b857f9d237..0000000000
--- a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/packaging/internal/AbstractJarVisitor.java
+++ /dev/null
@@ -1,262 +0,0 @@
-/*
- * Copyright (c) 2009, Red Hat Middleware LLC 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 Middleware LLC.
- *
- * 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.jpa.packaging.internal;
-
-import java.io.DataInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.net.URL;
-import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-
-import javassist.bytecode.AnnotationsAttribute;
-import javassist.bytecode.ClassFile;
-import org.jboss.logging.Logger;
-
-import org.hibernate.jpa.internal.EntityManagerMessageLogger;
-
-/**
- * Parse a JAR of any form (zip file, exploded directory, ...)
- * apply a set of filters (File filter, Class filter, Package filter)
- * and return the appropriate matching sets of elements
- *
- * @author Emmanuel Bernard
- */
-public abstract class AbstractJarVisitor implements JarVisitor {
-
- //TODO shortcut when filters are null or empty
-
- private static final EntityManagerMessageLogger LOG = Logger.getMessageLogger(EntityManagerMessageLogger.class,
- AbstractJarVisitor.class.getName());
-
- protected String unqualifiedJarName;
- protected URL jarUrl;
- protected boolean done = false;
- private List filters = new ArrayList();
- private Set fileFilters = new HashSet();
- private Set classFilters = new HashSet();
- private Set packageFilters = new HashSet();
- private Set[] entries;
-
-
-
- /**
- * Build a jar visitor from its jar string path
- */
- private AbstractJarVisitor(String jarPath) {
- this.jarUrl = JarVisitorFactory.getURLFromPath( jarPath );
- unqualify();
- }
-
- protected AbstractJarVisitor(String fileName, Filter[] filters) {
- this( fileName );
- initFilters( filters );
- }
-
- private void initFilters(Filter[] filters) {
- for ( Filter filter : filters ) {
- if ( filter instanceof FileFilter ) {
- fileFilters.add( (FileFilter) filter );
- }
- else if ( filter instanceof ClassFilter ) {
- classFilters.add( (ClassFilter) filter );
- }
- else if ( filter instanceof PackageFilter ) {
- packageFilters.add( (PackageFilter) filter );
- }
- else {
- throw new AssertionError( "Unknown filter type: " + filter.getClass().getName() );
- }
- this.filters.add( filter );
- }
- int size = this.filters.size();
- this.entries = new Set[ size ];
- for ( int index = 0; index < size ; index++ ) {
- this.entries[index] = new HashSet();
- }
- }
-
- protected AbstractJarVisitor(URL url, Filter[] filters) {
- this( url );
- initFilters( filters );
- }
-
- private AbstractJarVisitor(URL url) {
- jarUrl = url;
- unqualify();
- }
-
- protected void unqualify() {
- //FIXME weak algorithm subject to AOOBE
- String fileName = jarUrl.getFile();
- int exclamation = fileName.lastIndexOf( "!" );
- if (exclamation != -1) fileName = fileName.substring( 0, exclamation );
- int slash = fileName.lastIndexOf( "/" );
- if ( slash != -1 ) {
- fileName = fileName.substring(
- fileName.lastIndexOf( "/" ) + 1,
- fileName.length()
- );
- }
- if ( fileName.length() > 4 && fileName.endsWith( "ar" ) && fileName.charAt( fileName.length() - 4 ) == '.' ) {
- fileName = fileName.substring( 0, fileName.length() - 4 );
- }
- unqualifiedJarName = fileName;
- LOG.debugf("Searching mapped entities in jar/par: %s", jarUrl);
- }
-
- /**
- * Get the unqualified Jar name (ie wo path and wo extension)
- */
- public String getUnqualifiedJarName() {
- return unqualifiedJarName;
- }
-
- public Filter[] getFilters() {
- return filters.toArray( new Filter[ filters.size() ] );
- }
-
- /**
- * Return the matching entries for each filter in the same order the filter where passed
- *
- * @return array of Set of JarVisitor.Entry
- * @throws IOException if something went wrong
- */
- public Set[] getMatchingEntries() throws IOException {
- if ( !done ) {
- //avoid url access and so on
- if ( filters.size() > 0 ) doProcessElements();
- done = true;
- }
- return entries;
- }
-
- protected abstract void doProcessElements() throws IOException;
-
- //TODO avoid 2 input stream when not needed
- protected final void addElement(String entryName, InputStream is, InputStream secondIs) throws IOException {
- int entryNameLength = entryName.length();
- if ( entryName.endsWith( "package-info.class" ) ) {
- String name;
- if ( entryNameLength == "package-info.class".length() ) {
- name = "";
- }
- else {
- name = entryName.substring( 0, entryNameLength - ".package-info.class".length() ).replace( '/', '.' );
- }
- executeJavaElementFilter( name, packageFilters, is, secondIs );
- }
- else if ( entryName.endsWith( ".class" ) ) {
- String name = entryName.substring( 0, entryNameLength - ".class".length() ).replace( '/', '.' );
- LOG.debugf("Filtering: %s", name);
- executeJavaElementFilter( name, classFilters, is, secondIs );
- }
- else {
- String name = entryName;
- boolean accepted = false;
- for ( FileFilter filter : fileFilters ) {
- if ( filter.accept( name ) ) {
- accepted = true;
- InputStream localIs;
- if ( filter.getStream() ) {
- localIs = secondIs;
- }
- else {
- localIs = null;
- secondIs.close();
- }
- is.close();
- LOG.debugf("File Filter matched for %s", name);
- Entry entry = new Entry( name, localIs );
- int index = this.filters.indexOf( filter );
- this.entries[index].add( entry );
- }
- }
- if (!accepted) {
- //not accepted free resources
- is.close();
- secondIs.close();
- }
- }
- }
-
- private void executeJavaElementFilter(
- String name, Set filters, InputStream is, InputStream secondIs
- ) throws IOException {
- boolean accepted = false;
- for ( JavaElementFilter filter : filters ) {
- if ( filter.accept( name ) ) {
- //FIXME cannot currently have a class filtered twice but matching once
- // need to copy the is
- boolean match = checkAnnotationMatching( is, filter );
- if ( match ) {
- accepted = true;
- InputStream localIs;
- if ( filter.getStream() ) {
- localIs = secondIs;
- }
- else {
- localIs = null;
- secondIs.close();
- }
- LOG.debugf("Java element filter matched for %s", name);
- Entry entry = new Entry( name, localIs );
- int index = this.filters.indexOf( filter );
- this.entries[index].add( entry );
- break; //we matched
- }
- }
- }
- if (!accepted) {
- is.close();
- secondIs.close();
- }
- }
-
- private boolean checkAnnotationMatching(InputStream is, JavaElementFilter filter) throws IOException {
- if ( filter.getAnnotations().length == 0 ) {
- is.close();
- return true;
- }
- DataInputStream dstream = new DataInputStream( is );
- ClassFile cf = null;
-
- try {
- cf = new ClassFile( dstream );
- }
- finally {
- dstream.close();
- is.close();
- }
- boolean match = false;
- AnnotationsAttribute visible = (AnnotationsAttribute) cf.getAttribute( AnnotationsAttribute.visibleTag );
- if ( visible != null ) {
- for ( Class annotation : filter.getAnnotations() ) {
- match = visible.getAnnotation( annotation.getName() ) != null;
- if ( match ) break;
- }
- }
- return match;
- }
-}
diff --git a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/packaging/internal/ExplodedJarVisitor.java b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/packaging/internal/ExplodedJarVisitor.java
deleted file mode 100644
index cef0a7d9aa..0000000000
--- a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/packaging/internal/ExplodedJarVisitor.java
+++ /dev/null
@@ -1,138 +0,0 @@
-/*
- * Copyright (c) 2009, Red Hat Middleware LLC 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 Middleware LLC.
- *
- * 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.jpa.packaging.internal;
-
-import java.io.BufferedInputStream;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.net.URISyntaxException;
-import java.net.URL;
-import java.util.Enumeration;
-import java.util.jar.JarFile;
-import java.util.zip.ZipEntry;
-
-import org.jboss.logging.Logger;
-
-import org.hibernate.jpa.internal.EntityManagerMessageLogger;
-
-
-/**
- * @author Emmanuel Bernard
- */
-public class ExplodedJarVisitor extends AbstractJarVisitor {
-
- private static final EntityManagerMessageLogger LOG = Logger.getMessageLogger(EntityManagerMessageLogger.class,
- ExplodedJarVisitor.class.getName());
-
- private String entry;
-
- public ExplodedJarVisitor(URL url, Filter[] filters, String entry) {
- super( url, filters );
- this.entry = entry;
- }
-
- public ExplodedJarVisitor(String fileName, Filter[] filters) {
- super( fileName, filters );
- }
-
- @Override
- protected void doProcessElements() throws IOException {
- File jarFile;
- try {
- String filePart = jarUrl.getFile();
- if ( filePart != null && filePart.indexOf( ' ' ) != -1 ) {
- //unescaped (from the container), keep as is
- jarFile = new File( jarUrl.getFile() );
- }
- else {
- jarFile = new File( jarUrl.toURI().getSchemeSpecificPart() );
- }
- }
- catch (URISyntaxException e) {
- LOG.malformedUrl(jarUrl, e);
- return;
- }
-
- if ( !jarFile.exists() ) {
- LOG.explodedJarDoesNotExist(jarUrl);
- return;
- }
- if ( !jarFile.isDirectory() ) {
- LOG.explodedJarNotDirectory(jarUrl);
- return;
- }
- File rootFile;
- if (entry != null && entry.length() > 0 && ! "/".equals( entry ) ) {
- rootFile = new File(jarFile, entry);
- }
- else {
- rootFile = jarFile;
- }
- if ( rootFile.isDirectory() ) {
- getClassNamesInTree( rootFile, null );
- }
- else {
- //assume zipped file
- processZippedRoot(rootFile);
- }
- }
-
- //FIXME shameful copy of FileZippedJarVisitor.doProcess()
- //TODO long term fix is to introduce a process interface (closure like) to addElements and then share the code
- private void processZippedRoot(File rootFile) throws IOException {
- JarFile jarFile = new JarFile(rootFile);
- Enumeration extends ZipEntry> entries = jarFile.entries();
- while ( entries.hasMoreElements() ) {
- ZipEntry zipEntry = entries.nextElement();
- String name = zipEntry.getName();
- if ( !zipEntry.isDirectory() ) {
- //build relative name
- if ( name.startsWith( "/" ) ) name = name.substring( 1 );
- addElement(
- name,
- new BufferedInputStream( jarFile.getInputStream( zipEntry ) ),
- new BufferedInputStream( jarFile.getInputStream( zipEntry ) )
- );
- }
- }
- }
-
- private void getClassNamesInTree(File jarFile, String header) throws IOException {
- File[] files = jarFile.listFiles();
- header = header == null ? "" : header + "/";
- for ( File localFile : files ) {
- if ( !localFile.isDirectory() ) {
- String entryName = localFile.getName();
- addElement(
- header + entryName,
- new BufferedInputStream( new FileInputStream( localFile ) ),
- new BufferedInputStream( new FileInputStream( localFile ) )
- );
-
- }
- else {
- getClassNamesInTree( localFile, header + localFile.getName() );
- }
- }
- }
-}
diff --git a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/packaging/internal/FileZippedJarVisitor.java b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/packaging/internal/FileZippedJarVisitor.java
deleted file mode 100644
index 8dd003ce59..0000000000
--- a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/packaging/internal/FileZippedJarVisitor.java
+++ /dev/null
@@ -1,133 +0,0 @@
-/*
- * Copyright (c) 2009, Red Hat Middleware LLC 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 Middleware LLC.
- *
- * 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.jpa.packaging.internal;
-
-import java.io.BufferedInputStream;
-import java.io.ByteArrayInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.net.URISyntaxException;
-import java.net.URL;
-import java.util.Enumeration;
-import java.util.jar.JarFile;
-import java.util.jar.JarInputStream;
-import java.util.zip.ZipEntry;
-
-import org.jboss.logging.Logger;
-
-import org.hibernate.jpa.internal.EntityManagerMessageLogger;
-
-/**
- * Work on a JAR that can be accessed through a File
- *
- * @author Emmanuel Bernard
- */
-public class FileZippedJarVisitor extends AbstractJarVisitor {
-
- private static final EntityManagerMessageLogger LOG = Logger.getMessageLogger(EntityManagerMessageLogger.class,
- FileZippedJarVisitor.class.getName());
-
- private String entry;
-
- public FileZippedJarVisitor(String fileName, Filter[] filters) {
- super( fileName, filters );
- }
-
- public FileZippedJarVisitor(URL url, Filter[] filters, String entry) {
- super( url, filters );
- this.entry = entry;
- }
-
- @Override
- protected void doProcessElements() throws IOException {
- JarFile jarFile;
- try {
- String filePart = jarUrl.getFile();
- if ( filePart != null && filePart.indexOf( ' ' ) != -1 ) {
- //unescaped (from the container), keep as is
- jarFile = new JarFile( jarUrl.getFile() );
- }
- else {
- jarFile = new JarFile( jarUrl.toURI().getSchemeSpecificPart() );
- }
- }
- catch (IOException ze) {
- LOG.unableToFindFile(jarUrl, ze);
- return;
- }
- catch (URISyntaxException e) {
- LOG.malformedUrlWarning(jarUrl, e);
- return;
- }
-
- if ( entry != null && entry.length() == 1 ) entry = null; //no entry
- if ( entry != null && entry.startsWith( "/" ) ) entry = entry.substring( 1 ); //remove '/' header
-
- Enumeration extends ZipEntry> entries = jarFile.entries();
- while ( entries.hasMoreElements() ) {
- ZipEntry zipEntry = entries.nextElement();
- String name = zipEntry.getName();
- if ( entry != null && ! name.startsWith( entry ) ) continue; //filter it out
- if ( !zipEntry.isDirectory() ) {
- if ( name.equals( entry ) ) {
- //exact match, might be a nested jar entry (ie from jar:file:..../foo.ear!/bar.jar)
- /*
- * This algorithm assumes that the zipped file is only the URL root (including entry), not just any random entry
- */
- InputStream is = null;
- try {
- is = new BufferedInputStream( jarFile.getInputStream( zipEntry ) );
- JarInputStream jis = new JarInputStream( is );
- ZipEntry subZipEntry = jis.getNextEntry();
- while (subZipEntry != null) {
- if ( ! subZipEntry.isDirectory() ) {
- //FIXME copy sucks
- byte[] entryBytes = JarVisitorFactory.getBytesFromInputStream( jis );
- String subname = subZipEntry.getName();
- if ( subname.startsWith( "/" ) ) subname = subname.substring( 1 );
- addElement(
- subname,
- new ByteArrayInputStream(entryBytes),
- new ByteArrayInputStream(entryBytes)
- );
- }
- subZipEntry = jis.getNextEntry();
- }
- }
- finally {
- if ( is != null) is.close();
- }
- }
- else {
- //build relative name
- if (entry != null) name = name.substring( entry.length() );
- if ( name.startsWith( "/" ) ) name = name.substring( 1 );
- addElement(
- name,
- new BufferedInputStream( jarFile.getInputStream( zipEntry ) ),
- new BufferedInputStream( jarFile.getInputStream( zipEntry ) )
- );
- }
- }
- }
- }
-}
diff --git a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/packaging/internal/InputStreamZippedJarVisitor.java b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/packaging/internal/InputStreamZippedJarVisitor.java
deleted file mode 100644
index 27163d29ae..0000000000
--- a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/packaging/internal/InputStreamZippedJarVisitor.java
+++ /dev/null
@@ -1,121 +0,0 @@
-/*
- * Copyright (c) 2009, Red Hat Middleware LLC 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 Middleware LLC.
- *
- * 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.jpa.packaging.internal;
-
-import java.io.ByteArrayInputStream;
-import java.io.IOException;
-import java.net.URL;
-import java.util.jar.JarEntry;
-import java.util.jar.JarInputStream;
-import java.util.zip.ZipEntry;
-
-import org.jboss.logging.Logger;
-
-import org.hibernate.jpa.internal.EntityManagerMessageLogger;
-
-
-/**
- * Work on a JAR that can only be accessed through a inputstream
- * This is less efficient than the {@link FileZippedJarVisitor}
- *
- * @author Emmanuel Bernard
- */
-public class InputStreamZippedJarVisitor extends AbstractJarVisitor {
-
- private static final EntityManagerMessageLogger LOG = Logger.getMessageLogger(EntityManagerMessageLogger.class,
- InputStreamZippedJarVisitor.class.getName());
-
- private String entry;
-
- public InputStreamZippedJarVisitor(URL url, Filter[] filters, String entry) {
- super( url, filters );
- this.entry = entry;
- }
-
- public InputStreamZippedJarVisitor(String fileName, Filter[] filters) {
- super( fileName, filters );
- }
-
- @Override
- protected void doProcessElements() throws IOException {
- JarInputStream jis;
- try {
- jis = new JarInputStream( jarUrl.openStream() );
- }
- catch (Exception ze) {
- //really should catch IOException but Eclipse is buggy and raise NPE...
- LOG.unableToFindFile(jarUrl, ze);
- return;
- }
- if ( entry != null && entry.length() == 1 ) entry = null; //no entry
- if ( entry != null && entry.startsWith( "/" ) ) entry = entry.substring( 1 ); //remove '/' header
-
- JarEntry jarEntry;
- while ( ( jarEntry = jis.getNextJarEntry() ) != null ) {
- String name = jarEntry.getName();
- if ( entry != null && ! name.startsWith( entry ) ) continue; //filter it out
- if ( !jarEntry.isDirectory() ) {
- if ( name.equals( entry ) ) {
- //exact match, might be a nested jar entry (ie from jar:file:..../foo.ear!/bar.jar)
- /*
- * This algorithm assumes that the zipped file is only the URL root (including entry), not just any random entry
- */
- JarInputStream subJis = null;
- try {
- subJis = new JarInputStream( jis );
- ZipEntry subZipEntry = jis.getNextEntry();
- while (subZipEntry != null) {
- if ( ! subZipEntry.isDirectory() ) {
- //FIXME copy sucks
- byte[] entryBytes = JarVisitorFactory.getBytesFromInputStream( jis );
- String subname = subZipEntry.getName();
- if ( subname.startsWith( "/" ) ) subname = subname.substring( 1 );
- addElement(
- subname,
- new ByteArrayInputStream(entryBytes),
- new ByteArrayInputStream(entryBytes)
- );
- }
- subZipEntry = jis.getNextJarEntry();
- }
- }
- finally {
- if (subJis != null) subJis.close();
- }
- }
- else {
- byte[] entryBytes = JarVisitorFactory.getBytesFromInputStream( jis );
- //build relative name
- if (entry != null) name = name.substring( entry.length() );
- if ( name.startsWith( "/" ) ) name = name.substring( 1 );
- //this is bad cause we actually read everything instead of walking it lazily
- addElement(
- name,
- new ByteArrayInputStream( entryBytes ),
- new ByteArrayInputStream( entryBytes )
- );
- }
- }
- }
- jis.close();
- }
-}
diff --git a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/packaging/internal/JarProtocolVisitor.java b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/packaging/internal/JarProtocolVisitor.java
deleted file mode 100644
index c1bd24a169..0000000000
--- a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/packaging/internal/JarProtocolVisitor.java
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * Copyright (c) 2009, Red Hat Middleware LLC 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 Middleware LLC.
- *
- * 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.jpa.packaging.internal;
-
-import java.io.IOException;
-import java.net.URL;
-import java.util.Set;
-
-import org.hibernate.annotations.common.AssertionFailure;
-
-/**
- * @author Emmanuel Bernard
- */
-public class JarProtocolVisitor implements JarVisitor {
- private JarVisitor delegate;
- private URL jarUrl;
- private Filter[] filters;
-
- public JarProtocolVisitor(URL url, Filter[] filters, String entry) {
- this.jarUrl = url;
- this.filters = filters;
- if (entry != null && entry.length() > 0) throw new IllegalArgumentException( "jar:jar: not supported: " + jarUrl );
- init();
- }
-
- private void init() {
- String file = jarUrl.getFile();
- String entry;
- int subEntryIndex = file.lastIndexOf( "!" );
- if (subEntryIndex == -1) throw new AssertionFailure("JAR URL does not contain '!/' :" + jarUrl);
- if ( subEntryIndex + 1 >= file.length() ) {
- entry = "";
- }
- else {
- entry = file.substring( subEntryIndex + 1 );
- }
- URL fileUrl = JarVisitorFactory.getJarURLFromURLEntry( jarUrl, entry );
- delegate = JarVisitorFactory.getVisitor( fileUrl, filters, entry );
-
- }
-
- public String getUnqualifiedJarName() {
- return delegate.getUnqualifiedJarName();
- }
-
- public Filter[] getFilters() {
- return delegate.getFilters();
- }
-
- public Set[] getMatchingEntries() throws IOException {
- return delegate.getMatchingEntries();
- }
-
-}
diff --git a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/packaging/internal/JavaElementFilter.java b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/packaging/internal/JavaElementFilter.java
deleted file mode 100644
index ab7e42fc42..0000000000
--- a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/packaging/internal/JavaElementFilter.java
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright (c) 2009, Red Hat Middleware LLC 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 Middleware LLC.
- *
- * 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.jpa.packaging.internal;
-
-
-/**
- * Filter a Java element (class or package per fully qualified name and annotation existence)
- * At least 1 annotation has to annotate the element and the accept method must match
- * If none annotations are passed, only the accept method must pass.
- *
- * @author Emmanuel Bernard
- */
-public abstract class JavaElementFilter extends Filter {
- private Class[] annotations;
-
- /**
- * @param retrieveStream Give back an open stream to the matching element or not
- * @param annotations Array of annotations that must be present to match (1 of them should annotate the element
- */
- protected JavaElementFilter(boolean retrieveStream, Class[] annotations) {
- super( retrieveStream );
- this.annotations = annotations == null ? new Class[]{} : annotations;
- }
-
- public Class[] getAnnotations() {
- return annotations;
- }
-
- /**
- * Return true if the fully qualified name match
- */
- public abstract boolean accept(String javaElementName);
-}
\ No newline at end of file
diff --git a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/packaging/internal/NativeScanner.java b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/packaging/internal/NativeScanner.java
deleted file mode 100644
index 6a568a981d..0000000000
--- a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/packaging/internal/NativeScanner.java
+++ /dev/null
@@ -1,248 +0,0 @@
-/*
- * Copyright (c) 2009, Red Hat Middleware LLC 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 Middleware LLC.
- *
- * 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.jpa.packaging.internal;
-
-import java.io.IOException;
-import java.lang.annotation.Annotation;
-import java.net.URL;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
-import javax.persistence.Converter;
-import javax.persistence.Embeddable;
-import javax.persistence.Entity;
-import javax.persistence.MappedSuperclass;
-
-import org.hibernate.AssertionFailure;
-import org.hibernate.internal.util.ReflectHelper;
-import org.hibernate.jpa.packaging.spi.NamedInputStream;
-import org.hibernate.jpa.packaging.spi.Scanner;
-
-/**
- * @author Emmanuel Bernard
- */
-public class NativeScanner implements Scanner {
-
- private static final String META_INF_ORM_XML = "META-INF/orm.xml";
-
- private Map visitors = new HashMap();
- private static final int PACKAGE_FILTER_INDEX = 0;
- private static final int CLASS_FILTER_INDEX = 1;
- private static final int FILE_FILTER_INDEX = 2;
-
- /**
- * This implementation does not honor the list of annotations and return everything.
- * Must strictly be used by HEM
- */
- public Set getPackagesInJar(URL jarToScan, Set> annotationsToLookFor) {
- if ( annotationsToLookFor.size() > 0 ) {
- throw new AssertionFailure( "Improper use of NativeScanner: must not filter packages" );
- }
-
- JarVisitor jarVisitor = getVisitor( jarToScan );
- final Set packageEntries;
- try {
- packageEntries = ( Set ) jarVisitor.getMatchingEntries()[PACKAGE_FILTER_INDEX];
- }
- catch ( IOException e ) {
- throw new RuntimeException( "Error while reading " + jarToScan.toString(), e );
- }
- Set packages = new HashSet( packageEntries.size() );
- for ( Entry entry : packageEntries ) {
- try {
- packages.add( ReflectHelper.classForName( entry.getName() + ".package-info" ).getPackage() );
- }
- catch ( ClassNotFoundException e ) {
- //should never happen, if it happens, simply ignore the flawed package
- }
- }
- return packages;
- }
-
- /**
- * Build a JarVisitor with some assumptions wrt the scanning
- * This helps do one scan instead of several
- */
- private JarVisitor getVisitor(URL jar) {
- StateJarVisitor stateJarVisitor = visitors.get( jar );
-
- if ( stateJarVisitor == null ) {
-
- Filter[] filters = new Filter[3];
- filters[PACKAGE_FILTER_INDEX] = new PackageFilter( false, null ) {
- public boolean accept(String javaElementName) {
- return true;
- }
- };
- filters[CLASS_FILTER_INDEX] = new ClassFilter(
- false, new Class[] {
- Entity.class,
- MappedSuperclass.class,
- Embeddable.class
- }
- ) {
- public boolean accept(String javaElementName) {
- return true;
- }
- };
- filters[FILE_FILTER_INDEX] = new FileFilter( true ) {
- public boolean accept(String javaElementName) {
- return javaElementName.endsWith( "hbm.xml" )
- || javaElementName.endsWith( META_INF_ORM_XML );
- }
- };
-
- stateJarVisitor = new StateJarVisitor( JarVisitorFactory.getVisitor( jar, filters ) );
- visitors.put( jar, stateJarVisitor );
- }
- return stateJarVisitor.visitor;
- }
-
- public Set> getClassesInJar(URL jarToScan, Set> annotationsToLookFor) {
- if ( isValidForClasses( annotationsToLookFor ) ) {
- throw new AssertionFailure(
- "Improper use of NativeScanner: "
- + "must not filter classes by other annotations than Entity, MappedSuperclass, embeddable"
- );
- }
- JarVisitor jarVisitor = getVisitor( jarToScan );
- final Set classesEntry;
- try {
- classesEntry = ( Set ) jarVisitor.getMatchingEntries()[CLASS_FILTER_INDEX];
- }
- catch ( IOException e ) {
- throw new RuntimeException( "Error while reading " + jarToScan.toString(), e );
- }
- Set> classes = new HashSet>( classesEntry.size() );
- for ( Entry entry : classesEntry ) {
- try {
- classes.add( ReflectHelper.classForName( entry.getName() ) );
- }
- catch ( ClassNotFoundException e ) {
- //should never happen, if it happens, simply ignore the flawed package
- }
- }
- return classes;
- }
-
- private boolean isValidForClasses(Set> annotationsToLookFor) {
- return annotationsToLookFor.size() != 4
- || !annotationsToLookFor.contains( Entity.class )
- || !annotationsToLookFor.contains( MappedSuperclass.class )
- || !annotationsToLookFor.contains( Embeddable.class )
- || !annotationsToLookFor.contains( Converter.class );
- }
-
- /**
- * support for patterns is primitive:
- * - **\/*.hbm.xml
- * Other patterns will not be found
- */
- public Set getFilesInJar(URL jarToScan, Set filePatterns) {
- StringBuilder sb = new StringBuilder("URL: ").append( jarToScan )
- .append( "\n" );
- for (String pattern : filePatterns) {
- sb.append( " " ).append( pattern ).append( "\n" );
- }
- JarVisitor jarVisitor = getVisitor( jarToScan );
-
- //state visitor available
- final StateJarVisitor stateVisitor = visitors.get( jarToScan );
- if ( stateVisitor.hasReadFiles ) {
- throw new AssertionFailure( "Cannot read files twice on NativeScanner" );
- }
- stateVisitor.hasReadFiles = true;
-
- Set endWiths = new HashSet();
- Set exacts = new HashSet();
- for ( String pattern : filePatterns ) {
- if ( pattern.startsWith( "**/*" ) ) {
- final String patternTail = pattern.substring( 4, pattern.length() );
- if ( !patternTail.equals( ".hbm.xml" ) ) {
- throw new AssertionFailure(
- "Improper use of NativeScanner: "
- + "must not filter files via pattern other than .hbm.xml"
- );
- }
- endWiths.add( patternTail );
- }
- else {
- exacts.add( pattern );
- }
- }
-
- final Set fileEntries;
- try {
- fileEntries = ( Set ) jarVisitor.getMatchingEntries()[FILE_FILTER_INDEX];
- }
- catch ( IOException e ) {
- throw new RuntimeException( "Error while reading " + jarToScan.toString(), e );
- }
- Set files = new HashSet( fileEntries.size() );
- Set leftOver = new HashSet( fileEntries );
- for ( Entry entry : fileEntries ) {
- boolean done = false;
- for ( String exact : exacts ) {
- if ( entry.getName().equals( exact ) ) {
- files.add( new NamedInputStream( entry.getName(), entry.getInputStream() ) );
- leftOver.remove( entry );
- done = true;
- }
- }
- if (done) continue;
- for ( String endWithPattern : endWiths ) {
- if ( entry.getName().endsWith( endWithPattern ) ) {
- files.add( new NamedInputStream( entry.getName(), entry.getInputStream() ) );
- leftOver.remove( entry );
- }
- }
-
- }
- for ( Entry entry : leftOver ) {
- try {
- entry.getInputStream().close();
- }
- catch ( IOException e ) {
- //swallow as we don't care about these files
- }
- }
- return files;
- }
-
- public Set getFilesInClasspath(Set filePatterns) {
- throw new AssertionFailure( "Not implemented" );
- }
-
- public String getUnqualifiedJarName(URL jarToScan) {
- JarVisitor jarVisitor = getVisitor( jarToScan );
- return jarVisitor.getUnqualifiedJarName();
- }
-
- private static class StateJarVisitor {
- StateJarVisitor(JarVisitor visitor) {
- this.visitor = visitor;
- }
- JarVisitor visitor;
- boolean hasReadFiles = false;
- }
-}
diff --git a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/packaging/spi/Scanner.java b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/packaging/spi/Scanner.java
deleted file mode 100644
index 241d233d61..0000000000
--- a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/packaging/spi/Scanner.java
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Hibernate, Relational Persistence for Idiomatic Java
- *
- * Copyright (c) 2012, 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.jpa.packaging.spi;
-import java.lang.annotation.Annotation;
-import java.net.URL;
-import java.util.Set;
-
-/**
- * @author Emmanuel Bernard
- */
-public interface Scanner {
- /**
- * return all packages in the jar matching one of these annotations
- * if annotationsToLookFor is empty, return all packages
- */
- Set getPackagesInJar(URL jartoScan, Set> annotationsToLookFor);
-
- /**
- * return all classes in the jar matching one of these annotations
- * if annotationsToLookFor is empty, return all classes
- */
- Set> getClassesInJar(URL jartoScan, Set> annotationsToLookFor);
-
- /**
- * return all files in the jar matching one of these file names
- * if filePatterns is empty, return all files
- * eg **\/*.hbm.xml, META-INF/orm.xml
- */
- Set getFilesInJar(URL jartoScan, Set filePatterns);
-
-
- /**
- * Return all files in the classpath (ie PU visibility) matching one of these file names
- * if filePatterns is empty, return all files
- * the use case is really exact file name.
- *
- * NOT USED by HEM at the moment. We use exact file search via getResourceAsStream for now.
- */
- Set getFilesInClasspath(Set filePatterns);
-
- /**
- * return the unqualified JAR name ie customer-model.jar or store.war
- */
- String getUnqualifiedJarName(URL jarUrl);
-
-}
diff --git a/hibernate-entitymanager/src/test/java/org/hibernate/jpa/test/TestHelper.java b/hibernate-entitymanager/src/test/java/org/hibernate/jpa/test/TestHelper.java
new file mode 100644
index 0000000000..90ef4d9ce8
--- /dev/null
+++ b/hibernate-entitymanager/src/test/java/org/hibernate/jpa/test/TestHelper.java
@@ -0,0 +1,67 @@
+package org.hibernate.jpa.test;
+
+/*
+ * 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
+ */
+
+import java.io.File;
+import java.net.MalformedURLException;
+import java.net.URL;
+
+import static java.io.File.separatorChar;
+
+/**
+ * @author Steve Ebersole
+ */
+public class TestHelper {
+ private static URL RESOLVED_TEST_ROOT_URL;
+
+ public static URL determineTestRootUrl() {
+ if ( RESOLVED_TEST_ROOT_URL == null ) {
+ RESOLVED_TEST_ROOT_URL = resolveRootUrl( TestHelper.class );
+ }
+ return RESOLVED_TEST_ROOT_URL;
+ }
+
+ public static URL resolveRootUrl(Class knownClass) {
+ final String knownClassFileName = '/' + knownClass.getName().replace( '.', separatorChar ) + ".class";
+ final URL knownClassFileUrl = TestHelper.class.getResource( knownClassFileName );
+ final String knownClassFileUrlString = knownClassFileUrl.toExternalForm();
+
+ // to start, strip off the class file name
+ String rootUrlString = knownClassFileUrlString.substring( 0, knownClassFileUrlString.lastIndexOf( separatorChar ) );
+
+ // then strip off each package dir
+ final String packageName = knownClass.getPackage().getName();
+ for ( String packageNamePart : packageName.split( "\\." ) ) {
+ rootUrlString = rootUrlString.substring( 0, rootUrlString.lastIndexOf( separatorChar ) );
+ }
+
+ try {
+ return new URL( rootUrlString );
+ }
+ catch (MalformedURLException e) {
+ throw new RuntimeException( "Could not convert class base url as string to URL ref", e );
+ }
+ }
+}
diff --git a/hibernate-entitymanager/src/test/java/org/hibernate/jpa/test/packaging/CustomScanner.java b/hibernate-entitymanager/src/test/java/org/hibernate/jpa/test/packaging/CustomScanner.java
index c1ec0fdf84..71a6d5e72b 100644
--- a/hibernate-entitymanager/src/test/java/org/hibernate/jpa/test/packaging/CustomScanner.java
+++ b/hibernate-entitymanager/src/test/java/org/hibernate/jpa/test/packaging/CustomScanner.java
@@ -1,19 +1,17 @@
package org.hibernate.jpa.test.packaging;
-import java.lang.annotation.Annotation;
-import java.net.URL;
-import java.util.Set;
-
-import org.hibernate.jpa.packaging.internal.NativeScanner;
-import org.hibernate.jpa.packaging.spi.NamedInputStream;
-import org.hibernate.jpa.packaging.spi.Scanner;
+import org.hibernate.jpa.boot.spi.PersistenceUnitDescriptor;
+import org.hibernate.jpa.boot.scan.internal.StandardScanner;
+import org.hibernate.jpa.boot.scan.spi.ScanOptions;
+import org.hibernate.jpa.boot.scan.spi.ScanResult;
+import org.hibernate.jpa.boot.scan.spi.Scanner;
/**
* @author Emmanuel Bernard
*/
public class CustomScanner implements Scanner {
public static boolean isUsed = false;
- private Scanner scanner = new NativeScanner();
+ private Scanner delegate = new StandardScanner();
public static boolean isUsed() {
return isUsed;
@@ -23,28 +21,9 @@ public class CustomScanner implements Scanner {
isUsed = false;
}
- public Set getPackagesInJar(URL jartoScan, Set> annotationsToLookFor) {
+ @Override
+ public ScanResult scan(PersistenceUnitDescriptor persistenceUnit, ScanOptions options) {
isUsed = true;
- return scanner.getPackagesInJar( jartoScan, annotationsToLookFor );
- }
-
- public Set> getClassesInJar(URL jartoScan, Set> annotationsToLookFor) {
- isUsed = true;
- return scanner.getClassesInJar( jartoScan, annotationsToLookFor );
- }
-
- public Set getFilesInJar(URL jartoScan, Set filePatterns) {
- isUsed = true;
- return scanner.getFilesInJar( jartoScan, filePatterns );
- }
-
- public Set getFilesInClasspath(Set filePatterns) {
- isUsed = true;
- return scanner.getFilesInClasspath( filePatterns );
- }
-
- public String getUnqualifiedJarName(URL jarUrl) {
- isUsed = true;
- return scanner.getUnqualifiedJarName( jarUrl );
+ return delegate.scan( persistenceUnit, options );
}
}
diff --git a/hibernate-entitymanager/src/test/java/org/hibernate/jpa/test/packaging/JarVisitorTest.java b/hibernate-entitymanager/src/test/java/org/hibernate/jpa/test/packaging/JarVisitorTest.java
index b1fb148cb1..e4ed5d1ef4 100644
--- a/hibernate-entitymanager/src/test/java/org/hibernate/jpa/test/packaging/JarVisitorTest.java
+++ b/hibernate-entitymanager/src/test/java/org/hibernate/jpa/test/packaging/JarVisitorTest.java
@@ -23,12 +23,6 @@
*/
package org.hibernate.jpa.test.packaging;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
@@ -38,29 +32,32 @@ import java.net.URL;
import java.net.URLConnection;
import java.net.URLStreamHandler;
import java.net.URLStreamHandlerFactory;
-import java.util.Set;
-
-import javax.persistence.Embeddable;
-import javax.persistence.Entity;
-import javax.persistence.MappedSuperclass;
import org.hibernate.dialect.H2Dialect;
-import org.hibernate.jpa.packaging.internal.ClassFilter;
-import org.hibernate.jpa.packaging.internal.Entry;
-import org.hibernate.jpa.packaging.internal.ExplodedJarVisitor;
-import org.hibernate.jpa.packaging.internal.FileFilter;
-import org.hibernate.jpa.packaging.internal.FileZippedJarVisitor;
-import org.hibernate.jpa.packaging.internal.Filter;
-import org.hibernate.jpa.packaging.internal.InputStreamZippedJarVisitor;
-import org.hibernate.jpa.packaging.internal.JarProtocolVisitor;
-import org.hibernate.jpa.packaging.internal.JarVisitor;
-import org.hibernate.jpa.packaging.internal.JarVisitorFactory;
-import org.hibernate.jpa.packaging.internal.PackageFilter;
+import org.hibernate.jpa.boot.archive.internal.ArchiveHelper;
+import org.hibernate.jpa.boot.archive.internal.ExplodedArchiveDescriptor;
+import org.hibernate.jpa.boot.archive.internal.JarFileBasedArchiveDescriptor;
+import org.hibernate.jpa.boot.archive.internal.JarInputStreamBasedArchiveDescriptor;
+import org.hibernate.jpa.boot.archive.internal.JarProtocolArchiveDescriptor;
+import org.hibernate.jpa.boot.archive.internal.StandardArchiveDescriptorFactory;
+import org.hibernate.jpa.boot.archive.spi.ArchiveDescriptor;
+import org.hibernate.jpa.boot.internal.ClassDescriptorImpl;
+import org.hibernate.jpa.boot.scan.internal.StandardScanOptions;
+import org.hibernate.jpa.boot.scan.spi.AbstractScannerImpl;
+import org.hibernate.jpa.boot.spi.MappingFileDescriptor;
+import org.hibernate.jpa.test.PersistenceUnitDescriptorAdapter;
import org.hibernate.jpa.test.pack.defaultpar.Version;
import org.hibernate.jpa.test.pack.explodedpar.Carpet;
+
+import org.junit.Test;
+
import org.hibernate.testing.RequiresDialect;
import org.hibernate.testing.TestForIssue;
-import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
/**
* @author Emmanuel Bernard
@@ -72,7 +69,7 @@ import org.junit.Test;
public class JarVisitorTest extends PackagingTestCase {
@Test
public void testHttp() throws Exception {
- URL url = JarVisitorFactory.getJarURLFromURLEntry(
+ URL url = ArchiveHelper.getJarURLFromURLEntry(
new URL(
"jar:http://www.ibiblio.org/maven/hibernate/jars/hibernate-annotations-3.0beta1.jar!/META-INF/persistence.xml"
),
@@ -86,10 +83,18 @@ public class JarVisitorTest extends PackagingTestCase {
//fail silently
return;
}
- JarVisitor visitor = JarVisitorFactory.getVisitor( url, getFilters() );
- assertEquals( 0, visitor.getMatchingEntries()[0].size() );
- assertEquals( 0, visitor.getMatchingEntries()[1].size() );
- assertEquals( 0, visitor.getMatchingEntries()[2].size() );
+ ArchiveDescriptor archiveDescriptor = StandardArchiveDescriptorFactory.INSTANCE.buildArchiveDescriptor( url );
+ AbstractScannerImpl.ResultCollector resultCollector = new AbstractScannerImpl.ResultCollector( new StandardScanOptions() );
+ archiveDescriptor.visitArchive(
+ new AbstractScannerImpl.ArchiveContextImpl(
+ new PersistenceUnitDescriptorAdapter(),
+ true,
+ resultCollector
+ )
+ );
+ assertEquals( 0, resultCollector.getClassDescriptorSet().size() );
+ assertEquals( 0, resultCollector.getPackageDescriptorSet().size() );
+ assertEquals( 0, resultCollector.getMappingFileSet().size() );
}
@Test
@@ -97,20 +102,40 @@ public class JarVisitorTest extends PackagingTestCase {
File defaultPar = buildDefaultPar();
addPackageToClasspath( defaultPar );
- Filter[] filters = getFilters();
- JarVisitor jarVisitor = new InputStreamZippedJarVisitor( defaultPar.toURL(), filters, "" );
- assertEquals( "defaultpar", jarVisitor.getUnqualifiedJarName() );
- Set entries = jarVisitor.getMatchingEntries()[1];
- assertEquals( 3, entries.size() );
- Entry entry = new Entry( org.hibernate.jpa.test.pack.defaultpar.ApplicationServer.class.getName(), null );
- assertTrue( entries.contains( entry ) );
- entry = new Entry( Version.class.getName(), null );
- assertTrue( entries.contains( entry ) );
- assertNull( ( ( Entry ) entries.iterator().next() ).getInputStream() );
- assertEquals( 2, jarVisitor.getMatchingEntries()[2].size() );
- for ( Entry localEntry : ( Set ) jarVisitor.getMatchingEntries()[2] ) {
- assertNotNull( localEntry.getInputStream() );
- localEntry.getInputStream().close();
+ ArchiveDescriptor archiveDescriptor = new JarInputStreamBasedArchiveDescriptor(
+ StandardArchiveDescriptorFactory.INSTANCE,
+ defaultPar.toURL(),
+ ""
+ );
+
+ AbstractScannerImpl.ResultCollector resultCollector = new AbstractScannerImpl.ResultCollector( new StandardScanOptions() );
+ archiveDescriptor.visitArchive(
+ new AbstractScannerImpl.ArchiveContextImpl(
+ new PersistenceUnitDescriptorAdapter(),
+ true,
+ resultCollector
+ )
+ );
+
+ validateResults( resultCollector, org.hibernate.jpa.test.pack.defaultpar.ApplicationServer.class, Version.class );
+ }
+
+ private void validateResults(AbstractScannerImpl.ResultCollector resultCollector, Class... expectedClasses) throws IOException {
+ assertEquals( 3, resultCollector.getClassDescriptorSet().size() );
+ for ( Class expectedClass : expectedClasses ) {
+ assertTrue(
+ resultCollector.getClassDescriptorSet().contains(
+ new ClassDescriptorImpl( expectedClass.getName(), null )
+ )
+ );
+ }
+
+ assertEquals( 2, resultCollector.getMappingFileSet().size() );
+ for ( MappingFileDescriptor mappingFileDescriptor : resultCollector.getMappingFileSet() ) {
+ assertNotNull( mappingFileDescriptor.getStreamAccess() );
+ final InputStream stream = mappingFileDescriptor.getStreamAccess().accessInputStream();
+ assertNotNull( stream );
+ stream.close();
}
}
@@ -122,41 +147,39 @@ public class JarVisitorTest extends PackagingTestCase {
addPackageToClasspath( nestedEar );
String jarFileName = nestedEar.toURL().toExternalForm() + "!/defaultpar.par";
- Filter[] filters = getFilters();
- JarVisitor jarVisitor = new JarProtocolVisitor( new URL( jarFileName ), filters, "" );
- //TODO should we fix the name here to reach defaultpar rather than nestedjar ??
- //assertEquals( "defaultpar", jarVisitor.getUnqualifiedJarName() );
- Set entries = jarVisitor.getMatchingEntries()[1];
- assertEquals( 3, entries.size() );
- Entry entry = new Entry( org.hibernate.jpa.test.pack.defaultpar.ApplicationServer.class.getName(), null );
- assertTrue( entries.contains( entry ) );
- entry = new Entry( Version.class.getName(), null );
- assertTrue( entries.contains( entry ) );
- assertNull( ( ( Entry ) entries.iterator().next() ).getInputStream() );
- assertEquals( 2, jarVisitor.getMatchingEntries()[2].size() );
- for ( Entry localEntry : ( Set ) jarVisitor.getMatchingEntries()[2] ) {
- assertNotNull( localEntry.getInputStream() );
- localEntry.getInputStream().close();
- }
+
+ JarProtocolArchiveDescriptor archiveDescriptor = new JarProtocolArchiveDescriptor(
+ StandardArchiveDescriptorFactory.INSTANCE,
+ new URL( jarFileName ),
+ ""
+ );
+ AbstractScannerImpl.ResultCollector resultCollector = new AbstractScannerImpl.ResultCollector( new StandardScanOptions() );
+ archiveDescriptor.visitArchive(
+ new AbstractScannerImpl.ArchiveContextImpl(
+ new PersistenceUnitDescriptorAdapter(),
+ true,
+ resultCollector
+ )
+ );
+
+ validateResults( resultCollector, org.hibernate.jpa.test.pack.defaultpar.ApplicationServer.class, Version.class );
jarFileName = nestedEarDir.toURL().toExternalForm() + "!/defaultpar.par";
- //JarVisitor jarVisitor = new ZippedJarVisitor( jarFileName, true, true );
- filters = getFilters();
- jarVisitor = new JarProtocolVisitor( new URL( jarFileName ), filters, "" );
- //TODO should we fix the name here to reach defaultpar rather than nestedjar ??
- //assertEquals( "defaultpar", jarVisitor.getUnqualifiedJarName() );
- entries = jarVisitor.getMatchingEntries()[1];
- assertEquals( 3, entries.size() );
- entry = new Entry( org.hibernate.jpa.test.pack.defaultpar.ApplicationServer.class.getName(), null );
- assertTrue( entries.contains( entry ) );
- entry = new Entry( Version.class.getName(), null );
- assertTrue( entries.contains( entry ) );
- assertNull( ( ( Entry ) entries.iterator().next() ).getInputStream() );
- assertEquals( 2, jarVisitor.getMatchingEntries()[2].size() );
- for ( Entry localEntry : ( Set ) jarVisitor.getMatchingEntries()[2] ) {
- assertNotNull( localEntry.getInputStream() );
- localEntry.getInputStream().close();
- }
+ archiveDescriptor = new JarProtocolArchiveDescriptor(
+ StandardArchiveDescriptorFactory.INSTANCE,
+ new URL( jarFileName ),
+ ""
+ );
+ resultCollector = new AbstractScannerImpl.ResultCollector( new StandardScanOptions() );
+ archiveDescriptor.visitArchive(
+ new AbstractScannerImpl.ArchiveContextImpl(
+ new PersistenceUnitDescriptorAdapter(),
+ true,
+ resultCollector
+ )
+ );
+
+ validateResults( resultCollector, org.hibernate.jpa.test.pack.defaultpar.ApplicationServer.class, Version.class );
}
@Test
@@ -165,21 +188,26 @@ public class JarVisitorTest extends PackagingTestCase {
addPackageToClasspath( war );
String jarFileName = war.toURL().toExternalForm() + "!/WEB-INF/classes";
- Filter[] filters = getFilters();
- JarVisitor jarVisitor = new JarProtocolVisitor( new URL( jarFileName ), filters, "" );
- assertEquals( "war", jarVisitor.getUnqualifiedJarName() );
- Set entries = jarVisitor.getMatchingEntries()[1];
- assertEquals( 3, entries.size() );
- Entry entry = new Entry( org.hibernate.jpa.test.pack.war.ApplicationServer.class.getName(), null );
- assertTrue( entries.contains( entry ) );
- entry = new Entry( org.hibernate.jpa.test.pack.war.Version.class.getName(), null );
- assertTrue( entries.contains( entry ) );
- assertNull( ( ( Entry ) entries.iterator().next() ).getInputStream() );
- assertEquals( 2, jarVisitor.getMatchingEntries()[2].size() );
- for ( Entry localEntry : ( Set ) jarVisitor.getMatchingEntries()[2] ) {
- assertNotNull( localEntry.getInputStream() );
- localEntry.getInputStream().close();
- }
+ JarProtocolArchiveDescriptor archiveDescriptor = new JarProtocolArchiveDescriptor(
+ StandardArchiveDescriptorFactory.INSTANCE,
+ new URL( jarFileName ),
+ ""
+ );
+
+ AbstractScannerImpl.ResultCollector resultCollector = new AbstractScannerImpl.ResultCollector( new StandardScanOptions() );
+ archiveDescriptor.visitArchive(
+ new AbstractScannerImpl.ArchiveContextImpl(
+ new PersistenceUnitDescriptorAdapter(),
+ true,
+ resultCollector
+ )
+ );
+
+ validateResults(
+ resultCollector,
+ org.hibernate.jpa.test.pack.war.ApplicationServer.class,
+ org.hibernate.jpa.test.pack.war.Version.class
+ );
}
@Test
@@ -187,21 +215,21 @@ public class JarVisitorTest extends PackagingTestCase {
File defaultPar = buildDefaultPar();
addPackageToClasspath( defaultPar );
- Filter[] filters = getFilters();
- JarVisitor jarVisitor = new FileZippedJarVisitor( defaultPar.toURL(), filters, "" );
- assertEquals( "defaultpar", jarVisitor.getUnqualifiedJarName() );
- Set entries = jarVisitor.getMatchingEntries()[1];
- assertEquals( 3, entries.size() );
- Entry entry = new Entry( org.hibernate.jpa.test.pack.defaultpar.ApplicationServer.class.getName(), null );
- assertTrue( entries.contains( entry ) );
- entry = new Entry( Version.class.getName(), null );
- assertTrue( entries.contains( entry ) );
- assertNull( ( ( Entry ) entries.iterator().next() ).getInputStream() );
- assertEquals( 2, jarVisitor.getMatchingEntries()[2].size() );
- for ( Entry localEntry : ( Set ) jarVisitor.getMatchingEntries()[2] ) {
- assertNotNull( localEntry.getInputStream() );
- localEntry.getInputStream().close();
- }
+ JarFileBasedArchiveDescriptor archiveDescriptor = new JarFileBasedArchiveDescriptor(
+ StandardArchiveDescriptorFactory.INSTANCE,
+ defaultPar.toURL(),
+ ""
+ );
+ AbstractScannerImpl.ResultCollector resultCollector = new AbstractScannerImpl.ResultCollector( new StandardScanOptions() );
+ archiveDescriptor.visitArchive(
+ new AbstractScannerImpl.ArchiveContextImpl(
+ new PersistenceUnitDescriptorAdapter(),
+ true,
+ resultCollector
+ )
+ );
+
+ validateResults( resultCollector, org.hibernate.jpa.test.pack.defaultpar.ApplicationServer.class, Version.class );
}
@Test
@@ -209,32 +237,50 @@ public class JarVisitorTest extends PackagingTestCase {
File explodedPar = buildExplodedPar();
addPackageToClasspath( explodedPar );
- Filter[] filters = getFilters();
String dirPath = explodedPar.toURL().toExternalForm();
// TODO - shouldn't ExplodedJarVisitor take care of a trailing slash?
if ( dirPath.endsWith( "/" ) ) {
dirPath = dirPath.substring( 0, dirPath.length() - 1 );
}
- JarVisitor jarVisitor = new ExplodedJarVisitor( dirPath, filters );
- assertEquals( "explodedpar", jarVisitor.getUnqualifiedJarName() );
- Set[] entries = jarVisitor.getMatchingEntries();
- assertEquals( 1, entries[1].size() );
- assertEquals( 1, entries[0].size() );
- assertEquals( 1, entries[2].size() );
- Entry entry = new Entry( Carpet.class.getName(), null );
- assertTrue( entries[1].contains( entry ) );
- for ( Entry localEntry : ( Set ) jarVisitor.getMatchingEntries()[2] ) {
- assertNotNull( localEntry.getInputStream() );
- localEntry.getInputStream().close();
+ ExplodedArchiveDescriptor archiveDescriptor = new ExplodedArchiveDescriptor(
+ StandardArchiveDescriptorFactory.INSTANCE,
+ ArchiveHelper.getURLFromPath( dirPath ),
+ ""
+ );
+ AbstractScannerImpl.ResultCollector resultCollector = new AbstractScannerImpl.ResultCollector( new StandardScanOptions() );
+ archiveDescriptor.visitArchive(
+ new AbstractScannerImpl.ArchiveContextImpl(
+ new PersistenceUnitDescriptorAdapter(),
+ true,
+ resultCollector
+ )
+ );
+
+ assertEquals( 1, resultCollector.getClassDescriptorSet().size() );
+ assertEquals( 1, resultCollector.getPackageDescriptorSet().size() );
+ assertEquals( 1, resultCollector.getMappingFileSet().size() );
+
+ assertTrue(
+ resultCollector.getClassDescriptorSet().contains(
+ new ClassDescriptorImpl( Carpet.class.getName(), null )
+ )
+ );
+
+ for ( MappingFileDescriptor mappingFileDescriptor : resultCollector.getMappingFileSet() ) {
+ assertNotNull( mappingFileDescriptor.getStreamAccess() );
+ final InputStream stream = mappingFileDescriptor.getStreamAccess().accessInputStream();
+ assertNotNull( stream );
+ stream.close();
}
}
@Test
@TestForIssue(jiraKey = "HHH-6806")
- public void testJarVisitorFactory() throws Exception{
-
- addPackageToClasspath( buildExplodedPar(), buildDefaultPar() );
+ public void testJarVisitorFactory() throws Exception {
+ final File explodedPar = buildExplodedPar();
+ final File defaultPar = buildDefaultPar();
+ addPackageToClasspath( explodedPar, defaultPar );
//setting URL to accept vfs based protocol
URL.setURLStreamHandlerFactory(new URLStreamHandlerFactory() {
@@ -250,21 +296,21 @@ public class JarVisitorTest extends PackagingTestCase {
}
});
- URL jarUrl = new URL ("file:./target/packages/defaultpar.par");
- JarVisitor jarVisitor = JarVisitorFactory.getVisitor(jarUrl, getFilters(), null);
- assertEquals(FileZippedJarVisitor.class.getName(), jarVisitor.getClass().getName());
-
- jarUrl = new URL ("file:./target/packages/explodedpar");
- jarVisitor = JarVisitorFactory.getVisitor(jarUrl, getFilters(), null);
- assertEquals(ExplodedJarVisitor.class.getName(), jarVisitor.getClass().getName());
-
- jarUrl = new URL ("vfszip:./target/packages/defaultpar.par");
- jarVisitor = JarVisitorFactory.getVisitor(jarUrl, getFilters(), null);
- assertEquals(FileZippedJarVisitor.class.getName(), jarVisitor.getClass().getName());
-
- jarUrl = new URL ("vfsfile:./target/packages/explodedpar");
- jarVisitor = JarVisitorFactory.getVisitor(jarUrl, getFilters(), null);
- assertEquals(ExplodedJarVisitor.class.getName(), jarVisitor.getClass().getName());
+ URL jarUrl = defaultPar.toURL();
+ ArchiveDescriptor descriptor = StandardArchiveDescriptorFactory.INSTANCE.buildArchiveDescriptor( jarUrl );
+ assertEquals( JarFileBasedArchiveDescriptor.class.getName(), descriptor.getClass().getName() );
+
+ jarUrl = explodedPar.toURL();
+ descriptor = StandardArchiveDescriptorFactory.INSTANCE.buildArchiveDescriptor( jarUrl );
+ assertEquals( ExplodedArchiveDescriptor.class.getName(), descriptor.getClass().getName() );
+
+ jarUrl = new URL( defaultPar.toURL().toExternalForm().replace( "file:", "vfszip:" ) );
+ descriptor = StandardArchiveDescriptorFactory.INSTANCE.buildArchiveDescriptor( jarUrl );
+ assertEquals( JarFileBasedArchiveDescriptor.class.getName(), descriptor.getClass().getName());
+
+ jarUrl = new URL( explodedPar.toURL().toExternalForm().replace( "file:", "vfsfile:" ) );
+ descriptor = StandardArchiveDescriptorFactory.INSTANCE.buildArchiveDescriptor( jarUrl );
+ assertEquals( ExplodedArchiveDescriptor.class.getName(), descriptor.getClass().getName() );
}
@Test
@@ -315,36 +361,29 @@ public class JarVisitorTest extends PackagingTestCase {
@Test
@TestForIssue(jiraKey = "HHH-7835")
- public void testGetBytesFromInputStream() {
- try {
- File file = buildLargeJar();
+ public void testGetBytesFromInputStream() throws Exception {
+ File file = buildLargeJar();
- long start = System.currentTimeMillis();
- InputStream stream = new BufferedInputStream(
- new FileInputStream( file ) );
- int oldLength = getBytesFromInputStream( stream ).length;
- stream.close();
- long oldTime = System.currentTimeMillis() - start;
+ long start = System.currentTimeMillis();
+ InputStream stream = new BufferedInputStream(
+ new FileInputStream( file ) );
+ int oldLength = getBytesFromInputStream( stream ).length;
+ stream.close();
+ long oldTime = System.currentTimeMillis() - start;
- start = System.currentTimeMillis();
- stream = new BufferedInputStream( new FileInputStream( file ) );
- int newLength = JarVisitorFactory.getBytesFromInputStream(
- stream ).length;
- stream.close();
- long newTime = System.currentTimeMillis() - start;
+ start = System.currentTimeMillis();
+ stream = new BufferedInputStream( new FileInputStream( file ) );
+ int newLength = ArchiveHelper.getBytesFromInputStream( stream ).length;
+ stream.close();
+ long newTime = System.currentTimeMillis() - start;
- assertEquals( oldLength, newLength );
- assertTrue( oldTime > newTime );
- }
- catch ( Exception e ) {
- fail( e.getMessage() );
- }
+ assertEquals( oldLength, newLength );
+ assertTrue( oldTime > newTime );
}
// This is the old getBytesFromInputStream from JarVisitorFactory before
// it was changed by HHH-7835. Use it as a regression test.
- private byte[] getBytesFromInputStream(
- InputStream inputStream) throws IOException {
+ private byte[] getBytesFromInputStream(InputStream inputStream) throws IOException {
int size;
byte[] entryBytes = new byte[0];
@@ -363,46 +402,16 @@ public class JarVisitorTest extends PackagingTestCase {
@Test
@TestForIssue(jiraKey = "HHH-7835")
- public void testGetBytesFromZeroInputStream() {
- try {
- // Ensure that JarVisitorFactory#getBytesFromInputStream
- // can handle 0 length streams gracefully.
- InputStream emptyStream = new BufferedInputStream(
- new FileInputStream( new File(
- "src/test/resources/org/hibernate/jpa/test/packaging/empty.txt" ) ) );
- int length = JarVisitorFactory.getBytesFromInputStream(
- emptyStream ).length;
- assertEquals( length, 0 );
- emptyStream.close();
+ public void testGetBytesFromZeroInputStream() throws Exception {
+ // Ensure that JarVisitorFactory#getBytesFromInputStream
+ // can handle 0 length streams gracefully.
+ URL emptyTxtUrl = getClass().getResource( "/org/hibernate/jpa/test/packaging/empty.txt" );
+ if ( emptyTxtUrl == null ) {
+ throw new RuntimeException( "Bah!" );
}
- catch ( Exception e ) {
- fail( e.getMessage() );
- }
- }
-
- private Filter[] getFilters() {
- return new Filter[] {
- new PackageFilter( false, null ) {
- public boolean accept(String javaElementName) {
- return true;
- }
- },
- new ClassFilter(
- false, new Class[] {
- Entity.class,
- MappedSuperclass.class,
- Embeddable.class
- }
- ) {
- public boolean accept(String javaElementName) {
- return true;
- }
- },
- new FileFilter( true ) {
- public boolean accept(String javaElementName) {
- return javaElementName.endsWith( "hbm.xml" ) || javaElementName.endsWith( "META-INF/orm.xml" );
- }
- }
- };
+ InputStream emptyStream = new BufferedInputStream( emptyTxtUrl.openStream() );
+ int length = ArchiveHelper.getBytesFromInputStream( emptyStream ).length;
+ assertEquals( length, 0 );
+ emptyStream.close();
}
}
diff --git a/hibernate-entitymanager/src/test/java/org/hibernate/jpa/test/packaging/PackagingTestCase.java b/hibernate-entitymanager/src/test/java/org/hibernate/jpa/test/packaging/PackagingTestCase.java
index 30582808f6..af86c8aeae 100644
--- a/hibernate-entitymanager/src/test/java/org/hibernate/jpa/test/packaging/PackagingTestCase.java
+++ b/hibernate-entitymanager/src/test/java/org/hibernate/jpa/test/packaging/PackagingTestCase.java
@@ -45,6 +45,7 @@ import org.hibernate.jpa.test.Cat;
import org.hibernate.jpa.test.Distributor;
import org.hibernate.jpa.test.Item;
import org.hibernate.jpa.test.Kitten;
+import org.hibernate.jpa.test.TestHelper;
import org.hibernate.jpa.test.pack.cfgxmlpar.Morito;
import org.hibernate.jpa.test.pack.defaultpar.ApplicationServer;
import org.hibernate.jpa.test.pack.defaultpar.IncrementListener;
@@ -204,6 +205,10 @@ public abstract class PackagingTestCase extends BaseCoreFunctionalTestCase {
}
protected File buildExplicitPar() {
+ // explicitpar/persistence.xml references externaljar.jar so build that from here.
+ // this is the reason for tests failing after clean at least on my (Steve) local system
+ buildExternalJar();
+
String fileName = "explicitpar.par";
JavaArchive archive = ShrinkWrap.create( JavaArchive.class, fileName );
archive.addClasses(
@@ -342,8 +347,10 @@ public abstract class PackagingTestCase extends BaseCoreFunctionalTestCase {
// Build a large jar by adding a lorem ipsum file repeatedly.
for ( int i = 0; i < 100; i++ ) {
ArchivePath path = ArchivePaths.create( "META-INF/file" + i );
- archive.addAsResource( new File( "src/test/resources/org/hibernate/jpa/test/packaging/loremipsum.txt" ),
- path );
+ archive.addAsResource(
+ "org/hibernate/jpa/test/packaging/loremipsum.txt",
+ path
+ );
}
File testPackage = new File( packageTargetDir, fileName );
diff --git a/hibernate-entitymanager/src/test/java/org/hibernate/jpa/test/packaging/ScannerTest.java b/hibernate-entitymanager/src/test/java/org/hibernate/jpa/test/packaging/ScannerTest.java
index ed2bc44952..28ed10ab8e 100644
--- a/hibernate-entitymanager/src/test/java/org/hibernate/jpa/test/packaging/ScannerTest.java
+++ b/hibernate-entitymanager/src/test/java/org/hibernate/jpa/test/packaging/ScannerTest.java
@@ -23,31 +23,32 @@
*/
package org.hibernate.jpa.test.packaging;
-import java.io.File;
-import java.lang.annotation.Annotation;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Set;
-import javax.persistence.Converter;
-import javax.persistence.Embeddable;
-import javax.persistence.Entity;
import javax.persistence.EntityManagerFactory;
-import javax.persistence.MappedSuperclass;
import javax.persistence.Persistence;
-
-import org.junit.Test;
+import java.io.File;
+import java.io.InputStream;
+import java.util.HashMap;
import org.hibernate.jpa.AvailableSettings;
-import org.hibernate.jpa.packaging.internal.NativeScanner;
-
+import org.hibernate.jpa.boot.internal.ParsedPersistenceXmlDescriptor;
+import org.hibernate.jpa.boot.spi.PersistenceUnitDescriptor;
+import org.hibernate.jpa.boot.scan.internal.StandardScanOptions;
+import org.hibernate.jpa.boot.scan.internal.StandardScanner;
+import org.hibernate.jpa.boot.spi.ClassDescriptor;
+import org.hibernate.jpa.boot.spi.MappingFileDescriptor;
+import org.hibernate.jpa.boot.spi.NamedInputStream;
+import org.hibernate.jpa.boot.scan.spi.ScanOptions;
+import org.hibernate.jpa.boot.scan.spi.ScanResult;
+import org.hibernate.jpa.boot.scan.spi.Scanner;
import org.hibernate.jpa.test.pack.defaultpar.ApplicationServer;
-import org.hibernate.jpa.packaging.spi.NamedInputStream;
-import org.hibernate.jpa.packaging.spi.Scanner;
import org.hibernate.jpa.test.pack.defaultpar.Version;
+import org.junit.Test;
+
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
/**
* @author Emmanuel Bernard
@@ -59,32 +60,39 @@ public class ScannerTest extends PackagingTestCase {
File defaultPar = buildDefaultPar();
addPackageToClasspath( defaultPar );
- Scanner scanner = new NativeScanner();
- assertEquals( "defaultpar", scanner.getUnqualifiedJarName( defaultPar.toURL() ) );
+ PersistenceUnitDescriptor descriptor = new ParsedPersistenceXmlDescriptor( defaultPar.toURL() );
+ ScanOptions options = new StandardScanOptions( "hbm,class", descriptor.isExcludeUnlistedClasses() );
+ Scanner scanner = new StandardScanner();
+ ScanResult scanResult = scanner.scan( descriptor, options );
- Set> annotationsToLookFor = new HashSet>( 3 );
- annotationsToLookFor.add( Entity.class );
- annotationsToLookFor.add( MappedSuperclass.class );
- annotationsToLookFor.add( Embeddable.class );
- annotationsToLookFor.add( Converter.class );
- final Set> classes = scanner.getClassesInJar( defaultPar.toURL(), annotationsToLookFor );
+ assertEquals( 3, scanResult.getLocatedClasses().size() );
+ assertClassesContained( scanResult, ApplicationServer.class );
+ assertClassesContained( scanResult, Version.class );
- assertEquals( 3, classes.size() );
- assertTrue( classes.contains( ApplicationServer.class ) );
- assertTrue( classes.contains( Version.class ) );
-
- Set filePatterns = new HashSet( 2 );
- filePatterns.add( "**/*.hbm.xml" );
- filePatterns.add( "META-INF/orm.xml" );
- final Set files = scanner.getFilesInJar( defaultPar.toURL(), filePatterns );
-
- assertEquals( 2, files.size() );
- for ( NamedInputStream file : files ) {
- assertNotNull( file.getStream() );
- file.getStream().close();
+ assertEquals( 2, scanResult.getLocatedMappingFiles().size() );
+ for ( MappingFileDescriptor mappingFileDescriptor : scanResult.getLocatedMappingFiles() ) {
+ assertNotNull( mappingFileDescriptor.getName() );
+ assertNotNull( mappingFileDescriptor.getStreamAccess() );
+ InputStream stream = mappingFileDescriptor.getStreamAccess().accessInputStream();
+ assertNotNull( stream );
+ stream.close();
+ NamedInputStream namedInputStream = mappingFileDescriptor.getStreamAccess().asNamedInputStream();
+ assertNotNull( namedInputStream );
+ stream = namedInputStream.getStream();
+ assertNotNull( stream );
+ stream.close();
}
}
+ private void assertClassesContained(ScanResult scanResult, Class classToCheckFor) {
+ for ( ClassDescriptor classDescriptor : scanResult.getLocatedClasses() ) {
+ if ( classDescriptor.getName().equals( classToCheckFor.getName() ) ) {
+ return;
+ }
+ }
+ fail( "ScanResult did not contain expected Class : " + classToCheckFor.getName() );
+ }
+
@Test
public void testCustomScanner() throws Exception {
File defaultPar = buildDefaultPar();
diff --git a/hibernate-envers/src/main/java/org/hibernate/envers/event/BaseEnversCollectionEventListener.java b/hibernate-envers/src/main/java/org/hibernate/envers/event/BaseEnversCollectionEventListener.java
index b6ee70c6de..2cbd8a0553 100644
--- a/hibernate-envers/src/main/java/org/hibernate/envers/event/BaseEnversCollectionEventListener.java
+++ b/hibernate-envers/src/main/java/org/hibernate/envers/event/BaseEnversCollectionEventListener.java
@@ -50,6 +50,7 @@ import org.hibernate.persister.collection.AbstractCollectionPersister;
* @author HernпїЅn Chanfreau
* @author Steve Ebersole
* @author Michal Skowronek (mskowr at o2 dot pl)
+ * @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
*/
public abstract class BaseEnversCollectionEventListener extends BaseEnversEventListener {
protected BaseEnversCollectionEventListener(AuditConfiguration enversConfiguration) {
@@ -65,15 +66,12 @@ public abstract class BaseEnversCollectionEventListener extends BaseEnversEventL
PersistentCollection newColl,
Serializable oldColl,
CollectionEntry collectionEntry) {
- String entityName = event.getAffectedOwnerEntityName();
- if ( ! getAuditConfiguration().getGlobalCfg().isGenerateRevisionsForCollections() ) {
- return;
- }
- if ( getAuditConfiguration().getEntCfg().isVersioned( entityName ) ) {
+ if ( shouldGenerateRevision( event ) ) {
checkIfTransactionInProgress(event.getSession());
AuditProcess auditProcess = getAuditConfiguration().getSyncManager().get(event.getSession());
+ String entityName = event.getAffectedOwnerEntityName();
String ownerEntityName = ((AbstractCollectionPersister) collectionEntry.getLoadedPersister()).getOwnerEntityName();
String referencingPropertyName = collectionEntry.getRole().substring(ownerEntityName.length() + 1);
@@ -123,6 +121,27 @@ public abstract class BaseEnversCollectionEventListener extends BaseEnversEventL
}
}
+ /**
+ * Forces persistent collection initialization.
+ * @param event Collection event.
+ * @return Stored snapshot.
+ */
+ protected Serializable initializeCollection(AbstractCollectionEvent event) {
+ event.getCollection().forceInitialization();
+ return event.getCollection().getStoredSnapshot();
+ }
+
+ /**
+ * Checks whether modification of not-owned relation field triggers new revision and owner entity is versioned.
+ * @param event Collection event.
+ * @return {@code true} if revision based on given event should be generated, {@code false} otherwise.
+ */
+ protected boolean shouldGenerateRevision(AbstractCollectionEvent event) {
+ final String entityName = event.getAffectedOwnerEntityName();
+ return getAuditConfiguration().getGlobalCfg().isGenerateRevisionsForCollections()
+ && getAuditConfiguration().getEntCfg().isVersioned( entityName );
+ }
+
/**
* Looks up a relation description corresponding to the given property in the given entity. If no description is
* found in the given entity, the parent entity is checked (so that inherited relations work).
diff --git a/hibernate-envers/src/main/java/org/hibernate/envers/event/EnversPreCollectionRemoveEventListenerImpl.java b/hibernate-envers/src/main/java/org/hibernate/envers/event/EnversPreCollectionRemoveEventListenerImpl.java
index ab90d7ca26..84ed830874 100644
--- a/hibernate-envers/src/main/java/org/hibernate/envers/event/EnversPreCollectionRemoveEventListenerImpl.java
+++ b/hibernate-envers/src/main/java/org/hibernate/envers/event/EnversPreCollectionRemoveEventListenerImpl.java
@@ -23,6 +23,8 @@
*/
package org.hibernate.envers.event;
+import java.io.Serializable;
+
import org.hibernate.engine.spi.CollectionEntry;
import org.hibernate.envers.configuration.AuditConfiguration;
import org.hibernate.event.spi.PreCollectionRemoveEvent;
@@ -32,6 +34,7 @@ import org.hibernate.event.spi.PreCollectionRemoveEventListener;
* @author Adam Warski (adam at warski dot org)
* @author HernпїЅn Chanfreau
* @author Steve Ebersole
+ * @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
*/
public class EnversPreCollectionRemoveEventListenerImpl
extends BaseEnversCollectionEventListener
@@ -45,7 +48,12 @@ public class EnversPreCollectionRemoveEventListenerImpl
public void onPreRemoveCollection(PreCollectionRemoveEvent event) {
CollectionEntry collectionEntry = getCollectionEntry( event );
if ( collectionEntry != null && !collectionEntry.getLoadedPersister().isInverse() ) {
- onCollectionAction( event, null, collectionEntry.getSnapshot(), collectionEntry );
+ Serializable oldColl = collectionEntry.getSnapshot();
+ if ( !event.getCollection().wasInitialized() && shouldGenerateRevision( event ) ) {
+ // In case of uninitialized collection we need a fresh snapshot to properly calculate audit data.
+ oldColl = initializeCollection( event );
+ }
+ onCollectionAction( event, null, oldColl, collectionEntry );
}
}
}
diff --git a/hibernate-envers/src/test/java/org/hibernate/envers/test/entities/manytomany/unidirectional/JoinTableEntity.java b/hibernate-envers/src/test/java/org/hibernate/envers/test/entities/manytomany/unidirectional/JoinTableEntity.java
new file mode 100644
index 0000000000..1e5c162b08
--- /dev/null
+++ b/hibernate-envers/src/test/java/org/hibernate/envers/test/entities/manytomany/unidirectional/JoinTableEntity.java
@@ -0,0 +1,95 @@
+package org.hibernate.envers.test.entities.manytomany.unidirectional;
+
+import java.io.Serializable;
+import java.util.HashSet;
+import java.util.Set;
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.Id;
+import javax.persistence.JoinColumn;
+import javax.persistence.JoinTable;
+import javax.persistence.ManyToMany;
+
+import org.hibernate.envers.Audited;
+import org.hibernate.envers.test.entities.StrTestEntity;
+
+/**
+ * @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
+ */
+@Entity
+@Audited
+public class JoinTableEntity implements Serializable {
+ @Id
+ @GeneratedValue
+ private Long id;
+
+ private String data;
+
+ @ManyToMany
+ @JoinTable(name = "test_join_table",
+ joinColumns = @JoinColumn(name = "assoc_id1"),
+ inverseJoinColumns = @JoinColumn(name = "assoc_id2")
+ )
+ private Set references = new HashSet();
+
+ public JoinTableEntity() {
+ }
+
+ public JoinTableEntity(String data) {
+ this.data = data;
+ }
+
+ public JoinTableEntity(Long id, String data) {
+ this.id = id;
+ this.data = data;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if ( this == o ) return true;
+ if ( !( o instanceof JoinTableEntity ) ) return false;
+
+ JoinTableEntity that = (JoinTableEntity) o;
+
+ if ( data != null ? !data.equals( that.data ) : that.data != null ) return false;
+ if ( id != null ? !id.equals( that.id ) : that.id != null ) return false;
+
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ int result = id != null ? id.hashCode() : 0;
+ result = 31 * result + ( data != null ? data.hashCode() : 0 );
+ return result;
+ }
+
+ @Override
+ public String toString() {
+ return "JoinTableEntity(id = " + id + ", data = " + data + ")";
+ }
+
+ public Long getId() {
+ return id;
+ }
+
+ public void setId(Long id) {
+ this.id = id;
+ }
+
+ public Set getReferences() {
+ return references;
+ }
+
+ public void setReferences(Set references) {
+ this.references = references;
+ }
+
+ public String getData() {
+ return data;
+ }
+
+ public void setData(String data) {
+ this.data = data;
+ }
+}
diff --git a/hibernate-envers/src/test/java/org/hibernate/envers/test/integration/manytomany/unidirectional/JoinTableDetachedTest.java b/hibernate-envers/src/test/java/org/hibernate/envers/test/integration/manytomany/unidirectional/JoinTableDetachedTest.java
new file mode 100644
index 0000000000..78b6a86d72
--- /dev/null
+++ b/hibernate-envers/src/test/java/org/hibernate/envers/test/integration/manytomany/unidirectional/JoinTableDetachedTest.java
@@ -0,0 +1,137 @@
+package org.hibernate.envers.test.integration.manytomany.unidirectional;
+
+import java.util.Arrays;
+import java.util.HashSet;
+import javax.persistence.EntityManager;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import org.hibernate.envers.test.BaseEnversJPAFunctionalTestCase;
+import org.hibernate.envers.test.Priority;
+import org.hibernate.envers.test.entities.StrTestEntity;
+import org.hibernate.envers.test.entities.manytomany.unidirectional.JoinTableEntity;
+import org.hibernate.testing.TestForIssue;
+
+/**
+ * @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
+ */
+@TestForIssue( jiraKey = "HHH-8087" )
+public class JoinTableDetachedTest extends BaseEnversJPAFunctionalTestCase {
+ private Long collectionEntityId = null;
+ private Integer element1Id = null;
+ private Integer element2Id = null;
+
+ @Override
+ protected Class>[] getAnnotatedClasses() {
+ return new Class>[] { JoinTableEntity.class, StrTestEntity.class };
+ }
+
+ @Test
+ @Priority(10)
+ public void initData() {
+ EntityManager em = getEntityManager();
+
+ // Revision 1 - addition
+ em.getTransaction().begin();
+ JoinTableEntity collectionEntity = new JoinTableEntity( "some data" );
+ StrTestEntity element1 = new StrTestEntity( "str1" );
+ StrTestEntity element2 = new StrTestEntity( "str2" );
+ collectionEntity.getReferences().add( element1 );
+ collectionEntity.getReferences().add( element2 );
+ em.persist( element1 );
+ em.persist( element2 );
+ em.persist( collectionEntity );
+ em.getTransaction().commit();
+
+ collectionEntityId = collectionEntity.getId();
+ element1Id = element1.getId();
+ element2Id = element2.getId();
+
+ em.close();
+ em = getEntityManager();
+
+ // Revision 2 - simple modification
+ em.getTransaction().begin();
+ collectionEntity = em.find( JoinTableEntity.class, collectionEntity.getId() );
+ collectionEntity.setData( "some other data" );
+ collectionEntity = em.merge( collectionEntity );
+ em.getTransaction().commit();
+
+ em.close();
+ em = getEntityManager();
+
+ // Revision 3 - remove detached object from collection
+ em.getTransaction().begin();
+ collectionEntity = em.find( JoinTableEntity.class, collectionEntity.getId() );
+ collectionEntity.getReferences().remove( element1 );
+ collectionEntity = em.merge( collectionEntity );
+ em.getTransaction().commit();
+
+ em.close();
+ em = getEntityManager();
+
+ // Revision 4 - replace the collection
+ em.getTransaction().begin();
+ collectionEntity = em.find( JoinTableEntity.class, collectionEntity.getId() );
+ collectionEntity.setReferences( new HashSet() );
+ collectionEntity = em.merge( collectionEntity );
+ em.getTransaction().commit();
+
+ em.close();
+ em = getEntityManager();
+
+ // Revision 5 - add to collection
+ em.getTransaction().begin();
+ collectionEntity = em.find( JoinTableEntity.class, collectionEntity.getId() );
+ collectionEntity.getReferences().add( element1 );
+ collectionEntity = em.merge( collectionEntity );
+ em.getTransaction().commit();
+
+ em.close();
+ }
+
+ @Test
+ public void testRevisionsCounts() {
+ Assert.assertEquals( Arrays.asList( 1, 2, 3, 4, 5 ), getAuditReader().getRevisions(JoinTableEntity.class, collectionEntityId ) );
+ Assert.assertEquals( Arrays.asList( 1 ), getAuditReader().getRevisions(StrTestEntity.class, element1Id ) );
+ Assert.assertEquals( Arrays.asList( 1 ), getAuditReader().getRevisions(StrTestEntity.class, element2Id ) );
+ }
+
+ @Test
+ public void testHistoryOfCollectionEntity() {
+ // Revision 1
+ JoinTableEntity collectionEntity = new JoinTableEntity( collectionEntityId, "some data" );
+ StrTestEntity element1 = new StrTestEntity( "str1", element1Id );
+ StrTestEntity element2 = new StrTestEntity( "str2", element2Id );
+ collectionEntity.getReferences().add( element1 );
+ collectionEntity.getReferences().add( element2 );
+ JoinTableEntity ver1 = getAuditReader().find( JoinTableEntity.class, collectionEntityId, 1 );
+ Assert.assertEquals( collectionEntity, ver1 );
+ Assert.assertEquals( collectionEntity.getReferences(), ver1.getReferences() );
+
+ // Revision 2
+ collectionEntity.setData( "some other data" );
+ JoinTableEntity ver2 = getAuditReader().find( JoinTableEntity.class, collectionEntityId, 2 );
+ Assert.assertEquals( collectionEntity, ver2 );
+ Assert.assertEquals( collectionEntity.getReferences(), ver2.getReferences() );
+
+ // Revision 3
+ collectionEntity.getReferences().remove( element1 );
+ JoinTableEntity ver3 = getAuditReader().find( JoinTableEntity.class, collectionEntityId, 3 );
+ Assert.assertEquals( collectionEntity, ver3 );
+ Assert.assertEquals( collectionEntity.getReferences(), ver3.getReferences() );
+
+ // Revision 4
+ collectionEntity.setReferences( new HashSet() );
+ JoinTableEntity ver4 = getAuditReader().find( JoinTableEntity.class, collectionEntityId, 4 );
+ Assert.assertEquals( collectionEntity, ver4 );
+ Assert.assertEquals( collectionEntity.getReferences(), ver4.getReferences() );
+
+ // Revision 5
+ collectionEntity.getReferences().add( element1 );
+ JoinTableEntity ver5 = getAuditReader().find( JoinTableEntity.class, collectionEntityId, 5 );
+ Assert.assertEquals( collectionEntity, ver5 );
+ Assert.assertEquals( collectionEntity.getReferences(), ver5.getReferences() );
+ }
+}
diff --git a/libraries.gradle b/libraries.gradle
index c34ee46d6e..36aa4892b5 100644
--- a/libraries.gradle
+++ b/libraries.gradle
@@ -58,7 +58,7 @@ ext {
// javax
jpa: 'org.hibernate.javax.persistence:hibernate-jpa-2.1-api:1.0.0.Draft-14',
- jta: 'org.jboss.spec.javax.transaction:jboss-transaction-api_1.1_spec:1.0.0.Final',
+ jta: 'org.jboss.spec.javax.transaction:jboss-transaction-api_1.2_spec:1.0.0.Alpha1',
validation: 'javax.validation:validation-api:1.0.0.GA',
jacc: 'org.jboss.spec.javax.security.jacc:jboss-jacc-api_1.4_spec:1.0.2.Final',