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:
Emmanuel Bernard 2009-04-18 14:35:58 +00:00
parent b26b4dc46c
commit 70362709f6
6 changed files with 500 additions and 122 deletions

View File

@ -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 );
} }
} }

View File

@ -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();
} }

View File

@ -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
* *

View File

@ -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;
}
}

View File

@ -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);
}

View File

@ -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();
}
}
}