merge master
This commit is contained in:
commit
72c5f8f5e9
|
@ -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' )
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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 );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<Table, List<UniqueConstraintHolder>> tableListEntry : uniqueConstraintHoldersByTable.entrySet() ) {
|
||||
final Table table = tableListEntry.getKey();
|
||||
final List<UniqueConstraintHolder> 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
|
||||
);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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") );
|
||||
|
|
|
@ -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<indexElementList.size();i++){
|
||||
Element subelement = (Element)indexElementList.get( i );
|
||||
AnnotationDescriptor indexAnn = new AnnotationDescriptor( Index.class );
|
||||
copyStringAttribute( indexAnn, subelement, "name", false );
|
||||
copyStringAttribute( indexAnn, subelement, "column-list", true );
|
||||
copyBooleanAttribute( indexAnn, subelement, "unique" );
|
||||
indexes[i] = AnnotationFactory.create( indexAnn );
|
||||
}
|
||||
annotation.setValue( "indexes", indexes );
|
||||
}
|
||||
private static void buildUniqueConstraints(AnnotationDescriptor annotation, Element element) {
|
||||
List uniqueConstraintElementList = element.elements( "unique-constraint" );
|
||||
UniqueConstraint[] uniqueConstraints = new UniqueConstraint[uniqueConstraintElementList.size()];
|
||||
|
|
|
@ -29,6 +29,7 @@ import java.util.ArrayList;
|
|||
import java.util.Arrays;
|
||||
import java.util.Iterator;
|
||||
import java.util.StringTokenizer;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.hibernate.dialect.Dialect;
|
||||
import org.hibernate.internal.util.collections.ArrayHelper;
|
||||
|
@ -763,4 +764,18 @@ public final class StringHelper {
|
|||
public static String[] toArrayElement(String s) {
|
||||
return ( s == null || s.length() == 0 ) ? new String[0] : new String[] { s };
|
||||
}
|
||||
|
||||
// Oracle restricts identifier lengths to 30. Rather than tie this to
|
||||
// Dialect, simply restrict randomly-generated constrain names across
|
||||
// the board.
|
||||
private static final int MAX_NAME_LENGTH = 30;
|
||||
public static String randomFixedLengthHex(String prefix) {
|
||||
int length = MAX_NAME_LENGTH - prefix.length();
|
||||
String s = UUID.randomUUID().toString();
|
||||
s = s.replace( "-", "" );
|
||||
if (s.length() > length) {
|
||||
s = s.substring( 0, length );
|
||||
}
|
||||
return prefix + s;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,147 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2013, Red Hat Inc. or third-party contributors as
|
||||
* indicated by the @author tags or express copyright attribution
|
||||
* statements applied by the authors. All third-party contributions are
|
||||
* distributed under license by Red Hat Inc.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||
* Lesser General Public License, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this distribution; if not, write to:
|
||||
* Free Software Foundation, Inc.
|
||||
* 51 Franklin Street, Fifth Floor
|
||||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.hibernate.internal.util.xml;
|
||||
|
||||
import javax.xml.stream.XMLEventReader;
|
||||
import javax.xml.stream.XMLStreamConstants;
|
||||
import javax.xml.stream.XMLStreamException;
|
||||
import javax.xml.stream.events.Characters;
|
||||
import javax.xml.stream.events.EntityDeclaration;
|
||||
import javax.xml.stream.events.EntityReference;
|
||||
import javax.xml.stream.events.XMLEvent;
|
||||
import javax.xml.stream.util.EventReaderDelegate;
|
||||
|
||||
/**
|
||||
* Base for XMLEventReader that implements the {@link #getElementText()} and {@link #nextTag()} APIs in a
|
||||
* way that is agnostic from the rest of the XMLEventReader implementation. Both will use the subclasses
|
||||
* {@link #internalNextEvent()} as the exclusive way to read events.
|
||||
*
|
||||
* Note, copied from the uPortal project by permission of author. See
|
||||
* https://github.com/Jasig/uPortal/blob/master/uportal-war/src/main/java/org/jasig/portal/xml/stream/BaseXMLEventReader.java
|
||||
*
|
||||
* @author Eric Dalquist
|
||||
*/
|
||||
public abstract class BaseXMLEventReader extends EventReaderDelegate {
|
||||
private XMLEvent previousEvent;
|
||||
|
||||
public BaseXMLEventReader(XMLEventReader reader) {
|
||||
super(reader);
|
||||
}
|
||||
|
||||
/**
|
||||
* Subclass's version of {@link #nextEvent()}, called by {@link #next()}
|
||||
*/
|
||||
protected abstract XMLEvent internalNextEvent() throws XMLStreamException;
|
||||
|
||||
/**
|
||||
* @return The XMLEvent returned by the last call to {@link #internalNextEvent()}
|
||||
*/
|
||||
protected final XMLEvent getPreviousEvent() {
|
||||
return this.previousEvent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final XMLEvent nextEvent() throws XMLStreamException {
|
||||
this.previousEvent = this.internalNextEvent();
|
||||
return this.previousEvent;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see java.util.Iterator#next()
|
||||
*/
|
||||
@Override
|
||||
public final Object next() {
|
||||
try {
|
||||
return this.nextEvent();
|
||||
}
|
||||
catch (XMLStreamException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see javax.xml.stream.XMLEventReader#getElementText()
|
||||
*/
|
||||
@Override
|
||||
public final String getElementText() throws XMLStreamException {
|
||||
XMLEvent event = this.previousEvent;
|
||||
if (event == null) {
|
||||
throw new XMLStreamException("Must be on START_ELEMENT to read next text, element was null");
|
||||
}
|
||||
if (!event.isStartElement()) {
|
||||
throw new XMLStreamException("Must be on START_ELEMENT to read next text", event.getLocation());
|
||||
}
|
||||
|
||||
final StringBuilder text = new StringBuilder();
|
||||
while (!event.isEndDocument()) {
|
||||
switch (event.getEventType()) {
|
||||
case XMLStreamConstants.CHARACTERS:
|
||||
case XMLStreamConstants.SPACE:
|
||||
case XMLStreamConstants.CDATA: {
|
||||
final Characters characters = event.asCharacters();
|
||||
text.append(characters.getData());
|
||||
break;
|
||||
}
|
||||
case XMLStreamConstants.ENTITY_REFERENCE: {
|
||||
final EntityReference entityReference = (EntityReference)event;
|
||||
final EntityDeclaration declaration = entityReference.getDeclaration();
|
||||
text.append(declaration.getReplacementText());
|
||||
break;
|
||||
}
|
||||
case XMLStreamConstants.COMMENT:
|
||||
case XMLStreamConstants.PROCESSING_INSTRUCTION: {
|
||||
//Ignore
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
throw new XMLStreamException("Unexpected event type '" + XMLStreamConstantsUtils.getEventName(event.getEventType()) + "' encountered. Found event: " + event, event.getLocation());
|
||||
}
|
||||
}
|
||||
|
||||
event = this.nextEvent();
|
||||
}
|
||||
|
||||
return text.toString();
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see javax.xml.stream.XMLEventReader#nextTag()
|
||||
*/
|
||||
@Override
|
||||
public final XMLEvent nextTag() throws XMLStreamException {
|
||||
XMLEvent event = this.nextEvent();
|
||||
while ((event.isCharacters() && event.asCharacters().isWhiteSpace())
|
||||
|| event.isProcessingInstruction()
|
||||
|| event.getEventType() == XMLStreamConstants.COMMENT) {
|
||||
|
||||
event = this.nextEvent();
|
||||
}
|
||||
|
||||
if (!event.isStartElement() && event.isEndElement()) {
|
||||
throw new XMLStreamException("Unexpected event type '" + XMLStreamConstantsUtils.getEventName(event.getEventType()) + "' encountered. Found event: " + event, event.getLocation());
|
||||
}
|
||||
|
||||
return event;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,196 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2013, Red Hat Inc. or third-party contributors as
|
||||
* indicated by the @author tags or express copyright attribution
|
||||
* statements applied by the authors. All third-party contributions are
|
||||
* distributed under license by Red Hat Inc.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||
* Lesser General Public License, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this distribution; if not, write to:
|
||||
* Free Software Foundation, Inc.
|
||||
* 51 Franklin Street, Fifth Floor
|
||||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.hibernate.internal.util.xml;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.ListIterator;
|
||||
|
||||
import javax.xml.stream.XMLEventReader;
|
||||
import javax.xml.stream.XMLStreamException;
|
||||
import javax.xml.stream.events.XMLEvent;
|
||||
|
||||
/**
|
||||
* Buffers XML events for later re-reading
|
||||
*
|
||||
* Note, copied from the uPortal project by permission of author. See
|
||||
* https://github.com/Jasig/uPortal/blob/master/uportal-war/src/main/java/org/jasig/portal/xml/stream/BufferedXMLEventReader.java
|
||||
*
|
||||
* @author Eric Dalquist
|
||||
*/
|
||||
public class BufferedXMLEventReader extends BaseXMLEventReader {
|
||||
private final LinkedList<XMLEvent> eventBuffer = new LinkedList<XMLEvent>();
|
||||
private int eventLimit = 0;
|
||||
private ListIterator<XMLEvent> bufferReader = null;
|
||||
|
||||
/**
|
||||
* Create new buffering reader, no buffering is done until {@link #mark(int)} is called.
|
||||
*/
|
||||
public BufferedXMLEventReader(XMLEventReader reader) {
|
||||
super(reader);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create new buffering reader. Calls {@link #mark(int)} with the specified event limit
|
||||
* @see #mark(int)
|
||||
*/
|
||||
public BufferedXMLEventReader(XMLEventReader reader, int eventLimit) {
|
||||
super(reader);
|
||||
this.eventLimit = eventLimit;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return A copy of the current buffer
|
||||
*/
|
||||
public List<XMLEvent> getBuffer() {
|
||||
return new ArrayList<XMLEvent>(this.eventBuffer);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.jasig.portal.xml.stream.BaseXMLEventReader#internalNextEvent()
|
||||
*/
|
||||
@Override
|
||||
protected XMLEvent internalNextEvent() throws XMLStreamException {
|
||||
//If there is an iterator to read from reset was called, use the iterator
|
||||
//until it runs out of events.
|
||||
if (this.bufferReader != null) {
|
||||
final XMLEvent event = this.bufferReader.next();
|
||||
|
||||
//If nothing left in the iterator, remove the reference and fall through to direct reading
|
||||
if (!this.bufferReader.hasNext()) {
|
||||
this.bufferReader = null;
|
||||
}
|
||||
|
||||
return event;
|
||||
}
|
||||
|
||||
//Get the next event from the underlying reader
|
||||
final XMLEvent event = this.getParent().nextEvent();
|
||||
|
||||
//if buffering add the event
|
||||
if (this.eventLimit != 0) {
|
||||
this.eventBuffer.offer(event);
|
||||
|
||||
//If limited buffer size and buffer is too big trim the buffer.
|
||||
if (this.eventLimit > 0 && this.eventBuffer.size() > this.eventLimit) {
|
||||
this.eventBuffer.poll();
|
||||
}
|
||||
}
|
||||
|
||||
return event;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
return this.bufferReader != null || super.hasNext();
|
||||
}
|
||||
|
||||
@Override
|
||||
public XMLEvent peek() throws XMLStreamException {
|
||||
if (this.bufferReader != null) {
|
||||
final XMLEvent event = this.bufferReader.next();
|
||||
this.bufferReader.previous(); //move the iterator back
|
||||
return event;
|
||||
}
|
||||
return super.peek();
|
||||
}
|
||||
|
||||
/**
|
||||
* Same as calling {@link #mark(int)} with -1.
|
||||
*/
|
||||
public void mark() {
|
||||
this.mark(-1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Start buffering events
|
||||
* @param eventLimit the maximum number of events to buffer. -1 will buffer all events, 0 will buffer no events.
|
||||
*/
|
||||
public void mark(int eventLimit) {
|
||||
this.eventLimit = eventLimit;
|
||||
|
||||
//Buffering no events now, clear the buffer and buffered reader
|
||||
if (this.eventLimit == 0) {
|
||||
this.eventBuffer.clear();
|
||||
this.bufferReader = null;
|
||||
}
|
||||
//Buffering limited set of events, lets trim the buffer if needed
|
||||
else if (this.eventLimit > 0) {
|
||||
//If there is an iterator check its current position and calculate the new iterator start position
|
||||
int iteratorIndex = 0;
|
||||
if (this.bufferReader != null) {
|
||||
final int nextIndex = this.bufferReader.nextIndex();
|
||||
iteratorIndex = Math.max(0, nextIndex - (this.eventBuffer.size() - this.eventLimit));
|
||||
}
|
||||
|
||||
//Trim the buffer until it is not larger than the limit
|
||||
while (this.eventBuffer.size() > this.eventLimit) {
|
||||
this.eventBuffer.poll();
|
||||
}
|
||||
|
||||
//If there is an iterator re-create it using the newly calculated index
|
||||
if (this.bufferReader != null) {
|
||||
this.bufferReader = this.eventBuffer.listIterator(iteratorIndex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset the reader to these start of the buffered events.
|
||||
*/
|
||||
public void reset() {
|
||||
if (this.eventBuffer.isEmpty()) {
|
||||
this.bufferReader = null;
|
||||
}
|
||||
else {
|
||||
this.bufferReader = this.eventBuffer.listIterator();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws XMLStreamException {
|
||||
this.mark(0);
|
||||
super.close();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The number of events in the buffer.
|
||||
*/
|
||||
public int bufferSize() {
|
||||
return this.eventBuffer.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* If reading from the buffer after a {@link #reset()} call an {@link IllegalStateException} will be thrown.
|
||||
*/
|
||||
@Override
|
||||
public void remove() {
|
||||
if (this.bufferReader != null && this.bufferReader.hasNext()) {
|
||||
throw new IllegalStateException("Cannot remove a buffered element");
|
||||
}
|
||||
|
||||
super.remove();
|
||||
}
|
||||
}
|
|
@ -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<SAXParseException>();
|
||||
|
@ -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<SAXParseException> getErrors() {
|
||||
return errors;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,141 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2013, Red Hat Inc. or third-party contributors as
|
||||
* indicated by the @author tags or express copyright attribution
|
||||
* statements applied by the authors. All third-party contributions are
|
||||
* distributed under license by Red Hat Inc.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||
* Lesser General Public License, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this distribution; if not, write to:
|
||||
* Free Software Foundation, Inc.
|
||||
* 51 Franklin Street, Fifth Floor
|
||||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.hibernate.internal.util.xml;
|
||||
|
||||
import java.util.Deque;
|
||||
import java.util.LinkedList;
|
||||
import java.util.NoSuchElementException;
|
||||
|
||||
import javax.xml.namespace.QName;
|
||||
import javax.xml.stream.XMLEventReader;
|
||||
import javax.xml.stream.XMLStreamException;
|
||||
import javax.xml.stream.events.EndElement;
|
||||
import javax.xml.stream.events.StartElement;
|
||||
import javax.xml.stream.events.XMLEvent;
|
||||
|
||||
/**
|
||||
* Base class for {@link XMLEventReader}s that want to modify or remove events from the reader stream.
|
||||
* If a {@link StartElement} event is removed the subclass's {@link #filterEvent(XMLEvent, boolean)} will
|
||||
* not see any events until after the matching {@link EndElement} event.
|
||||
*
|
||||
* Note, copied from the uPortal project by permission of author. See
|
||||
* https://github.com/Jasig/uPortal/blob/master/uportal-war/src/main/java/org/jasig/portal/xml/stream/FilteringXMLEventReader.java
|
||||
*
|
||||
* @author Eric Dalquist
|
||||
*/
|
||||
public abstract class FilteringXMLEventReader extends BaseXMLEventReader {
|
||||
private final Deque<QName> prunedElements = new LinkedList<QName>();
|
||||
private XMLEvent peekedEvent = null;
|
||||
|
||||
public FilteringXMLEventReader(XMLEventReader reader) {
|
||||
super(reader);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected final XMLEvent internalNextEvent() throws XMLStreamException {
|
||||
return this.internalNext(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
try {
|
||||
return peekedEvent != null || (super.hasNext() && this.peek() != null);
|
||||
}
|
||||
catch (XMLStreamException e) {
|
||||
throw new RuntimeException(e.getMessage(), e);
|
||||
}
|
||||
catch (NoSuchElementException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public final XMLEvent peek() throws XMLStreamException {
|
||||
if (peekedEvent != null) {
|
||||
return peekedEvent;
|
||||
}
|
||||
|
||||
peekedEvent = internalNext(true);
|
||||
return peekedEvent;
|
||||
}
|
||||
|
||||
protected final XMLEvent internalNext(boolean peek) throws XMLStreamException {
|
||||
XMLEvent event = null;
|
||||
|
||||
if (peekedEvent != null) {
|
||||
event = peekedEvent;
|
||||
peekedEvent = null;
|
||||
return event;
|
||||
}
|
||||
|
||||
do {
|
||||
event = super.getParent().nextEvent();
|
||||
|
||||
//If there are pruned elements in the queue filtering events is still needed
|
||||
if (!prunedElements.isEmpty()) {
|
||||
//If another start element add it to the queue
|
||||
if (event.isStartElement()) {
|
||||
final StartElement startElement = event.asStartElement();
|
||||
prunedElements.push(startElement.getName());
|
||||
}
|
||||
//If end element pop the newest name of the queue and double check that the start/end elements match up
|
||||
else if (event.isEndElement()) {
|
||||
final QName startElementName = prunedElements.pop();
|
||||
|
||||
final EndElement endElement = event.asEndElement();
|
||||
final QName endElementName = endElement.getName();
|
||||
|
||||
if (!startElementName.equals(endElementName)) {
|
||||
throw new IllegalArgumentException("Malformed XMLEvent stream. Expected end element for " + startElementName + " but found end element for " + endElementName);
|
||||
}
|
||||
}
|
||||
|
||||
event = null;
|
||||
}
|
||||
else {
|
||||
final XMLEvent filteredEvent = this.filterEvent(event, peek);
|
||||
|
||||
//If the event is being removed and it is a start element all elements until the matching
|
||||
//end element need to be removed as well
|
||||
if (filteredEvent == null && event.isStartElement()) {
|
||||
final StartElement startElement = event.asStartElement();
|
||||
final QName name = startElement.getName();
|
||||
prunedElements.push(name);
|
||||
}
|
||||
|
||||
event = filteredEvent;
|
||||
}
|
||||
}
|
||||
while (event == null);
|
||||
|
||||
return event;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param event The current event
|
||||
* @param peek If the event is from a {@link #peek()} call
|
||||
* @return The event to return, if null is returned the event is dropped from the stream and the next event will be used.
|
||||
*/
|
||||
protected abstract XMLEvent filterEvent(XMLEvent event, boolean peek);
|
||||
}
|
|
@ -0,0 +1,148 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2013, Red Hat Inc. or third-party contributors as
|
||||
* indicated by the @author tags or express copyright attribution
|
||||
* statements applied by the authors. All third-party contributions are
|
||||
* distributed under license by Red Hat Inc.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||
* Lesser General Public License, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this distribution; if not, write to:
|
||||
* Free Software Foundation, Inc.
|
||||
* 51 Franklin Street, Fifth Floor
|
||||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.hibernate.internal.util.xml;
|
||||
|
||||
import javax.xml.stream.XMLResolver;
|
||||
import javax.xml.stream.XMLStreamException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.URL;
|
||||
|
||||
import org.xml.sax.InputSource;
|
||||
|
||||
import org.jboss.logging.Logger;
|
||||
|
||||
import org.hibernate.internal.CoreMessageLogger;
|
||||
import org.hibernate.internal.util.ConfigHelper;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class LocalXmlResourceResolver implements javax.xml.stream.XMLResolver {
|
||||
private static final CoreMessageLogger log = Logger.getMessageLogger(
|
||||
CoreMessageLogger.class,
|
||||
MappingReader.class.getName()
|
||||
);
|
||||
|
||||
public static final LocalXmlResourceResolver INSTANCE = new LocalXmlResourceResolver();
|
||||
|
||||
/**
|
||||
* Namespace for the orm.xml xsd for jpa 1.0 and 2.0
|
||||
*/
|
||||
public static final String INITIAL_JPA_ORM_NS = "http://java.sun.com/xml/ns/persistence/orm";
|
||||
|
||||
/**
|
||||
* Namespace for the orm.xml xsd for jpa 2.1
|
||||
*/
|
||||
public static final String SECOND_JPA_ORM_NS = "http://xmlns.jcp.org/xml/ns/persistence/orm";
|
||||
|
||||
public static final String HIBERNATE_MAPPING_DTD_URL_BASE = "http://www.hibernate.org/dtd/";
|
||||
public static final String LEGACY_HIBERNATE_MAPPING_DTD_URL_BASE = "http://hibernate.sourceforge.net/";
|
||||
public static final String CLASSPATH_EXTENSION_URL_BASE = "classpath://";
|
||||
|
||||
@Override
|
||||
public Object resolveEntity(String publicID, String systemID, String baseURI, String namespace) throws XMLStreamException {
|
||||
log.tracef( "In resolveEntity(%s, %s, %s, %s)", publicID, systemID, baseURI, namespace );
|
||||
|
||||
if ( namespace != null ) {
|
||||
log.debugf( "Interpreting namespace : %s", namespace );
|
||||
if ( INITIAL_JPA_ORM_NS.equals( namespace ) ) {
|
||||
return openUrlStream( MappingReader.SupportedOrmXsdVersion.ORM_2_0.getSchemaUrl() );
|
||||
}
|
||||
else if ( SECOND_JPA_ORM_NS.equals( namespace ) ) {
|
||||
return openUrlStream( MappingReader.SupportedOrmXsdVersion.ORM_2_1.getSchemaUrl() );
|
||||
}
|
||||
}
|
||||
|
||||
if ( systemID != null ) {
|
||||
log.debugf( "Interpreting systemID : %s", namespace );
|
||||
InputStream stream = null;
|
||||
if ( systemID.startsWith( HIBERNATE_MAPPING_DTD_URL_BASE ) ) {
|
||||
log.debug( "Recognized hibernate namespace; attempting to resolve on classpath under org/hibernate/" );
|
||||
stream = resolveOnClassPath( systemID, HIBERNATE_MAPPING_DTD_URL_BASE );
|
||||
}
|
||||
else if ( systemID.startsWith( LEGACY_HIBERNATE_MAPPING_DTD_URL_BASE ) ) {
|
||||
log.recognizedObsoleteHibernateNamespace( LEGACY_HIBERNATE_MAPPING_DTD_URL_BASE, HIBERNATE_MAPPING_DTD_URL_BASE );
|
||||
log.debug( "Attempting to resolve on classpath under org/hibernate/" );
|
||||
stream = resolveOnClassPath( systemID, LEGACY_HIBERNATE_MAPPING_DTD_URL_BASE );
|
||||
}
|
||||
else if ( systemID.startsWith( CLASSPATH_EXTENSION_URL_BASE ) ) {
|
||||
log.debug( "Recognized local namespace; attempting to resolve on classpath" );
|
||||
final String path = systemID.substring( CLASSPATH_EXTENSION_URL_BASE.length() );
|
||||
stream = resolveInLocalNamespace( path );
|
||||
if ( stream == null ) {
|
||||
log.debugf( "Unable to resolve [%s] on classpath", systemID );
|
||||
}
|
||||
else {
|
||||
log.debugf( "Resolved [%s] on classpath", systemID );
|
||||
}
|
||||
}
|
||||
|
||||
if ( stream != null ) {
|
||||
return stream;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private InputStream openUrlStream(URL url) {
|
||||
try {
|
||||
return url.openStream();
|
||||
}
|
||||
catch (IOException e) {
|
||||
throw new XmlInfrastructureException( "Could not open url stream : " + url.toExternalForm(), e );
|
||||
}
|
||||
}
|
||||
|
||||
private InputStream resolveOnClassPath(String systemID, String namespace) {
|
||||
final String relativeResourceName = systemID.substring( namespace.length() );
|
||||
final String path = "org/hibernate/" + relativeResourceName;
|
||||
InputStream dtdStream = resolveInHibernateNamespace( path );
|
||||
if ( dtdStream == null ) {
|
||||
log.debugf( "Unable to locate [%s] on classpath", systemID );
|
||||
if ( relativeResourceName.contains( "2.0" ) ) {
|
||||
log.usingOldDtd();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
else {
|
||||
log.debugf( "Located [%s] in classpath", systemID );
|
||||
return dtdStream;
|
||||
}
|
||||
}
|
||||
|
||||
private InputStream resolveInHibernateNamespace(String path) {
|
||||
return this.getClass().getClassLoader().getResourceAsStream( path );
|
||||
}
|
||||
|
||||
private InputStream resolveInLocalNamespace(String path) {
|
||||
try {
|
||||
return ConfigHelper.getUserResourceAsStream( path );
|
||||
}
|
||||
catch ( Throwable t ) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -23,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() + "]" );
|
||||
// }
|
||||
//
|
||||
// }
|
||||
}
|
||||
|
|
|
@ -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()
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
|
@ -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";
|
||||
}
|
||||
}
|
|
@ -27,6 +27,8 @@ import java.io.Serializable;
|
|||
|
||||
import org.dom4j.Document;
|
||||
|
||||
import org.hibernate.jaxb.spi.Origin;
|
||||
|
||||
/**
|
||||
* Describes a parsed xml document.
|
||||
*
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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 );
|
||||
}
|
||||
}
|
|
@ -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 );
|
||||
|
|
|
@ -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 <stliu@hibernate.org>
|
||||
*/
|
||||
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<Namespace> namespaces = new ArrayList<Namespace>();
|
||||
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() );
|
||||
}
|
||||
}
|
|
@ -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() );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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;
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -6,7 +6,7 @@
|
|||
jaxb:extensionBindingPrefixes="inheritance"
|
||||
version="2.1">
|
||||
|
||||
<jaxb:bindings schemaLocation="../resources/org/hibernate/ejb/orm_2_0.xsd" node="/xsd:schema">
|
||||
<jaxb:bindings schemaLocation="../resources/org/hibernate/jpa/orm_2_1.xsd" node="/xsd:schema">
|
||||
<jaxb:schemaBindings>
|
||||
<jaxb:nameXmlTransform>
|
||||
<jaxb:typeName prefix="Jaxb"/>
|
||||
|
|
|
@ -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" );
|
||||
|
|
|
@ -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<JaxbEntityMappings> xmlEntityMappingsList = new ArrayList<JaxbEntityMappings>();
|
||||
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() );
|
||||
|
|
|
@ -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 <stliu@hibernate.org>
|
||||
*/
|
||||
|
||||
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<Index> 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<Column> 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<Index> 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<Column> 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<Index> 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<Column> columnIterator = index.getColumnIterator();
|
||||
Column column = columnIterator.next();
|
||||
assertEquals( "importers_id", column.getName() );
|
||||
assertSame( collectionTable, index.getTable() );
|
||||
}
|
||||
|
||||
// @Test
|
||||
// public void testTableGeneratorIndex(){
|
||||
// //todo
|
||||
// }
|
||||
}
|
|
@ -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 <stliu@hibernate.org>
|
||||
*/
|
||||
@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<Dealer> otherDealers;
|
||||
|
||||
|
||||
@ManyToMany(cascade = CascadeType.ALL, mappedBy = "cars")
|
||||
private List<Importer> 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<Importer> getImporters() {
|
||||
return importers;
|
||||
}
|
||||
|
||||
public void setImporters(List<Importer> importers) {
|
||||
this.importers = importers;
|
||||
}
|
||||
|
||||
public Set<Dealer> getOtherDealers() {
|
||||
return otherDealers;
|
||||
}
|
||||
|
||||
public void setOtherDealers(Set<Dealer> 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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 <stliu@hibernate.org>
|
||||
*/
|
||||
@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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 <stliu@hibernate.org>
|
||||
*/
|
||||
@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<Car> cars;
|
||||
|
||||
public List<Car> getCars() {
|
||||
return cars;
|
||||
}
|
||||
|
||||
public void setCars(List<Car> 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;
|
||||
}
|
||||
}
|
|
@ -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 <stliu@hibernate.org>
|
||||
*/
|
||||
@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<Index> 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<Column> 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<Index> 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<Column> 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<Index> 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<Column> columnIterator = index.getColumnIterator();
|
||||
Column column = columnIterator.next();
|
||||
assertEquals( "characters_id", column.getName() );
|
||||
assertSame( collectionTable, index.getTable() );
|
||||
}
|
||||
|
||||
// @Test
|
||||
public void testTableGeneratorIndex(){
|
||||
//todo
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
package org.hibernate.test.annotations.index.jpa;
|
||||
|
||||
|
||||
import org.hibernate.testing.FailureExpectedWithNewMetamodel;
|
||||
|
||||
/**
|
||||
* @author Strong Liu <stliu@hibernate.org>
|
||||
*/
|
||||
@FailureExpectedWithNewMetamodel
|
||||
public class OrmXmlIndexTest extends AbstractJPAIndexTest {
|
||||
@Override
|
||||
protected String[] getXmlFiles() {
|
||||
return new String[] { "org/hibernate/test/annotations/index/jpa/orm-index.xml" };
|
||||
}
|
||||
}
|
|
@ -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 ) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<org.hibernate.mapping.Table> 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;
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -0,0 +1,67 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<entity-mappings xmlns="http://xmlns.jcp.org/xml/ns/persistence/orm"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
version="2.1" >
|
||||
<package>org.hibernate.test.annotations.index.jpa</package>
|
||||
<!--<access>FIELD</access>-->
|
||||
<entity class="Car">
|
||||
<table name="T_FATHER">
|
||||
<index unique="true" column-list="brand, producer"/>
|
||||
<index name="Car_idx" column-list="since DESC"/>
|
||||
</table>
|
||||
<secondary-table name="T_DEALER">
|
||||
<index column-list="dealer_name ASC, rate DESC"/>
|
||||
</secondary-table>
|
||||
<attributes>
|
||||
<id name="id">
|
||||
<generated-value strategy="AUTO"/>
|
||||
</id>
|
||||
<basic name="brand"/>
|
||||
<basic name="producer"/>
|
||||
<basic name="since"/>
|
||||
<many-to-many name="importers" mapped-by="cars">
|
||||
<cascade><cascade-all/></cascade>
|
||||
</many-to-many>
|
||||
<element-collection name="otherDealers">
|
||||
<collection-table name="CAR_DEALTERS">
|
||||
<index column-list="name"/>
|
||||
</collection-table>
|
||||
</element-collection>
|
||||
<embedded name="dealer">
|
||||
<attribute-override name="name">
|
||||
<column name="dealer_name" table="T_DEALER"/>
|
||||
</attribute-override>
|
||||
<attribute-override name="rate">
|
||||
<column table="T_DEALER"/>
|
||||
</attribute-override>
|
||||
</embedded>
|
||||
|
||||
|
||||
</attributes>
|
||||
</entity>
|
||||
|
||||
<entity class="Importer">
|
||||
<attributes>
|
||||
<id name="id"/>
|
||||
<basic name="name"/>
|
||||
<many-to-many name="cars">
|
||||
<join-table name="CAR_IMPORTER">
|
||||
<index column-list="importers_id"/>
|
||||
</join-table>
|
||||
<cascade><cascade-all/></cascade>
|
||||
</many-to-many>
|
||||
</attributes>
|
||||
</entity>
|
||||
|
||||
<embeddable class="Dealer">
|
||||
<attributes>
|
||||
<basic name="name"/>
|
||||
<basic name="rate"/>
|
||||
</attributes>
|
||||
</embeddable>
|
||||
|
||||
</entity-mappings>
|
||||
|
||||
|
||||
|
|
@ -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 );
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
}
|
||||
|
|
|
@ -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 <code>jarPath</code> 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<byte[]> data = new LinkedList<byte[]>();
|
||||
int bufferSize = 4096;
|
|
@ -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 );
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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 );
|
||||
}
|
||||
}
|
|
@ -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 );
|
||||
}
|
||||
}
|
|
@ -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 );
|
||||
}
|
||||
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
public URL getJarURLFromURLEntry(URL url, String entry) throws IllegalArgumentException;
|
||||
public URL getURLFromPath(String jarPath);
|
||||
}
|
|
@ -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();
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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 );
|
||||
}
|
||||
}
|
||||
|
||||
public ArchiveException(String message, Throwable root) {
|
||||
super( message, root );
|
||||
}
|
||||
}
|
|
@ -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() );
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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<String> 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<ClassDescriptor> getClassDescriptors();
|
||||
public Iterable<PackageDescriptor> getPackageDescriptors();
|
||||
public Iterable<MappingFileDescriptor> getMappingFileDescriptors();
|
||||
}
|
||||
|
||||
private DeploymentResources buildDeploymentResources(
|
||||
ScanResult scanResult,
|
||||
BootstrapServiceRegistry bootstrapServiceRegistry) {
|
||||
|
||||
// mapping files ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
final ArrayList<MappingFileDescriptor> mappingFileDescriptors = new ArrayList<MappingFileDescriptor>();
|
||||
|
||||
final Set<String> nonLocatedMappingFileNames = new HashSet<String>();
|
||||
final List<String> 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<String, ClassDescriptor> classDescriptorMap = new HashMap<String, ClassDescriptor>();
|
||||
final HashMap<String, PackageDescriptor> packageDescriptorMap = new HashMap<String, PackageDescriptor>();
|
||||
|
||||
for ( ClassDescriptor classDescriptor : scanResult.getLocatedClasses() ) {
|
||||
classDescriptorMap.put( classDescriptor.getName(), classDescriptor );
|
||||
}
|
||||
|
||||
for ( PackageDescriptor packageDescriptor : scanResult.getLocatedPackages() ) {
|
||||
packageDescriptorMap.put( packageDescriptor.getName(), packageDescriptor );
|
||||
}
|
||||
|
||||
final List<String> 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<ClassDescriptor> getClassDescriptors() {
|
||||
return classDescriptorMap.values();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterable<PackageDescriptor> getPackageDescriptors() {
|
||||
return packageDescriptorMap.values();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterable<MappingFileDescriptor> 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<String> explicitOrmXml = (List<String>) 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<String> 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<String> explicitOrmXml = (List<String>) configurationValues.remove( AvailableSettings.XML_FILE_NAMES );
|
||||
if ( explicitOrmXml != null ) {
|
||||
metadataSources.mappingFileResources.addAll( explicitOrmXml );
|
||||
}
|
||||
|
||||
return metadataSources;
|
||||
}
|
||||
|
||||
private Set<String> collectManagedClassNames(ScanResult scanResult) {
|
||||
Set<String> collectedNames = new HashSet<String>();
|
||||
if ( persistenceUnit.getManagedClassNames() != null ) {
|
||||
collectedNames.addAll( persistenceUnit.getManagedClassNames() );
|
||||
}
|
||||
collectedNames.addAll( scanResult.getManagedClassNames() );
|
||||
return collectedNames;
|
||||
}
|
||||
|
||||
private IndexView locateOrBuildJandexIndex(
|
||||
Set<String> collectedManagedClassNames,
|
||||
List<String> 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<String> classNamesSource, List<String> 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<Package> matchingPackages = scanner.getPackagesInJar( scanningContext.url, new HashSet<Class<? extends Annotation>>(0) );
|
||||
for ( Package pkg : matchingPackages ) {
|
||||
scanResult.getPackageNames().add( pkg.getName() );
|
||||
}
|
||||
|
||||
Set<Class<? extends Annotation>> annotationsToLookFor = new HashSet<Class<? extends Annotation>>();
|
||||
annotationsToLookFor.add( Entity.class );
|
||||
annotationsToLookFor.add( MappedSuperclass.class );
|
||||
annotationsToLookFor.add( Embeddable.class );
|
||||
annotationsToLookFor.add( Converter.class );
|
||||
Set<Class<?>> matchingClasses = scanner.getClassesInJar( scanningContext.url, annotationsToLookFor );
|
||||
for ( Class<?> clazz : matchingClasses ) {
|
||||
scanResult.getManagedClassNames().add( clazz.getName() );
|
||||
}
|
||||
}
|
||||
|
||||
Set<String> patterns = new HashSet<String>();
|
||||
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<NamedInputStream> 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<String> managedClassNames = new ArrayList<String>();
|
||||
private final List<String> packageNames = new ArrayList<String>();
|
||||
private final List<NamedInputStream> hbmFiles = new ArrayList<NamedInputStream>();
|
||||
private final List<String> mappingFiles = new ArrayList<String>();
|
||||
public static class JaccDefinition {
|
||||
public final String contextId;
|
||||
public final String role;
|
||||
public final String clazz;
|
||||
public final String actions;
|
||||
|
||||
public List<String> getManagedClassNames() {
|
||||
return managedClassNames;
|
||||
}
|
||||
|
||||
public List<String> getPackageNames() {
|
||||
return packageNames;
|
||||
}
|
||||
|
||||
public List<NamedInputStream> getHbmFiles() {
|
||||
return hbmFiles;
|
||||
}
|
||||
|
||||
public List<String> 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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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() );
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
// }
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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 );
|
||||
|
|
|
@ -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() );
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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 );
|
||||
}
|
||||
}
|
|
@ -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:<ul>
|
||||
* <li>explicitly listed in a {@code <class/>} entry within the {@code <persistence-unit/>}</li>
|
||||
* <li>whether the scan options indicate that we are allowed to detect this entry</li>
|
||||
* </ul>
|
||||
*
|
||||
* @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 );
|
||||
}
|
||||
}
|
|
@ -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<URL, ArchiveDescriptorInfo> archiveDescriptorCache = new HashMap<URL, ArchiveDescriptorInfo>();
|
||||
|
||||
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<PackageDescriptor> packageDescriptorSet = new HashSet<PackageDescriptor>();
|
||||
private final Set<ClassDescriptor> classDescriptorSet = new HashSet<ClassDescriptor>();
|
||||
private final Set<MappingFileDescriptor> mappingFileSet = new HashSet<MappingFileDescriptor>();
|
||||
|
||||
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<PackageDescriptor> getPackageDescriptorSet() {
|
||||
return packageDescriptorSet;
|
||||
}
|
||||
|
||||
public Set<ClassDescriptor> getClassDescriptorSet() {
|
||||
return classDescriptorSet;
|
||||
}
|
||||
|
||||
public Set<MappingFileDescriptor> 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<PackageDescriptor> packageDescriptorSet;
|
||||
private final Set<ClassDescriptor> classDescriptorSet;
|
||||
private final Set<MappingFileDescriptor> mappingFileSet;
|
||||
|
||||
private ScanResultImpl(
|
||||
Set<PackageDescriptor> packageDescriptorSet,
|
||||
Set<ClassDescriptor> classDescriptorSet,
|
||||
Set<MappingFileDescriptor> 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<PackageDescriptor> getLocatedPackages() {
|
||||
return packageDescriptorSet;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<ClassDescriptor> getLocatedClasses() {
|
||||
return classDescriptorSet;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<MappingFileDescriptor> getLocatedMappingFiles() {
|
||||
return mappingFileSet;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -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 );
|
||||
}
|
||||
}
|
|
@ -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() );
|
||||
}
|
||||
}
|
|
@ -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 );
|
||||
}
|
||||
}
|
|
@ -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 );
|
||||
}
|
||||
}
|
||||
public interface ScanOptions {
|
||||
public boolean canDetectUnlistedClassesInRoot();
|
||||
public boolean canDetectUnlistedClassesInNonRoot();
|
||||
|
||||
public boolean canDetectHibernateMappingFiles();
|
||||
}
|
|
@ -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<PackageDescriptor> getLocatedPackages();
|
||||
public Set<ClassDescriptor> getLocatedClasses();
|
||||
public Set<MappingFileDescriptor> getLocatedMappingFiles();
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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();
|
||||
}
|
|
@ -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();
|
||||
}
|
|
@ -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();
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
|
@ -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<Filter> filters = new ArrayList<Filter>();
|
||||
private Set<FileFilter> fileFilters = new HashSet<FileFilter>();
|
||||
private Set<JavaElementFilter> classFilters = new HashSet<JavaElementFilter>();
|
||||
private Set<JavaElementFilter> packageFilters = new HashSet<JavaElementFilter>();
|
||||
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<Entry>();
|
||||
}
|
||||
}
|
||||
|
||||
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<JavaElementFilter> 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;
|
||||
}
|
||||
}
|
|
@ -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() );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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 ) )
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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<URL, StateJarVisitor> visitors = new HashMap<URL, StateJarVisitor>();
|
||||
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<Package> getPackagesInJar(URL jarToScan, Set<Class<? extends Annotation>> annotationsToLookFor) {
|
||||
if ( annotationsToLookFor.size() > 0 ) {
|
||||
throw new AssertionFailure( "Improper use of NativeScanner: must not filter packages" );
|
||||
}
|
||||
|
||||
JarVisitor jarVisitor = getVisitor( jarToScan );
|
||||
final Set<Entry> packageEntries;
|
||||
try {
|
||||
packageEntries = ( Set<Entry> ) jarVisitor.getMatchingEntries()[PACKAGE_FILTER_INDEX];
|
||||
}
|
||||
catch ( IOException e ) {
|
||||
throw new RuntimeException( "Error while reading " + jarToScan.toString(), e );
|
||||
}
|
||||
Set<Package> packages = new HashSet<Package>( 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<Class<?>> getClassesInJar(URL jarToScan, Set<Class<? extends Annotation>> 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<Entry> classesEntry;
|
||||
try {
|
||||
classesEntry = ( Set<Entry> ) jarVisitor.getMatchingEntries()[CLASS_FILTER_INDEX];
|
||||
}
|
||||
catch ( IOException e ) {
|
||||
throw new RuntimeException( "Error while reading " + jarToScan.toString(), e );
|
||||
}
|
||||
Set<Class<?>> classes = new HashSet<Class<?>>( 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<Class<? extends Annotation>> 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<NamedInputStream> getFilesInJar(URL jarToScan, Set<String> 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<String> endWiths = new HashSet<String>();
|
||||
Set<String> exacts = new HashSet<String>();
|
||||
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<Entry> fileEntries;
|
||||
try {
|
||||
fileEntries = ( Set<Entry> ) jarVisitor.getMatchingEntries()[FILE_FILTER_INDEX];
|
||||
}
|
||||
catch ( IOException e ) {
|
||||
throw new RuntimeException( "Error while reading " + jarToScan.toString(), e );
|
||||
}
|
||||
Set<NamedInputStream> files = new HashSet<NamedInputStream>( fileEntries.size() );
|
||||
Set<Entry> leftOver = new HashSet<Entry>( 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<NamedInputStream> getFilesInClasspath(Set<String> 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;
|
||||
}
|
||||
}
|
|
@ -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<Package> getPackagesInJar(URL jartoScan, Set<Class<? extends Annotation>> annotationsToLookFor);
|
||||
|
||||
/**
|
||||
* return all classes in the jar matching one of these annotations
|
||||
* if annotationsToLookFor is empty, return all classes
|
||||
*/
|
||||
Set<Class<?>> getClassesInJar(URL jartoScan, Set<Class<? extends Annotation>> 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<NamedInputStream> getFilesInJar(URL jartoScan, Set<String> 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<NamedInputStream> getFilesInClasspath(Set<String> filePatterns);
|
||||
|
||||
/**
|
||||
* return the unqualified JAR name ie customer-model.jar or store.war
|
||||
*/
|
||||
String getUnqualifiedJarName(URL jarUrl);
|
||||
|
||||
}
|
|
@ -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 );
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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<Package> getPackagesInJar(URL jartoScan, Set<Class<? extends Annotation>> annotationsToLookFor) {
|
||||
@Override
|
||||
public ScanResult scan(PersistenceUnitDescriptor persistenceUnit, ScanOptions options) {
|
||||
isUsed = true;
|
||||
return scanner.getPackagesInJar( jartoScan, annotationsToLookFor );
|
||||
}
|
||||
|
||||
public Set<Class<?>> getClassesInJar(URL jartoScan, Set<Class<? extends Annotation>> annotationsToLookFor) {
|
||||
isUsed = true;
|
||||
return scanner.getClassesInJar( jartoScan, annotationsToLookFor );
|
||||
}
|
||||
|
||||
public Set<NamedInputStream> getFilesInJar(URL jartoScan, Set<String> filePatterns) {
|
||||
isUsed = true;
|
||||
return scanner.getFilesInJar( jartoScan, filePatterns );
|
||||
}
|
||||
|
||||
public Set<NamedInputStream> getFilesInClasspath(Set<String> filePatterns) {
|
||||
isUsed = true;
|
||||
return scanner.getFilesInClasspath( filePatterns );
|
||||
}
|
||||
|
||||
public String getUnqualifiedJarName(URL jarUrl) {
|
||||
isUsed = true;
|
||||
return scanner.getUnqualifiedJarName( jarUrl );
|
||||
return delegate.scan( persistenceUnit, options );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<Entry> ) 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<Entry> ) 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<Entry> ) 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<Entry> ) 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<Entry> ) 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<Entry> ) 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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 );
|
||||
|
|
|
@ -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<Class<? extends Annotation>> annotationsToLookFor = new HashSet<Class<? extends Annotation>>( 3 );
|
||||
annotationsToLookFor.add( Entity.class );
|
||||
annotationsToLookFor.add( MappedSuperclass.class );
|
||||
annotationsToLookFor.add( Embeddable.class );
|
||||
annotationsToLookFor.add( Converter.class );
|
||||
final Set<Class<?>> 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<String> filePatterns = new HashSet<String>( 2 );
|
||||
filePatterns.add( "**/*.hbm.xml" );
|
||||
filePatterns.add( "META-INF/orm.xml" );
|
||||
final Set<NamedInputStream> 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();
|
||||
|
|
|
@ -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).
|
||||
|
|
|
@ -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 );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<StrTestEntity> references = new HashSet<StrTestEntity>();
|
||||
|
||||
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<StrTestEntity> getReferences() {
|
||||
return references;
|
||||
}
|
||||
|
||||
public void setReferences(Set<StrTestEntity> references) {
|
||||
this.references = references;
|
||||
}
|
||||
|
||||
public String getData() {
|
||||
return data;
|
||||
}
|
||||
|
||||
public void setData(String data) {
|
||||
this.data = data;
|
||||
}
|
||||
}
|
|
@ -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<StrTestEntity>() );
|
||||
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<StrTestEntity>() );
|
||||
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() );
|
||||
}
|
||||
}
|
|
@ -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',
|
||||
|
||||
|
|
Loading…
Reference in New Issue