[hibernate-commits] Hibernate SVN: r20997 - in entitymanager/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/ejb: packaging and 1 other directory.

hibernate-commits at lists.jboss.org hibernate-commits at lists.jboss.org
Mon Dec 19 03:43:32 EST 2011


Author: stliu
Date: 2011-12-19 03:43:31 -0500 (Mon, 19 Dec 2011)
New Revision: 20997

Added:
   entitymanager/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/ejb/packaging/NativeScanner.java
   entitymanager/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/ejb/packaging/Scanner.java
Modified:
   entitymanager/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/ejb/Ejb3Configuration.java
   entitymanager/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/ejb/HibernatePersistence.java
   entitymanager/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/ejb/packaging/JarVisitorFactory.java
Log:
JBPAPP-7729 Hibernate 3.3.x Auto scan for JPA entities does not work with AS 7.1

Modified: entitymanager/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/ejb/Ejb3Configuration.java
===================================================================
--- entitymanager/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/ejb/Ejb3Configuration.java	2011-12-14 03:02:55 UTC (rev 20996)
+++ entitymanager/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/ejb/Ejb3Configuration.java	2011-12-19 08:43:31 UTC (rev 20997)
@@ -9,12 +9,14 @@
 import java.io.ObjectOutput;
 import java.io.ObjectOutputStream;
 import java.io.Serializable;
+import java.lang.annotation.Annotation;
 import java.net.URL;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.Enumeration;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
@@ -54,15 +56,15 @@
 import org.hibernate.ejb.connection.InjectedDataSourceConnectionProvider;
 import org.hibernate.ejb.instrument.InterceptFieldClassFileTransformer;
 import org.hibernate.ejb.packaging.ClassFilter;
-import org.hibernate.ejb.packaging.Entry;
 import org.hibernate.ejb.packaging.FileFilter;
 import org.hibernate.ejb.packaging.Filter;
-import org.hibernate.ejb.packaging.JarVisitor;
 import org.hibernate.ejb.packaging.JarVisitorFactory;
 import org.hibernate.ejb.packaging.NamedInputStream;
+import org.hibernate.ejb.packaging.NativeScanner;
 import org.hibernate.ejb.packaging.PackageFilter;
 import org.hibernate.ejb.packaging.PersistenceMetadata;
 import org.hibernate.ejb.packaging.PersistenceXmlLoader;
+import org.hibernate.ejb.packaging.Scanner;
 import org.hibernate.ejb.transaction.JoinableCMTTransactionFactory;
 import org.hibernate.ejb.util.ConfigurationHelper;
 import org.hibernate.ejb.util.LogHelper;
@@ -78,6 +80,7 @@
 import org.hibernate.util.ReflectHelper;
 import org.hibernate.util.StringHelper;
 import org.hibernate.util.XMLHelper;
+
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.xml.sax.EntityResolver;
@@ -232,24 +235,45 @@
 							metadata.getProvider()
 					) ) {
 						//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( metadata.getProps(), integration );
+							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( metadata.getProps(), integration );
+								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 );
 						}
@@ -268,40 +292,129 @@
 		}
 	}
 
-	//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 Scanner buildScanner(Properties properties, Map<?, ?> integration) {
+		//read the String or Instance from the integration map first and use the properties as a backup.
+		Object scanner = integration.get( HibernatePersistence.SCANNER );
+		if ( scanner == null ) {
+			scanner = properties.getProperty( HibernatePersistence.SCANNER );
+		}
+		if ( scanner != null ) {
+			Class<?> scannerClass;
+			if ( scanner instanceof String ) {
+				try {
+					scannerClass = ReflectHelper.classForName( (String) scanner, this.getClass() );
+				}
+				catch ( ClassNotFoundException e ) {
+					throw new PersistenceException(
+							"Cannot find scanner class. " + HibernatePersistence.SCANNER + "=" + scanner,
+							e
+					);
+				}
+			}
+			else if ( scanner instanceof Class ) {
+				scannerClass = (Class<? extends Scanner>) scanner;
+			}
+			else if ( scanner instanceof Scanner ) {
+				return (Scanner) scanner;
+			}
+			else {
+				throw new PersistenceException( "Scanner class configuration error: unknown type on the property. " + HibernatePersistence.SCANNER );
+			}
+			try {
+				return (Scanner) scannerClass.newInstance();
+			}
+			catch ( InstantiationException e ) {
+				throw new PersistenceException( "Unable to load Scanner class: " + scannerClass, e );
+			}
+			catch ( IllegalAccessException e ) {
+				throw new PersistenceException( "Unable to load Scanner class: " + scannerClass, e );
+			}
+		}
+		else {
+			return new NativeScanner();
+		}
+}
+
+	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 addMetadataFromVisitor(JarVisitor visitor, PersistenceMetadata metadata) throws IOException {
+	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() );
+			}
+		}
 	}
 
 	/**
@@ -353,13 +466,31 @@
 			//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();
+			final Properties copyOfProperties = (Properties) info.getProperties().clone();
+			ConfigurationHelper.overrideProperties( copyOfProperties, integration );
+			context.scanner( buildScanner( copyOfProperties, integration ) )
+					.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 );
 
+//			boolean[] detectArtifactForOtherJars = getDetectedArtifacts( info.getProperties(), null, false );
+//			boolean[] detectArtifactForMainJar = getDetectedArtifacts( info.getProperties(), null, info.excludeUnlistedClasses() );
+//			for ( URL jar : info.getJarFileUrls() ) {
+//				scanForClasses( jar, packages, entities, hbmFiles, detectArtifactForOtherJars, searchForORMFiles );
+//			}
+//			scanForClasses( info.getPersistenceUnitRootUrl(), packages, entities, hbmFiles, detectArtifactForMainJar, searchForORMFiles );
+
 			Properties properties = info.getProperties() != null ?
 					info.getProperties() :
 					new Properties();
@@ -604,24 +735,56 @@
 		}
 		return filters;
 	}
+	/**
+	 * Set ScanningContext detectClasses and detectHbmFiles according to context
+	 */
+	private void setDetectedArtifactsOnScanningContext(ScanningContext context,
+													   Properties properties,
+													   Map overridenProperties,
+													   boolean excludeIfNotOverriden) {
 
-	private void scanForClasses(URL jar, List<String> packages, List<String> entities, List<NamedInputStream> hbmFiles, boolean[] detectedArtifacts, boolean searchORM) {
-		if (jar == null) {
+		boolean detectClasses = false;
+		boolean detectHbm = false;
+		String detectSetting = overridenProperties != null ?
+				(String) overridenProperties.get( HibernatePersistence.AUTODETECTION ) :
+				null;
+		detectSetting = detectSetting == null ?
+				properties.getProperty( HibernatePersistence.AUTODETECTION) :
+				detectSetting;
+		if ( detectSetting == null && excludeIfNotOverriden) {
+			//not overriden through HibernatePersistence.AUTODETECTION so we comply with the spec excludeUnlistedClasses
+			context.detectClasses( false ).detectHbmFiles( false );
+			return;
+		}
+
+		if ( detectSetting == null){
+			detectSetting = "class,hbm";
+		}
+		StringTokenizer st = new StringTokenizer( detectSetting, ", ", false );
+		while ( st.hasMoreElements() ) {
+			String element = (String) st.nextElement();
+			if ( "class".equalsIgnoreCase( element ) ) detectClasses = true;
+			if ( "hbm".equalsIgnoreCase( element ) ) detectHbm = true;
+		}
+		log.debug( "Detect class: {}; detect hbm: {}", detectClasses, detectHbm );
+		context.detectClasses( detectClasses ).detectHbmFiles( detectHbm );
+	}
+
+	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 );
 		}
 	}
-
 	/**
 	 * create a factory from a list of properties and
 	 * HibernatePersistence.CLASS_NAMES -> Collection<String> (use to list the classes from config files

Modified: entitymanager/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/ejb/HibernatePersistence.java
===================================================================
--- entitymanager/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/ejb/HibernatePersistence.java	2011-12-14 03:02:55 UTC (rev 20996)
+++ entitymanager/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/ejb/HibernatePersistence.java	2011-12-19 08:43:31 UTC (rev 20997)
@@ -83,7 +83,12 @@
 	 * in the JNDI in a serialized form
 	 */
 	public static final String CONFIGURATION_JNDI_NAME = "hibernate.ejb.configuration_jndi_name";
-
+	/**
+	 * Pass an implementation of {@link org.hibernate.ejb.packaging.Scanner}:
+	 *  - preferably an actual instance
+	 *  - or a class name with a no-arg constructor
+	 */
+	public static final String SCANNER = "hibernate.ejb.resource_scanner";
 	//The following properties are for Internal use only
 	/**
 	 * link to the alternative Hibernate configuration file

Modified: entitymanager/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/ejb/packaging/JarVisitorFactory.java
===================================================================
--- entitymanager/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/ejb/packaging/JarVisitorFactory.java	2011-12-14 03:02:55 UTC (rev 20996)
+++ entitymanager/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/ejb/packaging/JarVisitorFactory.java	2011-12-19 08:43:31 UTC (rev 20997)
@@ -17,7 +17,23 @@
  */
 public class JarVisitorFactory {
 	private static final Logger log = LoggerFactory.getLogger( JarVisitorFactory.class );
-
+	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 the JAR URL of the JAR containing the given entry
 	 * Method used in a non managed environment

Added: entitymanager/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/ejb/packaging/NativeScanner.java
===================================================================
--- entitymanager/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/ejb/packaging/NativeScanner.java	                        (rev 0)
+++ entitymanager/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/ejb/packaging/NativeScanner.java	2011-12-19 08:43:31 UTC (rev 20997)
@@ -0,0 +1,242 @@
+/*
+ * Copyright (c) 2009, Red Hat Middleware LLC or third-party contributors as
+ * indicated by the @author tags or express copyright attribution
+ * statements applied by the authors.  All third-party contributions are
+ * distributed under license by Red Hat Middleware LLC.
+ *
+ * This copyrighted material is made available to anyone wishing to use, modify,
+ * copy, or redistribute it subject to the terms and conditions of the GNU
+ * Lesser General Public License, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this distribution; if not, write to:
+ * Free Software Foundation, Inc.
+ * 51 Franklin Street, Fifth Floor
+ * Boston, MA  02110-1301  USA
+ */
+package org.hibernate.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" );
+		}
+		JarVisitor jarVisitor = getVisitor( jarToScan );
+
+		//state visitor available
+		final StateJarVisitor stateVisitor = visitors.get( jarToScan );
+		if ( stateVisitor.hasReadFiles ) {
+			throw new AssertionFailure( "Cannot read files twice on NativeScanner" );
+		}
+		stateVisitor.hasReadFiles = true;
+
+		Set<String> endWiths = new HashSet<String>();
+		Set<String> exacts = new HashSet<String>();
+		for ( String pattern : filePatterns ) {
+			if ( pattern.startsWith( "**/*" ) ) {
+				final String patternTail = pattern.substring( 4, pattern.length() );
+				if ( !patternTail.equals( ".hbm.xml" ) ) {
+					throw new AssertionFailure(
+							"Improper use of NativeScanner: "
+									+ "must not filter files via pattern other than .hbm.xml"
+					);
+				}
+				endWiths.add( patternTail );
+			}
+			else {
+				exacts.add( pattern );
+			}
+		}
+
+		final Set<Entry> fileEntries;
+		try {
+			fileEntries = ( Set<Entry> ) jarVisitor.getMatchingEntries()[FILE_FILTER_INDEX];
+		}
+		catch ( IOException e ) {
+			throw new RuntimeException( "Error while reading " + jarToScan.toString(), e );
+		}
+		Set<NamedInputStream> files = new HashSet<NamedInputStream>( fileEntries.size() );
+		Set<Entry> leftOver = new HashSet<Entry>( fileEntries );
+		for ( Entry entry : fileEntries ) {
+			boolean done = false;
+			for ( String exact : exacts ) {
+				if ( entry.getName().equals( exact ) ) {
+					files.add( new NamedInputStream( entry.getName(), entry.getInputStream() ) );
+					leftOver.remove( entry );
+					done = true;
+				}
+			}
+			if (done) continue;
+			for ( String endWithPattern : endWiths ) {
+				if ( entry.getName().endsWith( endWithPattern ) ) {
+					files.add( new NamedInputStream( entry.getName(), entry.getInputStream() ) );
+					leftOver.remove( entry );
+				}
+			}
+
+		}
+		for ( Entry entry : leftOver ) {
+			try {
+				entry.getInputStream().close();
+			}
+			catch ( IOException e ) {
+				//swallow as we don't care about these files
+			}
+		}
+		return files;
+	}
+
+	public Set<NamedInputStream> getFilesInClasspath(Set<String> filePatterns) {
+		throw new AssertionFailure( "Not implemented" );
+	}
+
+	public String getUnqualifiedJarName(URL jarToScan) {
+		JarVisitor jarVisitor = getVisitor( jarToScan );
+		return jarVisitor.getUnqualifiedJarName();
+	}
+
+	private static class StateJarVisitor {
+		StateJarVisitor(JarVisitor visitor) {
+			this.visitor = visitor;
+		}
+		JarVisitor visitor;
+		boolean hasReadFiles = false;
+	}
+}

Added: entitymanager/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/ejb/packaging/Scanner.java
===================================================================
--- entitymanager/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/ejb/packaging/Scanner.java	                        (rev 0)
+++ entitymanager/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/ejb/packaging/Scanner.java	2011-12-19 08:43:31 UTC (rev 20997)
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2009, Red Hat Middleware LLC or third-party contributors as
+ * indicated by the @author tags or express copyright attribution
+ * statements applied by the authors.  All third-party contributions are
+ * distributed under license by Red Hat Middleware LLC.
+ *
+ * This copyrighted material is made available to anyone wishing to use, modify,
+ * copy, or redistribute it subject to the terms and conditions of the GNU
+ * Lesser General Public License, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this distribution; if not, write to:
+ * Free Software Foundation, Inc.
+ * 51 Franklin Street, Fifth Floor
+ * Boston, MA  02110-1301  USA
+ */
+package org.hibernate.ejb.packaging;
+import java.lang.annotation.Annotation;
+import java.net.URL;
+import java.util.Set;
+
+/**
+ * @author Emmanuel Bernard
+ */
+public interface Scanner {
+	/**
+	 * return all packages in the jar matching one of these annotations
+	 * if annotationsToLookFor is empty, return all packages
+	 */
+	Set<Package> getPackagesInJar(URL jartoScan, Set<Class<? extends Annotation>> annotationsToLookFor);
+
+	/**
+	 * return all classes in the jar matching one of these annotations
+	 * if annotationsToLookFor is empty, return all classes
+	 */
+	Set<Class<?>> getClassesInJar(URL jartoScan, Set<Class<? extends Annotation>> annotationsToLookFor);
+
+	/**
+	 * return all files in the jar matching one of these file names
+	 * if filePatterns is empty, return all files
+	 * eg **\/*.hbm.xml, META-INF/orm.xml
+	 */
+	Set<NamedInputStream> getFilesInJar(URL jartoScan, Set<String> filePatterns);
+
+
+	/**
+	 * Return all files in the classpath (ie PU visibility) matching one of these file names
+	 * if filePatterns is empty, return all files
+	 * the use case is really exact file name.
+	 *
+	 * NOT USED by HEM at the moment. We use exact file search via getResourceAsStream for now.
+	 */
+	Set<NamedInputStream> getFilesInClasspath(Set<String> filePatterns);
+
+	/**
+	 * return the unqualified JAR name ie customer-model.jar or store.war
+	 */
+	String getUnqualifiedJarName(URL jarUrl);
+
+}



More information about the hibernate-commits mailing list