From 70362709f688e46c10593956f3d0f76c33ce9c79 Mon Sep 17 00:00:00 2001 From: Emmanuel Bernard Date: Sat, 18 Apr 2009 14:35:58 +0000 Subject: [PATCH] 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 --- .../org/hibernate/ejb/Ejb3Configuration.java | 256 ++++++++++-------- .../ejb/packaging/AbstractJarVisitor.java | 16 +- .../ejb/packaging/JarVisitorFactory.java | 25 ++ .../ejb/packaging/NativeScanner.java | 227 ++++++++++++++++ .../org/hibernate/ejb/packaging/Scanner.java | 45 +++ .../ejb/test/packaging/NativeScannerTest.java | 53 ++++ 6 files changed, 500 insertions(+), 122 deletions(-) create mode 100644 entitymanager/src/main/java/org/hibernate/ejb/packaging/NativeScanner.java create mode 100644 entitymanager/src/main/java/org/hibernate/ejb/packaging/Scanner.java create mode 100644 entitymanager/src/test/java/org/hibernate/ejb/test/packaging/NativeScannerTest.java diff --git a/entitymanager/src/main/java/org/hibernate/ejb/Ejb3Configuration.java b/entitymanager/src/main/java/org/hibernate/ejb/Ejb3Configuration.java index 06487cbc7b..b9e1f64143 100644 --- a/entitymanager/src/main/java/org/hibernate/ejb/Ejb3Configuration.java +++ b/entitymanager/src/main/java/org/hibernate/ejb/Ejb3Configuration.java @@ -21,6 +21,8 @@ import java.util.Map; import java.util.Properties; import java.util.Set; import java.util.StringTokenizer; +import java.util.HashSet; +import java.lang.annotation.Annotation; import javax.naming.BinaryRefAddr; import javax.naming.NamingException; import javax.naming.Reference; @@ -52,16 +54,12 @@ import org.hibernate.cfg.SettingsFactory; import org.hibernate.cfg.annotations.reflection.XMLContext; import org.hibernate.ejb.connection.InjectedDataSourceConnectionProvider; import org.hibernate.ejb.instrument.InterceptFieldClassFileTransformer; -import org.hibernate.ejb.packaging.JarVisitor; import org.hibernate.ejb.packaging.NamedInputStream; import org.hibernate.ejb.packaging.PersistenceMetadata; import org.hibernate.ejb.packaging.PersistenceXmlLoader; -import org.hibernate.ejb.packaging.Filter; import org.hibernate.ejb.packaging.JarVisitorFactory; -import org.hibernate.ejb.packaging.Entry; -import org.hibernate.ejb.packaging.FileFilter; -import org.hibernate.ejb.packaging.PackageFilter; -import org.hibernate.ejb.packaging.ClassFilter; +import org.hibernate.ejb.packaging.Scanner; +import org.hibernate.ejb.packaging.NativeScanner; import org.hibernate.ejb.transaction.JoinableCMTTransactionFactory; import org.hibernate.ejb.util.ConfigurationHelper; import org.hibernate.ejb.util.LogHelper; @@ -232,23 +230,41 @@ public class Ejb3Configuration implements Serializable, Referenceable { ) ) { //correct provider - //lazy compute the visitor if possible to avoid useless exceptions if an unexpected state happens - JarVisitor visitor = null; - + //lazy load the scanner to avoid unnecessary IOExceptions + Scanner scanner = null; + URL jarURL = null; if ( metadata.getName() == null ) { - visitor = getMainJarVisitor( url, metadata, integration ); - metadata.setName( visitor.getUnqualifiedJarName() ); + scanner = buildScanner(); + jarURL = JarVisitorFactory.getJarURLFromURLEntry( url, "/META-INF/persistence.xml" ); + metadata.setName( scanner.getUnqualifiedJarName(jarURL) ); } if ( persistenceUnitName == null && xmls.hasMoreElements() ) { throw new PersistenceException( "No name provided and several persistence units found" ); } else if ( persistenceUnitName == null || metadata.getName().equals( persistenceUnitName ) ) { - if (visitor == null) visitor = getMainJarVisitor( url, metadata, integration ); - addMetadataFromVisitor( visitor, metadata ); - Filter[] otherXmlFilter = getFilters( metadata, integration, false ); + if (scanner == null) { + scanner = buildScanner(); + 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() ) { - visitor = JarVisitorFactory.getVisitor( jarFile, otherXmlFilter ); - addMetadataFromVisitor( visitor, metadata ); + otherJarScanCtx.url( JarVisitorFactory.getURLFromPath( jarFile ) ); + addMetadataFromScan( otherJarScanCtx, metadata ); } return configure( metadata, integration ); } @@ -267,38 +283,88 @@ public class Ejb3Configuration implements Serializable, Referenceable { } } - //method used in a non managed environment - private JarVisitor getMainJarVisitor(URL url, PersistenceMetadata metadata, Map integration) { - URL jarURL = JarVisitorFactory.getJarURLFromURLEntry( url, "/META-INF/persistence.xml" ); - Filter[] persistenceXmlFilter = getFilters( metadata, integration, metadata.getExcludeUnlistedClasses() ); - return JarVisitorFactory.getVisitor( jarURL, persistenceXmlFilter ); + private NativeScanner buildScanner() { + return new NativeScanner(); } - private static void addMetadataFromVisitor(JarVisitor visitor, PersistenceMetadata metadata) throws IOException { + private static class ScanningContext { + //boolean excludeUnlistedClasses; + private Scanner scanner; + private URL url; + private List 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 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 classes = metadata.getClasses(); List packages = metadata.getPackages(); List hbmFiles = metadata.getHbmfiles(); List mappingFiles = metadata.getMappingFiles(); - addScannedEntries( visitor, classes, packages, hbmFiles, mappingFiles ); + addScannedEntries( scanningContext, classes, packages, hbmFiles, mappingFiles ); } - private static void addScannedEntries(JarVisitor visitor, List classes, List packages, List hbmFiles, List mappingFiles) throws IOException { - Filter[] filters = visitor.getFilters(); - Set[] entries = visitor.getMatchingEntries(); - int size = filters.length; - for ( int index = 0; index < size ; index++ ) { - for (Object o : entries[index]) { - Entry entry = (Entry) o; - if ( filters[index] instanceof ClassFilter ) { - classes.add( entry.getName() ); - } - else if ( filters[index] instanceof PackageFilter ) { - packages.add( entry.getName() ); - } - else if ( filters[index] instanceof FileFilter ) { - hbmFiles.add( new NamedInputStream( entry.getName(), entry.getInputStream() ) ); - if (mappingFiles != null) mappingFiles.remove( entry.getName() ); - } + private static void addScannedEntries(ScanningContext scanningContext, List classes, List packages, List hbmFiles, List mappingFiles) throws IOException { + Scanner scanner = scanningContext.scanner; + if (scanningContext.detectClasses) { + Set> annotationsToExclude = new HashSet>(3); + annotationsToExclude.add( Entity.class ); + annotationsToExclude.add( MappedSuperclass.class ); + annotationsToExclude.add( Embeddable.class ); + Set> matchingClasses = scanner.getClassesInJar( scanningContext.url, annotationsToExclude ); + for (Class clazz : matchingClasses) { + classes.add( clazz.getName() ); + } + + Set matchingPackages = scanner.getPackagesInJar( scanningContext.url, new HashSet>(0) ); + for (Package pkg : matchingPackages) { + packages.add( pkg.getName() ); + } + } + Set patterns = new HashSet(); + 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 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 boolean searchForORMFiles = ! xmlFiles.contains( META_INF_ORM_XML ); - boolean[] detectArtifactForOtherJars = getDetectedArtifacts( info.getProperties(), null, false ); - boolean[] detectArtifactForMainJar = getDetectedArtifacts( info.getProperties(), null, info.excludeUnlistedClasses() ); + ScanningContext context = new ScanningContext(); + 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() ) { - 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 ? info.getProperties() : @@ -536,88 +612,54 @@ public class Ejb3Configuration implements Serializable, Referenceable { return this; } - private boolean[] getDetectedArtifacts(Properties properties, Map overridenProperties, boolean excludeIfNotOverriden) { - boolean[] result = new boolean[2]; - result[0] = false; //detect classes - result[1] = false; //detect hbm - String detect = overridenProperties != null ? + /** + * Set ScanningContext detectClasses and detectHbmFiles according to context + */ + private void setDetectedArtifactsOnScanningContext(ScanningContext context, + Properties properties, + Map overridenProperties, + boolean excludeIfNotOverriden) { + + boolean detectClasses = false; + boolean detectHbm = false; + String detectSetting = overridenProperties != null ? (String) overridenProperties.get( HibernatePersistence.AUTODETECTION ) : null; - detect = detect == null ? + detectSetting = detectSetting == null ? properties.getProperty( HibernatePersistence.AUTODETECTION) : - detect; - if (detect == null && excludeIfNotOverriden) { + detectSetting; + if ( detectSetting == null && excludeIfNotOverriden) { //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() ) { String element = (String) st.nextElement(); - if ( "class".equalsIgnoreCase( element ) ) result[0] = true; - if ( "hbm".equalsIgnoreCase( element ) ) result[1] = true; + if ( "class".equalsIgnoreCase( element ) ) detectClasses = true; + if ( "hbm".equalsIgnoreCase( element ) ) detectHbm = true; } - log.debug( "Detect class: {}; detect hbm: {}", result[0], result[1] ); - return result; + log.debug( "Detect class: {}; detect hbm: {}", detectClasses, detectHbm ); + context.detectClasses( detectClasses ).detectHbmFiles( detectHbm ); } - private Filter[] getFilters(PersistenceMetadata metadata, Map overridenProperties, boolean excludeIfNotOverriden) { - Properties properties = metadata.getProps(); - final List 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 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 packages, List entities, List hbmFiles, boolean[] detectedArtifacts, boolean searchORM) { - if (jar == null) { + private void scanForClasses(ScanningContext scanningContext, List packages, List entities, List hbmFiles) { + if (scanningContext.url == null) { log.error( "Container is providing a null PersistenceUnitRootUrl: discovery impossible"); return; } try { - JarVisitor visitor = JarVisitorFactory.getVisitor( jar, getFilters( detectedArtifacts, searchORM, null ) ); - addScannedEntries( visitor, entities, packages, hbmFiles, null ); + addScannedEntries( scanningContext, entities, packages, hbmFiles, null ); } catch (RuntimeException e) { - throw new RuntimeException( "error trying to scan : " + jar.toString(), e ); + throw new RuntimeException( "error trying to scan : " + scanningContext.url.toString(), e ); } catch( IOException e ) { - throw new RuntimeException( "Error while reading " + jar.toString(), e ); + throw new RuntimeException( "Error while reading " + scanningContext.url.toString(), e ); } } diff --git a/entitymanager/src/main/java/org/hibernate/ejb/packaging/AbstractJarVisitor.java b/entitymanager/src/main/java/org/hibernate/ejb/packaging/AbstractJarVisitor.java index 9a83a1e0b5..626305dc22 100644 --- a/entitymanager/src/main/java/org/hibernate/ejb/packaging/AbstractJarVisitor.java +++ b/entitymanager/src/main/java/org/hibernate/ejb/packaging/AbstractJarVisitor.java @@ -41,21 +41,7 @@ public abstract class AbstractJarVisitor implements JarVisitor { * Build a jar visitor from its jar string path */ private AbstractJarVisitor(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 ); - } - } - this.jarUrl = jarUrl; + this.jarUrl = JarVisitorFactory.getURLFromPath( jarPath ); unqualify(); } diff --git a/entitymanager/src/main/java/org/hibernate/ejb/packaging/JarVisitorFactory.java b/entitymanager/src/main/java/org/hibernate/ejb/packaging/JarVisitorFactory.java index 48dcbff049..4d8299cbfb 100644 --- a/entitymanager/src/main/java/org/hibernate/ejb/packaging/JarVisitorFactory.java +++ b/entitymanager/src/main/java/org/hibernate/ejb/packaging/JarVisitorFactory.java @@ -26,6 +26,7 @@ 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; @@ -74,6 +75,30 @@ public class JarVisitorFactory { 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 jarPath applying the given filters * diff --git a/entitymanager/src/main/java/org/hibernate/ejb/packaging/NativeScanner.java b/entitymanager/src/main/java/org/hibernate/ejb/packaging/NativeScanner.java new file mode 100644 index 0000000000..d3a6ab547d --- /dev/null +++ b/entitymanager/src/main/java/org/hibernate/ejb/packaging/NativeScanner.java @@ -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 visitors = new HashMap(); + private static final int PACKAGE_FILTER_INDEX = 0; + private static final int CLASS_FILTER_INDEX = 1; + private static final int FILE_FILTER_INDEX = 2; + + /** + * This implementation does not honor the list of annotations and return everything. + * Must strictly be used by HEM + */ + public Set getPackagesInJar(URL jarToScan, Set> annotationsToLookFor) { + if ( annotationsToLookFor.size() > 0 ) { + throw new AssertionFailure( "Improper use of NativeScanner: must not filter packages" ); + } + + JarVisitor jarVisitor = getVisitor( jarToScan ); + final Set packageEntries; + try { + packageEntries = ( Set ) jarVisitor.getMatchingEntries()[PACKAGE_FILTER_INDEX]; + } + catch ( IOException e ) { + throw new RuntimeException( "Error while reading " + jarToScan.toString(), e ); + } + Set packages = new HashSet( packageEntries.size() ); + for ( Entry entry : packageEntries ) { + try { + packages.add( ReflectHelper.classForName( entry.getName() + ".package-info" ).getPackage() ); + } + catch ( ClassNotFoundException e ) { + //should never happen, if it happens, simply ignore the flawed package + } + } + return packages; + } + + /** + * Build a JarVisitor with some assumptions wrt the scanning + * This helps do one scan instead of several + */ + private JarVisitor getVisitor(URL jar) { + StateJarVisitor stateJarVisitor = visitors.get( jar ); + + if ( stateJarVisitor == null ) { + + Filter[] filters = new Filter[3]; + filters[PACKAGE_FILTER_INDEX] = new PackageFilter( false, null ) { + public boolean accept(String javaElementName) { + return true; + } + }; + filters[CLASS_FILTER_INDEX] = new ClassFilter( + false, new Class[] { + Entity.class, + MappedSuperclass.class, + Embeddable.class + } + ) { + public boolean accept(String javaElementName) { + return true; + } + }; + filters[FILE_FILTER_INDEX] = new FileFilter( true ) { + public boolean accept(String javaElementName) { + return javaElementName.endsWith( "hbm.xml" ) + || javaElementName.endsWith( META_INF_ORM_XML ); + } + }; + + stateJarVisitor = new StateJarVisitor( JarVisitorFactory.getVisitor( jar, filters ) ); + visitors.put( jar, stateJarVisitor ); + } + return stateJarVisitor.visitor; + } + + public Set> getClassesInJar(URL jarToScan, Set> annotationsToLookFor) { + if ( isValidForClasses( annotationsToLookFor ) ) { + throw new AssertionFailure( + "Improper use of NativeScanner: " + + "must not filter classes by other annotations than Entity, MappedSuperclass, embeddable" + ); + } + JarVisitor jarVisitor = getVisitor( jarToScan ); + final Set classesEntry; + try { + classesEntry = ( Set ) jarVisitor.getMatchingEntries()[CLASS_FILTER_INDEX]; + } + catch ( IOException e ) { + throw new RuntimeException( "Error while reading " + jarToScan.toString(), e ); + } + Set> classes = new HashSet>( classesEntry.size() ); + for ( Entry entry : classesEntry ) { + try { + classes.add( ReflectHelper.classForName( entry.getName() ) ); + } + catch ( ClassNotFoundException e ) { + //should never happen, if it happens, simply ignore the flawed package + } + } + return classes; + } + + private boolean isValidForClasses(Set> annotationsToLookFor) { + return annotationsToLookFor.size() != 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 getFilesInJar(URL jarToScan, Set 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 endWiths = new HashSet(); + Set exacts = new HashSet(); + for ( String pattern : filePatterns ) { + if ( pattern.startsWith( "**/*" ) ) { + final String patternTail = pattern.substring( 4, pattern.length() ); + if ( !patternTail.equals( ".hbm.xml" ) ) { + throw new AssertionFailure( + "Improper use of NativeScanner: " + + "must not filter files via pattern other than .hbm.xml" + ); + } + endWiths.add( patternTail ); + } + else { + exacts.add( pattern ); + } + } + + final Set fileEntries; + try { + fileEntries = ( Set ) jarVisitor.getMatchingEntries()[FILE_FILTER_INDEX]; + } + catch ( IOException e ) { + throw new RuntimeException( "Error while reading " + jarToScan.toString(), e ); + } + Set files = new HashSet( fileEntries.size() ); + Set leftOver = new HashSet( fileEntries ); + for ( Entry entry : fileEntries ) { + boolean done = false; + for ( String exact : exacts ) { + if ( entry.getName().equals( exact ) ) { + files.add( new NamedInputStream( entry.getName(), entry.getInputStream() ) ); + leftOver.remove( entry ); + done = true; + 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 getFilesInClasspath(URL jartoScan, Set filePatterns) { + throw new AssertionFailure( "Not implemented" ); + } + + public String getUnqualifiedJarName(URL jarToScan) { + JarVisitor jarVisitor = getVisitor( jarToScan ); + return jarVisitor.getUnqualifiedJarName(); + } + + private static class StateJarVisitor { + StateJarVisitor(JarVisitor visitor) { + this.visitor = visitor; + } + JarVisitor visitor; + boolean hasReadFiles = false; + } +} diff --git a/entitymanager/src/main/java/org/hibernate/ejb/packaging/Scanner.java b/entitymanager/src/main/java/org/hibernate/ejb/packaging/Scanner.java new file mode 100644 index 0000000000..6144a4958c --- /dev/null +++ b/entitymanager/src/main/java/org/hibernate/ejb/packaging/Scanner.java @@ -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 getPackagesInJar(URL jartoScan, Set> annotationsToLookFor); + + /** + * return all classes in the jar matching one of these annotations + * if annotationsToLookFor is empty, return all classes + */ + Set> getClassesInJar(URL jartoScan, Set> annotationsToLookFor); + + /** + * return all files in the jar matching one of these file names + * if filePatterns is empty, return all files + * eg **\/*.hbm.xml, META-INF/orm.xml + */ + Set getFilesInJar(URL jartoScan, Set filePatterns); + + + /** + * return all files in the classpath (ie PU visibility) matching one of these file names + * if filePatterns is empty, return all files + * the use case is really exact file name. + */ + Set getFilesInClasspath(URL jartoScan, Set filePatterns); + + /** + * return the unqualified JAR name ie customer-model.jar or store.war + */ + String getUnqualifiedJarName(URL jarUrl); + +} diff --git a/entitymanager/src/test/java/org/hibernate/ejb/test/packaging/NativeScannerTest.java b/entitymanager/src/test/java/org/hibernate/ejb/test/packaging/NativeScannerTest.java new file mode 100644 index 0000000000..9a5417105b --- /dev/null +++ b/entitymanager/src/test/java/org/hibernate/ejb/test/packaging/NativeScannerTest.java @@ -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> annotationsToLookFor = new HashSet>(3); + annotationsToLookFor.add( Entity.class ); + annotationsToLookFor.add( MappedSuperclass.class ); + annotationsToLookFor.add( Embeddable.class ); + final Set> 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 filePatterns = new HashSet(2); + filePatterns.add("**/*.hbm.xml"); + filePatterns.add("META-INF/orm.xml"); + final Set files = scanner.getFilesInJar( jarUrl, filePatterns ); + + assertEquals( 2, files.size() ); + for (NamedInputStream file : files ) { + assertNotNull( file.getStream() ); + file.getStream().close(); + } + } +}