[hibernate-commits] Hibernate SVN: r16358 - in core/trunk/entitymanager/src: main/java/org/hibernate/ejb/packaging and 1 other directories.

hibernate-commits at lists.jboss.org hibernate-commits at lists.jboss.org
Sat Apr 18 10:35:58 EDT 2009


Author: epbernard
Date: 2009-04-18 10:35:58 -0400 (Sat, 18 Apr 2009)
New Revision: 16358

Added:
   core/trunk/entitymanager/src/main/java/org/hibernate/ejb/packaging/NativeScanner.java
   core/trunk/entitymanager/src/main/java/org/hibernate/ejb/packaging/Scanner.java
   core/trunk/entitymanager/src/test/java/org/hibernate/ejb/test/packaging/NativeScannerTest.java
Modified:
   core/trunk/entitymanager/src/main/java/org/hibernate/ejb/Ejb3Configuration.java
   core/trunk/entitymanager/src/main/java/org/hibernate/ejb/packaging/AbstractJarVisitor.java
   core/trunk/entitymanager/src/main/java/org/hibernate/ejb/packaging/JarVisitorFactory.java
Log:
EJB-428 move scanning facility under the Scanner interface and implement NativeScanner

Modified: core/trunk/entitymanager/src/main/java/org/hibernate/ejb/Ejb3Configuration.java
===================================================================
--- core/trunk/entitymanager/src/main/java/org/hibernate/ejb/Ejb3Configuration.java	2009-04-17 20:48:26 UTC (rev 16357)
+++ core/trunk/entitymanager/src/main/java/org/hibernate/ejb/Ejb3Configuration.java	2009-04-18 14:35:58 UTC (rev 16358)
@@ -21,6 +21,8 @@
 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.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 @@
 					) ) {
 						//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,40 +283,90 @@
 		}
 	}
 
-	//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<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> packages = metadata.getPackages();
 		List<NamedInputStream> hbmFiles = metadata.getHbmfiles();
 		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 {
-		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<String> classes, List<String> packages, List<NamedInputStream> hbmFiles, List<String> mappingFiles) throws IOException {
+		Scanner scanner = scanningContext.scanner;
+		if (scanningContext.detectClasses) {
+			Set<Class<? extends Annotation>> annotationsToExclude = new HashSet<Class<? extends Annotation>>(3);
+			annotationsToExclude.add( Entity.class );
+			annotationsToExclude.add( MappedSuperclass.class );
+			annotationsToExclude.add( Embeddable.class );
+			Set<Class<?>> matchingClasses = scanner.getClassesInJar( scanningContext.url, annotationsToExclude );
+			for (Class<?> clazz : matchingClasses) {
+				classes.add( clazz.getName() );
 			}
+
+			Set<Package> matchingPackages = scanner.getPackagesInJar( scanningContext.url, new HashSet<Class<? extends Annotation>>(0) );
+			for (Package pkg : matchingPackages) {
+				packages.add( pkg.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,13 +418,23 @@
 			//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() :
 					new Properties();
@@ -536,88 +612,54 @@
 		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<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) {
+	private void scanForClasses(ScanningContext scanningContext, List<String> packages, List<String> entities, List<NamedInputStream> 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-file>: " + jar.toString(), e );
+			throw new RuntimeException( "error trying to scan <jar-file>: " + 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 );
 		}
 	}
 

Modified: core/trunk/entitymanager/src/main/java/org/hibernate/ejb/packaging/AbstractJarVisitor.java
===================================================================
--- core/trunk/entitymanager/src/main/java/org/hibernate/ejb/packaging/AbstractJarVisitor.java	2009-04-17 20:48:26 UTC (rev 16357)
+++ core/trunk/entitymanager/src/main/java/org/hibernate/ejb/packaging/AbstractJarVisitor.java	2009-04-18 14:35:58 UTC (rev 16358)
@@ -41,21 +41,7 @@
 	 * 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();
 	}
 

Modified: core/trunk/entitymanager/src/main/java/org/hibernate/ejb/packaging/JarVisitorFactory.java
===================================================================
--- core/trunk/entitymanager/src/main/java/org/hibernate/ejb/packaging/JarVisitorFactory.java	2009-04-17 20:48:26 UTC (rev 16357)
+++ core/trunk/entitymanager/src/main/java/org/hibernate/ejb/packaging/JarVisitorFactory.java	2009-04-18 14:35:58 UTC (rev 16358)
@@ -26,6 +26,7 @@
 	 * @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;
@@ -75,6 +76,30 @@
 	}
 
 	/**
+	 * 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
 	 *
 	 * Method used in a non-managed environment

Added: core/trunk/entitymanager/src/main/java/org/hibernate/ejb/packaging/NativeScanner.java
===================================================================
--- core/trunk/entitymanager/src/main/java/org/hibernate/ejb/packaging/NativeScanner.java	                        (rev 0)
+++ core/trunk/entitymanager/src/main/java/org/hibernate/ejb/packaging/NativeScanner.java	2009-04-18 14:35:58 UTC (rev 16358)
@@ -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;
+	}
+}

Added: core/trunk/entitymanager/src/main/java/org/hibernate/ejb/packaging/Scanner.java
===================================================================
--- core/trunk/entitymanager/src/main/java/org/hibernate/ejb/packaging/Scanner.java	                        (rev 0)
+++ core/trunk/entitymanager/src/main/java/org/hibernate/ejb/packaging/Scanner.java	2009-04-18 14:35:58 UTC (rev 16358)
@@ -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);
+
+}

Added: core/trunk/entitymanager/src/test/java/org/hibernate/ejb/test/packaging/NativeScannerTest.java
===================================================================
--- core/trunk/entitymanager/src/test/java/org/hibernate/ejb/test/packaging/NativeScannerTest.java	                        (rev 0)
+++ core/trunk/entitymanager/src/test/java/org/hibernate/ejb/test/packaging/NativeScannerTest.java	2009-04-18 14:35:58 UTC (rev 16358)
@@ -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();
+		}
+	}
+}




More information about the hibernate-commits mailing list