EJB-428 move scanning facility under the Scanner interface and implement NativeScanner
git-svn-id: https://svn.jboss.org/repos/hibernate/core/trunk@16358 1b8cb986-b30d-0410-93ca-fae66ebed9b2
This commit is contained in:
parent
b26b4dc46c
commit
70362709f6
|
@ -21,6 +21,8 @@ import java.util.Map;
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.StringTokenizer;
|
import java.util.StringTokenizer;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.lang.annotation.Annotation;
|
||||||
import javax.naming.BinaryRefAddr;
|
import javax.naming.BinaryRefAddr;
|
||||||
import javax.naming.NamingException;
|
import javax.naming.NamingException;
|
||||||
import javax.naming.Reference;
|
import javax.naming.Reference;
|
||||||
|
@ -52,16 +54,12 @@ import org.hibernate.cfg.SettingsFactory;
|
||||||
import org.hibernate.cfg.annotations.reflection.XMLContext;
|
import org.hibernate.cfg.annotations.reflection.XMLContext;
|
||||||
import org.hibernate.ejb.connection.InjectedDataSourceConnectionProvider;
|
import org.hibernate.ejb.connection.InjectedDataSourceConnectionProvider;
|
||||||
import org.hibernate.ejb.instrument.InterceptFieldClassFileTransformer;
|
import org.hibernate.ejb.instrument.InterceptFieldClassFileTransformer;
|
||||||
import org.hibernate.ejb.packaging.JarVisitor;
|
|
||||||
import org.hibernate.ejb.packaging.NamedInputStream;
|
import org.hibernate.ejb.packaging.NamedInputStream;
|
||||||
import org.hibernate.ejb.packaging.PersistenceMetadata;
|
import org.hibernate.ejb.packaging.PersistenceMetadata;
|
||||||
import org.hibernate.ejb.packaging.PersistenceXmlLoader;
|
import org.hibernate.ejb.packaging.PersistenceXmlLoader;
|
||||||
import org.hibernate.ejb.packaging.Filter;
|
|
||||||
import org.hibernate.ejb.packaging.JarVisitorFactory;
|
import org.hibernate.ejb.packaging.JarVisitorFactory;
|
||||||
import org.hibernate.ejb.packaging.Entry;
|
import org.hibernate.ejb.packaging.Scanner;
|
||||||
import org.hibernate.ejb.packaging.FileFilter;
|
import org.hibernate.ejb.packaging.NativeScanner;
|
||||||
import org.hibernate.ejb.packaging.PackageFilter;
|
|
||||||
import org.hibernate.ejb.packaging.ClassFilter;
|
|
||||||
import org.hibernate.ejb.transaction.JoinableCMTTransactionFactory;
|
import org.hibernate.ejb.transaction.JoinableCMTTransactionFactory;
|
||||||
import org.hibernate.ejb.util.ConfigurationHelper;
|
import org.hibernate.ejb.util.ConfigurationHelper;
|
||||||
import org.hibernate.ejb.util.LogHelper;
|
import org.hibernate.ejb.util.LogHelper;
|
||||||
|
@ -232,23 +230,41 @@ public class Ejb3Configuration implements Serializable, Referenceable {
|
||||||
) ) {
|
) ) {
|
||||||
//correct provider
|
//correct provider
|
||||||
|
|
||||||
//lazy compute the visitor if possible to avoid useless exceptions if an unexpected state happens
|
//lazy load the scanner to avoid unnecessary IOExceptions
|
||||||
JarVisitor visitor = null;
|
Scanner scanner = null;
|
||||||
|
URL jarURL = null;
|
||||||
if ( metadata.getName() == null ) {
|
if ( metadata.getName() == null ) {
|
||||||
visitor = getMainJarVisitor( url, metadata, integration );
|
scanner = buildScanner();
|
||||||
metadata.setName( visitor.getUnqualifiedJarName() );
|
jarURL = JarVisitorFactory.getJarURLFromURLEntry( url, "/META-INF/persistence.xml" );
|
||||||
|
metadata.setName( scanner.getUnqualifiedJarName(jarURL) );
|
||||||
}
|
}
|
||||||
if ( persistenceUnitName == null && xmls.hasMoreElements() ) {
|
if ( persistenceUnitName == null && xmls.hasMoreElements() ) {
|
||||||
throw new PersistenceException( "No name provided and several persistence units found" );
|
throw new PersistenceException( "No name provided and several persistence units found" );
|
||||||
}
|
}
|
||||||
else if ( persistenceUnitName == null || metadata.getName().equals( persistenceUnitName ) ) {
|
else if ( persistenceUnitName == null || metadata.getName().equals( persistenceUnitName ) ) {
|
||||||
if (visitor == null) visitor = getMainJarVisitor( url, metadata, integration );
|
if (scanner == null) {
|
||||||
addMetadataFromVisitor( visitor, metadata );
|
scanner = buildScanner();
|
||||||
Filter[] otherXmlFilter = getFilters( metadata, integration, false );
|
jarURL = JarVisitorFactory.getJarURLFromURLEntry( url, "/META-INF/persistence.xml" );
|
||||||
|
}
|
||||||
|
//scan main JAR
|
||||||
|
ScanningContext mainJarScanCtx = new ScanningContext()
|
||||||
|
.scanner( scanner )
|
||||||
|
.url( jarURL )
|
||||||
|
.explicitMappingFiles( metadata.getMappingFiles() )
|
||||||
|
.searchOrm( true );
|
||||||
|
setDetectedArtifactsOnScanningContext( mainJarScanCtx, metadata.getProps(), integration,
|
||||||
|
metadata.getExcludeUnlistedClasses() );
|
||||||
|
addMetadataFromScan( mainJarScanCtx, metadata );
|
||||||
|
|
||||||
|
ScanningContext otherJarScanCtx = new ScanningContext()
|
||||||
|
.scanner( scanner )
|
||||||
|
.explicitMappingFiles( metadata.getMappingFiles() )
|
||||||
|
.searchOrm( true );
|
||||||
|
setDetectedArtifactsOnScanningContext( otherJarScanCtx, metadata.getProps(), integration,
|
||||||
|
false );
|
||||||
for ( String jarFile : metadata.getJarFiles() ) {
|
for ( String jarFile : metadata.getJarFiles() ) {
|
||||||
visitor = JarVisitorFactory.getVisitor( jarFile, otherXmlFilter );
|
otherJarScanCtx.url( JarVisitorFactory.getURLFromPath( jarFile ) );
|
||||||
addMetadataFromVisitor( visitor, metadata );
|
addMetadataFromScan( otherJarScanCtx, metadata );
|
||||||
}
|
}
|
||||||
return configure( metadata, integration );
|
return configure( metadata, integration );
|
||||||
}
|
}
|
||||||
|
@ -267,38 +283,88 @@ public class Ejb3Configuration implements Serializable, Referenceable {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//method used in a non managed environment
|
private NativeScanner buildScanner() {
|
||||||
private JarVisitor getMainJarVisitor(URL url, PersistenceMetadata metadata, Map integration) {
|
return new NativeScanner();
|
||||||
URL jarURL = JarVisitorFactory.getJarURLFromURLEntry( url, "/META-INF/persistence.xml" );
|
|
||||||
Filter[] persistenceXmlFilter = getFilters( metadata, integration, metadata.getExcludeUnlistedClasses() );
|
|
||||||
return JarVisitorFactory.getVisitor( jarURL, persistenceXmlFilter );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void addMetadataFromVisitor(JarVisitor visitor, PersistenceMetadata metadata) throws IOException {
|
private static class ScanningContext {
|
||||||
|
//boolean excludeUnlistedClasses;
|
||||||
|
private Scanner scanner;
|
||||||
|
private URL url;
|
||||||
|
private List<String> explicitMappingFiles;
|
||||||
|
private boolean detectClasses;
|
||||||
|
private boolean detectHbmFiles;
|
||||||
|
private boolean searchOrm;
|
||||||
|
|
||||||
|
public ScanningContext scanner(Scanner scanner) {
|
||||||
|
this.scanner = scanner;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ScanningContext url(URL url) {
|
||||||
|
this.url = url;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ScanningContext explicitMappingFiles(List<String> explicitMappingFiles) {
|
||||||
|
this.explicitMappingFiles = explicitMappingFiles;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ScanningContext detectClasses(boolean detectClasses) {
|
||||||
|
this.detectClasses = detectClasses;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ScanningContext detectHbmFiles(boolean detectHbmFiles) {
|
||||||
|
this.detectHbmFiles = detectHbmFiles;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ScanningContext searchOrm(boolean searchOrm) {
|
||||||
|
this.searchOrm = searchOrm;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void addMetadataFromScan(ScanningContext scanningContext, PersistenceMetadata metadata) throws IOException {
|
||||||
List<String> classes = metadata.getClasses();
|
List<String> classes = metadata.getClasses();
|
||||||
List<String> packages = metadata.getPackages();
|
List<String> packages = metadata.getPackages();
|
||||||
List<NamedInputStream> hbmFiles = metadata.getHbmfiles();
|
List<NamedInputStream> hbmFiles = metadata.getHbmfiles();
|
||||||
List<String> mappingFiles = metadata.getMappingFiles();
|
List<String> mappingFiles = metadata.getMappingFiles();
|
||||||
addScannedEntries( visitor, classes, packages, hbmFiles, mappingFiles );
|
addScannedEntries( scanningContext, classes, packages, hbmFiles, mappingFiles );
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void addScannedEntries(JarVisitor visitor, List<String> classes, List<String> packages, List<NamedInputStream> hbmFiles, List<String> mappingFiles) throws IOException {
|
private static void addScannedEntries(ScanningContext scanningContext, List<String> classes, List<String> packages, List<NamedInputStream> hbmFiles, List<String> mappingFiles) throws IOException {
|
||||||
Filter[] filters = visitor.getFilters();
|
Scanner scanner = scanningContext.scanner;
|
||||||
Set[] entries = visitor.getMatchingEntries();
|
if (scanningContext.detectClasses) {
|
||||||
int size = filters.length;
|
Set<Class<? extends Annotation>> annotationsToExclude = new HashSet<Class<? extends Annotation>>(3);
|
||||||
for ( int index = 0; index < size ; index++ ) {
|
annotationsToExclude.add( Entity.class );
|
||||||
for (Object o : entries[index]) {
|
annotationsToExclude.add( MappedSuperclass.class );
|
||||||
Entry entry = (Entry) o;
|
annotationsToExclude.add( Embeddable.class );
|
||||||
if ( filters[index] instanceof ClassFilter ) {
|
Set<Class<?>> matchingClasses = scanner.getClassesInJar( scanningContext.url, annotationsToExclude );
|
||||||
classes.add( entry.getName() );
|
for (Class<?> clazz : matchingClasses) {
|
||||||
}
|
classes.add( clazz.getName() );
|
||||||
else if ( filters[index] instanceof PackageFilter ) {
|
}
|
||||||
packages.add( entry.getName() );
|
|
||||||
}
|
Set<Package> matchingPackages = scanner.getPackagesInJar( scanningContext.url, new HashSet<Class<? extends Annotation>>(0) );
|
||||||
else if ( filters[index] instanceof FileFilter ) {
|
for (Package pkg : matchingPackages) {
|
||||||
hbmFiles.add( new NamedInputStream( entry.getName(), entry.getInputStream() ) );
|
packages.add( pkg.getName() );
|
||||||
if (mappingFiles != null) mappingFiles.remove( entry.getName() );
|
}
|
||||||
}
|
}
|
||||||
|
Set<String> patterns = new HashSet<String>();
|
||||||
|
if (scanningContext.searchOrm) {
|
||||||
|
patterns.add( META_INF_ORM_XML );
|
||||||
|
}
|
||||||
|
if (scanningContext.detectHbmFiles) {
|
||||||
|
patterns.add( "**/*.hbm.xml" );
|
||||||
|
}
|
||||||
|
if ( mappingFiles != null) patterns.addAll( mappingFiles );
|
||||||
|
if (patterns.size() !=0) {
|
||||||
|
Set<NamedInputStream> files = scanner.getFilesInJar( scanningContext.url, patterns );
|
||||||
|
for (NamedInputStream file : files) {
|
||||||
|
hbmFiles.add( file );
|
||||||
|
if (mappingFiles != null) mappingFiles.remove( file.getName() );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -352,12 +418,22 @@ public class Ejb3Configuration implements Serializable, Referenceable {
|
||||||
//Should always be true if the container is not dump
|
//Should always be true if the container is not dump
|
||||||
boolean searchForORMFiles = ! xmlFiles.contains( META_INF_ORM_XML );
|
boolean searchForORMFiles = ! xmlFiles.contains( META_INF_ORM_XML );
|
||||||
|
|
||||||
boolean[] detectArtifactForOtherJars = getDetectedArtifacts( info.getProperties(), null, false );
|
ScanningContext context = new ScanningContext();
|
||||||
boolean[] detectArtifactForMainJar = getDetectedArtifacts( info.getProperties(), null, info.excludeUnlistedClasses() );
|
context.scanner( buildScanner() )
|
||||||
|
.searchOrm( searchForORMFiles )
|
||||||
|
.explicitMappingFiles( null ); //URLs provided by the container already
|
||||||
|
|
||||||
|
//context for other JARs
|
||||||
|
setDetectedArtifactsOnScanningContext(context, info.getProperties(), null, false );
|
||||||
for ( URL jar : info.getJarFileUrls() ) {
|
for ( URL jar : info.getJarFileUrls() ) {
|
||||||
scanForClasses( jar, packages, entities, hbmFiles, detectArtifactForOtherJars, searchForORMFiles );
|
context.url(jar);
|
||||||
|
scanForClasses( context, packages, entities, hbmFiles );
|
||||||
}
|
}
|
||||||
scanForClasses( info.getPersistenceUnitRootUrl(), packages, entities, hbmFiles, detectArtifactForMainJar, searchForORMFiles );
|
|
||||||
|
//main jar
|
||||||
|
context.url( info.getPersistenceUnitRootUrl() );
|
||||||
|
setDetectedArtifactsOnScanningContext( context, info.getProperties(), null, info.excludeUnlistedClasses() );
|
||||||
|
scanForClasses( context, packages, entities, hbmFiles );
|
||||||
|
|
||||||
Properties properties = info.getProperties() != null ?
|
Properties properties = info.getProperties() != null ?
|
||||||
info.getProperties() :
|
info.getProperties() :
|
||||||
|
@ -536,88 +612,54 @@ public class Ejb3Configuration implements Serializable, Referenceable {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean[] getDetectedArtifacts(Properties properties, Map overridenProperties, boolean excludeIfNotOverriden) {
|
/**
|
||||||
boolean[] result = new boolean[2];
|
* Set ScanningContext detectClasses and detectHbmFiles according to context
|
||||||
result[0] = false; //detect classes
|
*/
|
||||||
result[1] = false; //detect hbm
|
private void setDetectedArtifactsOnScanningContext(ScanningContext context,
|
||||||
String detect = overridenProperties != null ?
|
Properties properties,
|
||||||
|
Map overridenProperties,
|
||||||
|
boolean excludeIfNotOverriden) {
|
||||||
|
|
||||||
|
boolean detectClasses = false;
|
||||||
|
boolean detectHbm = false;
|
||||||
|
String detectSetting = overridenProperties != null ?
|
||||||
(String) overridenProperties.get( HibernatePersistence.AUTODETECTION ) :
|
(String) overridenProperties.get( HibernatePersistence.AUTODETECTION ) :
|
||||||
null;
|
null;
|
||||||
detect = detect == null ?
|
detectSetting = detectSetting == null ?
|
||||||
properties.getProperty( HibernatePersistence.AUTODETECTION) :
|
properties.getProperty( HibernatePersistence.AUTODETECTION) :
|
||||||
detect;
|
detectSetting;
|
||||||
if (detect == null && excludeIfNotOverriden) {
|
if ( detectSetting == null && excludeIfNotOverriden) {
|
||||||
//not overriden through HibernatePersistence.AUTODETECTION so we comply with the spec excludeUnlistedClasses
|
//not overriden through HibernatePersistence.AUTODETECTION so we comply with the spec excludeUnlistedClasses
|
||||||
return result;
|
context.detectClasses( false ).detectHbmFiles( false );
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
else if (detect == null){
|
|
||||||
detect = "class,hbm";
|
if ( detectSetting == null){
|
||||||
|
detectSetting = "class,hbm";
|
||||||
}
|
}
|
||||||
StringTokenizer st = new StringTokenizer( detect, ", ", false );
|
StringTokenizer st = new StringTokenizer( detectSetting, ", ", false );
|
||||||
while ( st.hasMoreElements() ) {
|
while ( st.hasMoreElements() ) {
|
||||||
String element = (String) st.nextElement();
|
String element = (String) st.nextElement();
|
||||||
if ( "class".equalsIgnoreCase( element ) ) result[0] = true;
|
if ( "class".equalsIgnoreCase( element ) ) detectClasses = true;
|
||||||
if ( "hbm".equalsIgnoreCase( element ) ) result[1] = true;
|
if ( "hbm".equalsIgnoreCase( element ) ) detectHbm = true;
|
||||||
}
|
}
|
||||||
log.debug( "Detect class: {}; detect hbm: {}", result[0], result[1] );
|
log.debug( "Detect class: {}; detect hbm: {}", detectClasses, detectHbm );
|
||||||
return result;
|
context.detectClasses( detectClasses ).detectHbmFiles( detectHbm );
|
||||||
}
|
}
|
||||||
|
|
||||||
private Filter[] getFilters(PersistenceMetadata metadata, Map overridenProperties, boolean excludeIfNotOverriden) {
|
private void scanForClasses(ScanningContext scanningContext, List<String> packages, List<String> entities, List<NamedInputStream> hbmFiles) {
|
||||||
Properties properties = metadata.getProps();
|
if (scanningContext.url == null) {
|
||||||
final List<String> mappingFiles = metadata.getMappingFiles();
|
|
||||||
boolean[] detectedArtifacts = getDetectedArtifacts( properties, overridenProperties, excludeIfNotOverriden );
|
|
||||||
|
|
||||||
return getFilters( detectedArtifacts, true, mappingFiles );
|
|
||||||
}
|
|
||||||
|
|
||||||
private Filter[] getFilters(final boolean[] detectedArtifacts, final boolean searchORM, final List<String> mappingFiles) {
|
|
||||||
final int mappingFilesSize = mappingFiles != null ? mappingFiles.size() : 0;
|
|
||||||
int size = ( detectedArtifacts[0] ? 2 : 0 ) + ( (searchORM || detectedArtifacts[1] || mappingFilesSize > 0 ) ? 1 : 0);
|
|
||||||
Filter[] filters = new Filter[size];
|
|
||||||
if ( detectedArtifacts[0] ) {
|
|
||||||
filters[0] = new PackageFilter( false, null ) {
|
|
||||||
public boolean accept(String javaElementName) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
filters[1] = new ClassFilter(
|
|
||||||
false, new Class[]{
|
|
||||||
Entity.class,
|
|
||||||
MappedSuperclass.class,
|
|
||||||
Embeddable.class}
|
|
||||||
) {
|
|
||||||
public boolean accept(String javaElementName) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
if ( detectedArtifacts[1] || searchORM || mappingFilesSize > 0) {
|
|
||||||
filters[size - 1] = new FileFilter( true ) {
|
|
||||||
public boolean accept(String javaElementName) {
|
|
||||||
return ( detectedArtifacts[1] && javaElementName.endsWith( "hbm.xml" ) )
|
|
||||||
|| ( searchORM && javaElementName.endsWith( META_INF_ORM_XML ) )
|
|
||||||
|| ( mappingFilesSize > 0 && mappingFiles.contains( javaElementName ) );
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
return filters;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void scanForClasses(URL jar, List<String> packages, List<String> entities, List<NamedInputStream> hbmFiles, boolean[] detectedArtifacts, boolean searchORM) {
|
|
||||||
if (jar == null) {
|
|
||||||
log.error( "Container is providing a null PersistenceUnitRootUrl: discovery impossible");
|
log.error( "Container is providing a null PersistenceUnitRootUrl: discovery impossible");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
JarVisitor visitor = JarVisitorFactory.getVisitor( jar, getFilters( detectedArtifacts, searchORM, null ) );
|
addScannedEntries( scanningContext, entities, packages, hbmFiles, null );
|
||||||
addScannedEntries( visitor, entities, packages, hbmFiles, null );
|
|
||||||
}
|
}
|
||||||
catch (RuntimeException e) {
|
catch (RuntimeException e) {
|
||||||
throw new RuntimeException( "error trying to scan <jar-file>: " + jar.toString(), e );
|
throw new RuntimeException( "error trying to scan <jar-file>: " + scanningContext.url.toString(), e );
|
||||||
}
|
}
|
||||||
catch( IOException e ) {
|
catch( IOException e ) {
|
||||||
throw new RuntimeException( "Error while reading " + jar.toString(), e );
|
throw new RuntimeException( "Error while reading " + scanningContext.url.toString(), e );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -41,21 +41,7 @@ public abstract class AbstractJarVisitor implements JarVisitor {
|
||||||
* Build a jar visitor from its jar string path
|
* Build a jar visitor from its jar string path
|
||||||
*/
|
*/
|
||||||
private AbstractJarVisitor(String jarPath) {
|
private AbstractJarVisitor(String jarPath) {
|
||||||
URL jarUrl;
|
this.jarUrl = JarVisitorFactory.getURLFromPath( jarPath );
|
||||||
try {
|
|
||||||
//is it an url
|
|
||||||
jarUrl = new URL( jarPath );
|
|
||||||
}
|
|
||||||
catch (MalformedURLException e) {
|
|
||||||
try {
|
|
||||||
//consider it as a file path
|
|
||||||
jarUrl = new URL( "file:" + jarPath );
|
|
||||||
}
|
|
||||||
catch (MalformedURLException ee) {
|
|
||||||
throw new IllegalArgumentException( "Unable to find jar:" + jarPath, ee );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
this.jarUrl = jarUrl;
|
|
||||||
unqualify();
|
unqualify();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -26,6 +26,7 @@ public class JarVisitorFactory {
|
||||||
* @param entry file known to be in the JAR
|
* @param entry file known to be in the JAR
|
||||||
* @return the JAR URL
|
* @return the JAR URL
|
||||||
* @throws IllegalArgumentException if none URL is found
|
* @throws IllegalArgumentException if none URL is found
|
||||||
|
* TODO move to a ScannerHelper service?
|
||||||
*/
|
*/
|
||||||
public static URL getJarURLFromURLEntry(URL url, String entry) throws IllegalArgumentException {
|
public static URL getJarURLFromURLEntry(URL url, String entry) throws IllegalArgumentException {
|
||||||
URL jarUrl;
|
URL jarUrl;
|
||||||
|
@ -74,6 +75,30 @@ public class JarVisitorFactory {
|
||||||
return jarUrl;
|
return jarUrl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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;
|
||||||
|
try {
|
||||||
|
//is it an url
|
||||||
|
jarUrl = new URL( jarPath );
|
||||||
|
}
|
||||||
|
catch ( MalformedURLException e) {
|
||||||
|
try {
|
||||||
|
//consider it as a file path
|
||||||
|
jarUrl = new URL( "file:" + jarPath );
|
||||||
|
}
|
||||||
|
catch (MalformedURLException ee) {
|
||||||
|
throw new IllegalArgumentException( "Unable to find jar:" + jarPath, ee );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return jarUrl;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get a JarVisitor to the jar <code>jarPath</code> applying the given filters
|
* Get a JarVisitor to the jar <code>jarPath</code> applying the given filters
|
||||||
*
|
*
|
||||||
|
|
|
@ -0,0 +1,227 @@
|
||||||
|
package org.hibernate.ejb.packaging;
|
||||||
|
|
||||||
|
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.Embeddable;
|
||||||
|
import javax.persistence.Entity;
|
||||||
|
import javax.persistence.MappedSuperclass;
|
||||||
|
|
||||||
|
import org.hibernate.AssertionFailure;
|
||||||
|
import org.hibernate.util.ReflectHelper;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @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() != 3
|
||||||
|
|| !annotationsToLookFor.contains( Entity.class )
|
||||||
|
|| !annotationsToLookFor.contains( MappedSuperclass.class )
|
||||||
|
|| !annotationsToLookFor.contains( Embeddable.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" );
|
||||||
|
}
|
||||||
|
System.err.println(sb.toString());
|
||||||
|
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;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (done) continue;
|
||||||
|
for ( String endWithPattern : endWiths ) {
|
||||||
|
if ( entry.getName().endsWith( endWithPattern ) ) {
|
||||||
|
files.add( new NamedInputStream( entry.getName(), entry.getInputStream() ) );
|
||||||
|
leftOver.remove( entry );
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
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(URL jartoScan, 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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,45 @@
|
||||||
|
package org.hibernate.ejb.packaging;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.List;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.lang.annotation.Annotation;
|
||||||
|
import java.io.InputStream;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @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.
|
||||||
|
*/
|
||||||
|
Set<NamedInputStream> getFilesInClasspath(URL jartoScan, Set<String> filePatterns);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* return the unqualified JAR name ie customer-model.jar or store.war
|
||||||
|
*/
|
||||||
|
String getUnqualifiedJarName(URL jarUrl);
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,53 @@
|
||||||
|
package org.hibernate.ejb.test.packaging;
|
||||||
|
|
||||||
|
import java.lang.annotation.Annotation;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
import javax.persistence.Embeddable;
|
||||||
|
import javax.persistence.Entity;
|
||||||
|
import javax.persistence.MappedSuperclass;
|
||||||
|
|
||||||
|
import junit.framework.TestCase;
|
||||||
|
|
||||||
|
import org.hibernate.ejb.packaging.NamedInputStream;
|
||||||
|
import org.hibernate.ejb.packaging.NativeScanner;
|
||||||
|
import org.hibernate.ejb.packaging.Scanner;
|
||||||
|
import org.hibernate.ejb.test.pack.defaultpar.ApplicationServer;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Emmanuel Bernard
|
||||||
|
*/
|
||||||
|
public class NativeScannerTest extends TestCase {
|
||||||
|
private static final String jarFileBase = "file:./target/test-packages";
|
||||||
|
|
||||||
|
public void testNativeScanner() throws Exception {
|
||||||
|
String jarFileName = jarFileBase + "/defaultpar.par";
|
||||||
|
Scanner scanner = new NativeScanner();
|
||||||
|
|
||||||
|
final URL jarUrl = new URL( jarFileName );
|
||||||
|
assertEquals( "defaultpar", scanner.getUnqualifiedJarName( jarUrl ) );
|
||||||
|
|
||||||
|
Set<Class<? extends Annotation>> annotationsToLookFor = new HashSet<Class<? extends Annotation>>(3);
|
||||||
|
annotationsToLookFor.add( Entity.class );
|
||||||
|
annotationsToLookFor.add( MappedSuperclass.class );
|
||||||
|
annotationsToLookFor.add( Embeddable.class );
|
||||||
|
final Set<Class<?>> classes = scanner.getClassesInJar( jarUrl, annotationsToLookFor );
|
||||||
|
|
||||||
|
assertEquals( 3, classes.size() );
|
||||||
|
assertTrue( classes.contains( ApplicationServer.class ) );
|
||||||
|
assertTrue( classes.contains( org.hibernate.ejb.test.pack.defaultpar.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( jarUrl, filePatterns );
|
||||||
|
|
||||||
|
assertEquals( 2, files.size() );
|
||||||
|
for (NamedInputStream file : files ) {
|
||||||
|
assertNotNull( file.getStream() );
|
||||||
|
file.getStream().close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue