Author: stliu
Date: 2012-06-01 13:26:52 -0400 (Fri, 01 Jun 2012)
New Revision: 21036
Added:
entitymanager/patches/3.4.0.GA_CP04_JBPAPP-9172/src/main/java/org/hibernate/ejb/packaging/NativeScanner.java
entitymanager/patches/3.4.0.GA_CP04_JBPAPP-9172/src/main/java/org/hibernate/ejb/packaging/Scanner.java
Modified:
core/patches/hibernate-3.3.2.GA_CP04_JBPAPP-9172/core/src/main/java/org/hibernate/transaction/JBossTransactionManagerLookup.java
entitymanager/patches/3.4.0.GA_CP04_JBPAPP-9172/src/main/java/org/hibernate/ejb/Ejb3Configuration.java
entitymanager/patches/3.4.0.GA_CP04_JBPAPP-9172/src/main/java/org/hibernate/ejb/HibernatePersistence.java
entitymanager/patches/3.4.0.GA_CP04_JBPAPP-9172/src/main/java/org/hibernate/ejb/packaging/JarVisitorFactory.java
entitymanager/patches/3.4.0.GA_CP04_JBPAPP-9172/src/test/java/org/hibernate/ejb/test/packaging/JarVisitorTest.java
Log:
JBPAPP-9172 support hibernate 3.3 on EAP6 / WFK 2.0
Modified:
core/patches/hibernate-3.3.2.GA_CP04_JBPAPP-9172/core/src/main/java/org/hibernate/transaction/JBossTransactionManagerLookup.java
===================================================================
---
core/patches/hibernate-3.3.2.GA_CP04_JBPAPP-9172/core/src/main/java/org/hibernate/transaction/JBossTransactionManagerLookup.java 2012-06-01
03:00:23 UTC (rev 21035)
+++
core/patches/hibernate-3.3.2.GA_CP04_JBPAPP-9172/core/src/main/java/org/hibernate/transaction/JBossTransactionManagerLookup.java 2012-06-01
17:26:52 UTC (rev 21036)
@@ -24,19 +24,40 @@
*/
package org.hibernate.transaction;
+import java.util.Properties;
+import javax.naming.NamingException;
+import javax.transaction.TransactionManager;
+
+import org.hibernate.HibernateException;
+import org.hibernate.util.NamingHelper;
+
/**
* A {@link TransactionManagerLookup} lookup strategy for JBoss AS.
*
* @author Gavin King
*/
public final class JBossTransactionManagerLookup extends JNDITransactionManagerLookup {
-
+ public static final String AS4_TM_NAME = "java:/TransactionManager";
+ public static final String AS7_TM_NAME = "java:jboss/TransactionManager";
protected String getName() {
- return "java:/TransactionManager";
+ return AS4_TM_NAME;
}
public String getUserTransactionName() {
return "UserTransaction";
}
+ @Override
+ public TransactionManager getTransactionManager(Properties props) throws
HibernateException {
+ try {
+ return (TransactionManager) NamingHelper.getInitialContext( props ).lookup( getName()
);
+ }
+ catch ( NamingException e ) {
+ try{
+ return (TransactionManager) NamingHelper.getInitialContext( props ).lookup(
AS7_TM_NAME );
+ } catch ( NamingException e2 ){
+ throw new HibernateException( "Could not locate TransactionManager", e2
);
+ }
+ }
+ }
}
Modified:
entitymanager/patches/3.4.0.GA_CP04_JBPAPP-9172/src/main/java/org/hibernate/ejb/Ejb3Configuration.java
===================================================================
---
entitymanager/patches/3.4.0.GA_CP04_JBPAPP-9172/src/main/java/org/hibernate/ejb/Ejb3Configuration.java 2012-06-01
03:00:23 UTC (rev 21035)
+++
entitymanager/patches/3.4.0.GA_CP04_JBPAPP-9172/src/main/java/org/hibernate/ejb/Ejb3Configuration.java 2012-06-01
17:26:52 UTC (rev 21036)
@@ -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 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() );
+ }
+ }
}
/**
@@ -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();
@@ -526,7 +657,7 @@
else {
throw new PersistenceException( getExceptionHeader() +
HibernatePersistence.TRANSACTION_TYPE + " of the wrong class type"
- + ": " + overridenTxType.getClass()
+ + ": " + overridenTxType.getClass()
);
}
@@ -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
@@ -908,7 +1071,7 @@
}
catch( MappingException me ) {
throw new PersistenceException( getExceptionHeader()
- + "Error while reading JPA XML file: " + xmlFile, me);
+ + "Error while reading JPA XML file: " + xmlFile, me);
}
if ( log.isInfoEnabled() ) {
if ( Boolean.TRUE.equals( useMetaInf ) ) {
@@ -1049,8 +1212,8 @@
if ( !properties.containsKey( HibernatePersistence.JACC_CONTEXT_ID ) ) {
throw new PersistenceException( getExceptionHeader() +
"Entities have been configured for JACC, but "
- + HibernatePersistence.JACC_CONTEXT_ID
- + " has not been set"
+ + HibernatePersistence.JACC_CONTEXT_ID
+ + " has not been set"
);
}
String contextId = (String) properties.get( HibernatePersistence.JACC_CONTEXT_ID );
Modified:
entitymanager/patches/3.4.0.GA_CP04_JBPAPP-9172/src/main/java/org/hibernate/ejb/HibernatePersistence.java
===================================================================
---
entitymanager/patches/3.4.0.GA_CP04_JBPAPP-9172/src/main/java/org/hibernate/ejb/HibernatePersistence.java 2012-06-01
03:00:23 UTC (rev 21035)
+++
entitymanager/patches/3.4.0.GA_CP04_JBPAPP-9172/src/main/java/org/hibernate/ejb/HibernatePersistence.java 2012-06-01
17:26:52 UTC (rev 21036)
@@ -84,6 +84,12 @@
*/
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/patches/3.4.0.GA_CP04_JBPAPP-9172/src/main/java/org/hibernate/ejb/packaging/JarVisitorFactory.java
===================================================================
---
entitymanager/patches/3.4.0.GA_CP04_JBPAPP-9172/src/main/java/org/hibernate/ejb/packaging/JarVisitorFactory.java 2012-06-01
03:00:23 UTC (rev 21035)
+++
entitymanager/patches/3.4.0.GA_CP04_JBPAPP-9172/src/main/java/org/hibernate/ejb/packaging/JarVisitorFactory.java 2012-06-01
17:26:52 UTC (rev 21036)
@@ -18,6 +18,23 @@
public class JarVisitorFactory {
private static final Logger log = LoggerFactory.getLogger( JarVisitorFactory.class );
+ public static URL getURLFromPath(String jarPath) {
+ URL jarUrl;
+ try {
+ jarUrl = new URL( jarPath );
+ }
+ catch ( MalformedURLException e ) {
+ try {
+ 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
@@ -105,7 +122,7 @@
if ( "jar".equals( protocol ) ) {
return new JarProtocolVisitor( jarUrl, filters, entry );
}
- else if ( StringHelper.isEmpty( protocol ) || "file".equals( protocol ) ) {
+ else if ( StringHelper.isEmpty( protocol ) || "file".equals( protocol ) ||
"vfsfile".equals( protocol ) ) {
File file;
try {
final String filePart = jarUrl.getFile();
Added:
entitymanager/patches/3.4.0.GA_CP04_JBPAPP-9172/src/main/java/org/hibernate/ejb/packaging/NativeScanner.java
===================================================================
---
entitymanager/patches/3.4.0.GA_CP04_JBPAPP-9172/src/main/java/org/hibernate/ejb/packaging/NativeScanner.java
(rev 0)
+++
entitymanager/patches/3.4.0.GA_CP04_JBPAPP-9172/src/main/java/org/hibernate/ejb/packaging/NativeScanner.java 2012-06-01
17:26:52 UTC (rev 21036)
@@ -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/patches/3.4.0.GA_CP04_JBPAPP-9172/src/main/java/org/hibernate/ejb/packaging/Scanner.java
===================================================================
---
entitymanager/patches/3.4.0.GA_CP04_JBPAPP-9172/src/main/java/org/hibernate/ejb/packaging/Scanner.java
(rev 0)
+++
entitymanager/patches/3.4.0.GA_CP04_JBPAPP-9172/src/main/java/org/hibernate/ejb/packaging/Scanner.java 2012-06-01
17:26:52 UTC (rev 21036)
@@ -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);
+
+}
Modified:
entitymanager/patches/3.4.0.GA_CP04_JBPAPP-9172/src/test/java/org/hibernate/ejb/test/packaging/JarVisitorTest.java
===================================================================
---
entitymanager/patches/3.4.0.GA_CP04_JBPAPP-9172/src/test/java/org/hibernate/ejb/test/packaging/JarVisitorTest.java 2012-06-01
03:00:23 UTC (rev 21035)
+++
entitymanager/patches/3.4.0.GA_CP04_JBPAPP-9172/src/test/java/org/hibernate/ejb/test/packaging/JarVisitorTest.java 2012-06-01
17:26:52 UTC (rev 21036)
@@ -4,6 +4,8 @@
import java.io.IOException;
import java.net.URL;
import java.net.URLConnection;
+import java.net.URLStreamHandler;
+import java.net.URLStreamHandlerFactory;
import java.util.Set;
import javax.persistence.Embeddable;
@@ -33,7 +35,7 @@
*/
@SuppressWarnings("unchecked")
public class JarVisitorTest extends TestCase {
-
+
private static final Logger log = LoggerFactory.getLogger(JarVisitorTest.class);
public void testHttp() throws Exception {
@@ -57,6 +59,45 @@
assertEquals( 0, visitor.getMatchingEntries()[2].size() );
}
+ /**
+ * related to JBPAPP-7488
+ */
+ public void testJarVisitorFactory() throws Exception{
+
+ //setting URL to accept vfs based protocol
+ URL.setURLStreamHandlerFactory(new URLStreamHandlerFactory() {
+ public URLStreamHandler createURLStreamHandler(String protocol) {
+ if("vfsfile".equals(protocol) || "vfszip".equals(protocol)) {
+ return new URLStreamHandler() {
+ protected URLConnection openConnection(URL u)
+ throws IOException {
+ return null;
+ }
+ };
+ } else
+ return null;
+ }
+ });
+
+ URL jarUrl = new URL ("file:./target/test-packages/defaultpar.par");
+ JarVisitor jarVisitor = JarVisitorFactory.getVisitor(jarUrl, getFilters(), null);
+ assertEquals(FileZippedJarVisitor.class.getName(), jarVisitor.getClass().getName());
+
+ jarUrl = new URL ("file:./target/test-packages/explodedpar.par");
+ jarVisitor = JarVisitorFactory.getVisitor(jarUrl, getFilters(), null);
+ assertEquals(ExplodedJarVisitor.class.getName(), jarVisitor.getClass().getName());
+
+ jarUrl = new URL ("vfszip:./target/test-packages/defaultpar.par");
+ jarVisitor = JarVisitorFactory.getVisitor(jarUrl, getFilters(), null);
+ //ideally it should be FileZippedJarVisitor as well, but there is a bug in
FileZippedJarVisitor
+ //which causes regression for some tests in EAP test suite. InputStreamZippedJarVisitor
is safer than it, for now.
+ assertEquals(InputStreamZippedJarVisitor.class.getName(),
jarVisitor.getClass().getName());
+
+ jarUrl = new URL ("vfsfile:./target/test-packages/explodedpar.par");
+ jarVisitor = JarVisitorFactory.getVisitor(jarUrl, getFilters(), null);
+ assertEquals(ExplodedJarVisitor.class.getName(), jarVisitor.getClass().getName());
+ }
+
public void testInputStreamZippedJar() throws Exception {
String jarFileName = "file:./target/test-packages/defaultpar.par";
//JarVisitor jarVisitor = new ZippedJarVisitor( jarFileName, true, true );
@@ -181,7 +222,7 @@
* @see EJB-230
*/
public void testDuplicateFilterExplodedJarExpected() throws Exception {
-
+
log.warn("Skipping test! See jira issue EJB-230.");
// String jarFileName = "./target/test-packages/explodedpar.par";