HHH-5026 Ability to customize Scanner strategies
git-svn-id: https://svn.jboss.org/repos/hibernate/core/trunk@19060 1b8cb986-b30d-0410-93ca-fae66ebed9b2
This commit is contained in:
parent
e94b5fc95f
commit
00b0459ce5
|
@ -67,7 +67,7 @@
|
|||
|
||||
<para>If you use Maven, add the following dependencies</para>
|
||||
|
||||
<programlisting role="XML" language="XML"><project ...>
|
||||
<programlisting language="XML" role="XML"><project ...>
|
||||
...
|
||||
<dependencies>
|
||||
<dependency>
|
||||
|
@ -100,7 +100,7 @@
|
|||
configuration, so by default, your persistence.xml will be quite
|
||||
minimalist:</para>
|
||||
|
||||
<programlisting role="XML" language="XML"><persistence xmlns="http://java.sun.com/xml/ns/persistence"
|
||||
<programlisting language="XML" role="XML"><persistence xmlns="http://java.sun.com/xml/ns/persistence"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"
|
||||
version="2.0">
|
||||
|
@ -116,7 +116,7 @@
|
|||
<para>Here's a more complete example of a
|
||||
<filename><literal>persistence.xml</literal></filename> file</para>
|
||||
|
||||
<programlisting role="XML" language="XML"><persistence xmlns="http://java.sun.com/xml/ns/persistence"
|
||||
<programlisting language="XML" role="XML"><persistence xmlns="http://java.sun.com/xml/ns/persistence"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"
|
||||
version="2.0">
|
||||
|
@ -211,7 +211,7 @@
|
|||
environment, the persistence.xml file is not under the same root
|
||||
directory or jar than your domain model).</para>
|
||||
|
||||
<programlisting role="XML" language="XML"> <jar-file>file:/home/turin/work/local/lab8/build/classes</jar-file></programlisting>
|
||||
<programlisting language="XML" role="XML"> <jar-file>file:/home/turin/work/local/lab8/build/classes</jar-file></programlisting>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
|
@ -323,14 +323,14 @@
|
|||
<literal><validation-mode></literal>. To use it, add a
|
||||
regular property</para>
|
||||
|
||||
<programlisting role="XML" language="XML"><property name="javax.persistence.validation.mode">
|
||||
<programlisting language="XML" role="XML"><property name="javax.persistence.validation.mode">
|
||||
ddl
|
||||
</property></programlisting>
|
||||
|
||||
<para>With this approach, you can mix ddl and callback
|
||||
modes:</para>
|
||||
|
||||
<programlisting role="XML" language="XML"><property name="javax.persistence.validation.mode">
|
||||
<programlisting language="XML" role="XML"><property name="javax.persistence.validation.mode">
|
||||
ddl, callback
|
||||
</property></programlisting>
|
||||
</listitem>
|
||||
|
@ -376,12 +376,35 @@
|
|||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>javax.persistence.validation.group.pre-persist defines
|
||||
the group or list of groups to validate before persisting an
|
||||
entity. This is a comma separated fully qualified class name
|
||||
string (eg <code>com.acme.groups.Common</code> or
|
||||
<para><literal>javax.persistence.validation.group.pre-persist</literal>
|
||||
defines the group or list of groups to validate before
|
||||
persisting an entity. This is a comma separated fully
|
||||
qualified class name string (eg
|
||||
<code>com.acme.groups.Common</code> or
|
||||
<code>com.acme.groups.Common,
|
||||
javax.validation.groups.Default</code>)</para>
|
||||
javax.validation.groups.Default</code>). Defaults to the Bean
|
||||
Validation default group.</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para><literal>javax.persistence.validation.group.pre-update</literal>
|
||||
defines the group or list of groups to validate before
|
||||
updating an entity. This is a comma separated fully qualified
|
||||
class name string (eg <code>com.acme.groups.Common</code> or
|
||||
<code>com.acme.groups.Common,
|
||||
javax.validation.groups.Default</code>). Defaults to the Bean
|
||||
Validation default group.</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para><literal>javax.persistence.validation.group.pre-remove</literal>
|
||||
defines the group or list of groups to validate before
|
||||
persisting an entity. This is a comma separated fully
|
||||
qualified class name string (eg
|
||||
<code>com.acme.groups.Common</code> or
|
||||
<code>com.acme.groups.Common,
|
||||
javax.validation.groups.Default</code>). Defaults to no
|
||||
group.</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
|
||||
|
@ -427,7 +450,7 @@
|
|||
the version embedded in the hibernate-entitymanager.jar. It won't fetch
|
||||
the resource from the internet.</para>
|
||||
|
||||
<programlisting role="XML" language="XML"><persistence xmlns="http://java.sun.com/xml/ns/persistence"
|
||||
<programlisting language="XML" role="XML"><persistence xmlns="http://java.sun.com/xml/ns/persistence"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"
|
||||
version="2.0"></programlisting>
|
||||
|
@ -441,7 +464,7 @@
|
|||
<classname>EntityManager</classname>. The bootstrap class is
|
||||
<classname>javax.persistence.Persistence</classname>, e.g.</para>
|
||||
|
||||
<programlisting role="JAVA" language="JAVA">EntityManagerFactory emf = Persistence.createEntityManagerFactory("manager1");
|
||||
<programlisting language="JAVA" role="JAVA">EntityManagerFactory emf = Persistence.createEntityManagerFactory("manager1");
|
||||
|
||||
//or
|
||||
|
||||
|
@ -636,10 +659,26 @@ EntityManagerFactory programmaticEmf =
|
|||
<entry>If true, the persistence context will be discarded (think
|
||||
clear() when the method is called. Otherwise the persistence
|
||||
context will stay alive till the transaction completion: all
|
||||
objects will remain managed, and any change will be sy,chronized
|
||||
objects will remain managed, and any change will be synchronized
|
||||
with the database (default to false, ie wait the transaction
|
||||
completion)</entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry>hibernate.ejb.resource_scanner</entry>
|
||||
|
||||
<entry><para>By default, Hibernate EntityManager scans itself
|
||||
the list of resources for annotated classes and persistence
|
||||
deployment descriptors (like orm.xml and hbm.xml
|
||||
files).</para><para>You can customize this scanning strategy by
|
||||
implementing
|
||||
<classname>org.hibernate.ejb.packaging.Scanner</classname>. This
|
||||
property is used by container implementors to improve
|
||||
integration with Hibernate.</para><para>Accepts an instance of
|
||||
<classname>Scanner</classname> or the file name of a no-arg
|
||||
constructor class implementing
|
||||
<classname>Scanner</classname>.</para></entry>
|
||||
</row>
|
||||
</tbody>
|
||||
</tgroup>
|
||||
</table>
|
||||
|
@ -663,7 +702,7 @@ EntityManagerFactory programmaticEmf =
|
|||
|
||||
<para>Here is a typical configuration in a Java SE environment</para>
|
||||
|
||||
<programlisting role="XML" language="XML"><persistence>
|
||||
<programlisting language="XML" role="XML"><persistence>
|
||||
<persistence-unit name="manager1" transaction-type="RESOURCE_LOCAL">
|
||||
<class>org.hibernate.ejb.test.Cat</class>
|
||||
<class>org.hibernate.ejb.test.Distributor</class>
|
||||
|
@ -695,7 +734,7 @@ EntityManagerFactory programmaticEmf =
|
|||
|
||||
<para>TODO: me more descriptive on some APIs like setDatasource()</para>
|
||||
|
||||
<programlisting role="JAVA" language="JAVA">Ejb3Configuration cfg = new Ejb3Configuration();
|
||||
<programlisting language="JAVA" role="JAVA">Ejb3Configuration cfg = new Ejb3Configuration();
|
||||
EntityManagerFactory emf =
|
||||
cfg.addProperties( properties ) //add some properties
|
||||
.setInterceptor( myInterceptorImpl ) // set an interceptor
|
||||
|
@ -857,7 +896,7 @@ EntityManagerFactory emf =
|
|||
<classname>Persistence</classname> class is bootstrap class to create an
|
||||
entity manager factory.</para>
|
||||
|
||||
<programlisting role="JAVA" language="JAVA">// Use persistence.xml configuration
|
||||
<programlisting language="JAVA" role="JAVA">// Use persistence.xml configuration
|
||||
EntityManagerFactory emf = Persistence.createEntityManagerFactory("manager1")
|
||||
EntityManager em = emf.createEntityManager(); // Retrieve an application managed entity manager
|
||||
// Work with the EM
|
||||
|
@ -892,4 +931,4 @@ emf.close(); //close at application end</programlisting>
|
|||
be no performance cost. For more information on Hibernate Validator,
|
||||
please refer to the Hibernate Annotations reference guide.</para>
|
||||
</section>
|
||||
</chapter>
|
||||
</chapter>
|
||||
|
|
|
@ -270,10 +270,17 @@ public class AvailableSettings {
|
|||
public static final String CONFIGURATION_JNDI_NAME = "hibernate.ejb.configuration_jndi_name";
|
||||
|
||||
/**
|
||||
* Used to detrmine flush mode.
|
||||
* Used to determine flush mode.
|
||||
*/
|
||||
public static final String FLUSH_MODE = "org.hibernate.flushMode";
|
||||
|
||||
/**
|
||||
* 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";
|
||||
|
||||
/**
|
||||
* List of classes names
|
||||
* Internal use only
|
||||
|
|
|
@ -324,7 +324,7 @@ public class Ejb3Configuration implements Serializable, Referenceable {
|
|||
Scanner scanner = null;
|
||||
URL jarURL = null;
|
||||
if ( metadata.getName() == null ) {
|
||||
scanner = buildScanner();
|
||||
scanner = buildScanner( metadata.getProps() );
|
||||
jarURL = JarVisitorFactory.getJarURLFromURLEntry( url, "/META-INF/persistence.xml" );
|
||||
metadata.setName( scanner.getUnqualifiedJarName(jarURL) );
|
||||
}
|
||||
|
@ -333,7 +333,7 @@ public class Ejb3Configuration implements Serializable, Referenceable {
|
|||
}
|
||||
else if ( persistenceUnitName == null || metadata.getName().equals( persistenceUnitName ) ) {
|
||||
if (scanner == null) {
|
||||
scanner = buildScanner();
|
||||
scanner = buildScanner( metadata.getProps() );
|
||||
jarURL = JarVisitorFactory.getJarURLFromURLEntry( url, "/META-INF/persistence.xml" );
|
||||
}
|
||||
//scan main JAR
|
||||
|
@ -373,8 +373,40 @@ public class Ejb3Configuration implements Serializable, Referenceable {
|
|||
}
|
||||
}
|
||||
|
||||
private NativeScanner buildScanner() {
|
||||
return new NativeScanner();
|
||||
private Scanner buildScanner(Properties properties) {
|
||||
final Object scanner = properties.getProperty( AvailableSettings.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. " + AvailableSettings.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. " + AvailableSettings.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 {
|
||||
|
@ -531,7 +563,9 @@ public class Ejb3Configuration implements Serializable, Referenceable {
|
|||
boolean searchForORMFiles = ! xmlFiles.contains( META_INF_ORM_XML );
|
||||
|
||||
ScanningContext context = new ScanningContext();
|
||||
context.scanner( buildScanner() )
|
||||
final Properties copyOfProperties = (Properties) info.getProperties().clone();
|
||||
ConfigurationHelper.overrideProperties( copyOfProperties, integration );
|
||||
context.scanner( buildScanner( copyOfProperties ) )
|
||||
.searchOrm( searchForORMFiles )
|
||||
.explicitMappingFiles( null ); //URLs provided by the container already
|
||||
|
||||
|
|
|
@ -225,7 +225,7 @@ public class NativeScanner implements Scanner {
|
|||
return files;
|
||||
}
|
||||
|
||||
public Set<NamedInputStream> getFilesInClasspath(URL jartoScan, Set<String> filePatterns) {
|
||||
public Set<NamedInputStream> getFilesInClasspath(Set<String> filePatterns) {
|
||||
throw new AssertionFailure( "Not implemented" );
|
||||
}
|
||||
|
||||
|
|
|
@ -50,11 +50,13 @@ public interface Scanner {
|
|||
|
||||
|
||||
/**
|
||||
* return all files in the classpath (ie PU visibility) matching one of these file names
|
||||
* 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(URL jartoScan, Set<String> filePatterns);
|
||||
Set<NamedInputStream> getFilesInClasspath(Set<String> filePatterns);
|
||||
|
||||
/**
|
||||
* return the unqualified JAR name ie customer-model.jar or store.war
|
||||
|
|
|
@ -11,6 +11,9 @@
|
|||
<class>org.hibernate.ejb.test.Item</class>
|
||||
<exclude-unlisted-classes>true</exclude-unlisted-classes>
|
||||
<properties>
|
||||
<!-- custom scanner test -->
|
||||
<property name="hibernate.ejb.resource_scanner" value="org.hibernate.ejb.test.packaging.CustomScanner"/>
|
||||
|
||||
<property name="hibernate.dialect" value="${db.dialect}"/>
|
||||
<property name="hibernate.connection.driver_class" value="${jdbc.driver}"/>
|
||||
<property name="hibernate.connection.username" value="${jdbc.user}"/>
|
||||
|
|
|
@ -0,0 +1,50 @@
|
|||
package org.hibernate.ejb.test.packaging;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.net.URL;
|
||||
import java.util.Set;
|
||||
|
||||
import org.hibernate.ejb.packaging.NamedInputStream;
|
||||
import org.hibernate.ejb.packaging.NativeScanner;
|
||||
import org.hibernate.ejb.packaging.Scanner;
|
||||
|
||||
/**
|
||||
* @author Emmanuel Bernard
|
||||
*/
|
||||
public class CustomScanner implements Scanner {
|
||||
public static boolean isUsed = false;
|
||||
private Scanner scanner = new NativeScanner();
|
||||
|
||||
public static boolean isUsed() {
|
||||
return isUsed;
|
||||
}
|
||||
|
||||
public static void resetUsed() {
|
||||
isUsed = false;
|
||||
}
|
||||
|
||||
public Set<Package> getPackagesInJar(URL jartoScan, Set<Class<? extends Annotation>> annotationsToLookFor) {
|
||||
isUsed = true;
|
||||
return scanner.getPackagesInJar( jartoScan, annotationsToLookFor );
|
||||
}
|
||||
|
||||
public Set<Class<?>> getClassesInJar(URL jartoScan, Set<Class<? extends Annotation>> annotationsToLookFor) {
|
||||
isUsed = true;
|
||||
return scanner.getClassesInJar( jartoScan, annotationsToLookFor );
|
||||
}
|
||||
|
||||
public Set<NamedInputStream> getFilesInJar(URL jartoScan, Set<String> filePatterns) {
|
||||
isUsed = true;
|
||||
return scanner.getFilesInJar( jartoScan, filePatterns );
|
||||
}
|
||||
|
||||
public Set<NamedInputStream> getFilesInClasspath(Set<String> filePatterns) {
|
||||
isUsed = true;
|
||||
return scanner.getFilesInClasspath( filePatterns );
|
||||
}
|
||||
|
||||
public String getUnqualifiedJarName(URL jarUrl) {
|
||||
isUsed = true;
|
||||
return scanner.getUnqualifiedJarName( jarUrl );
|
||||
}
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
package org.hibernate.ejb.test.packaging;
|
||||
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.Id;
|
||||
|
||||
/**
|
||||
* @author Emmanuel Bernard
|
||||
*/
|
||||
@Entity
|
||||
public class Pasta {
|
||||
@Id @GeneratedValue
|
||||
public Integer getId() { return id; }
|
||||
public void setId(Integer id) { this.id = id;}
|
||||
private Integer id;
|
||||
|
||||
public String getType() { return type; }
|
||||
public void setType(String type) { this.type = type;}
|
||||
private String type;
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
// $Id:$
|
||||
// $Id$
|
||||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
|
@ -26,11 +26,14 @@ package org.hibernate.ejb.test.packaging;
|
|||
|
||||
import java.io.File;
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import javax.persistence.Embeddable;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.EntityManagerFactory;
|
||||
import javax.persistence.MappedSuperclass;
|
||||
import javax.persistence.Persistence;
|
||||
|
||||
import org.hibernate.ejb.packaging.NamedInputStream;
|
||||
import org.hibernate.ejb.packaging.NativeScanner;
|
||||
|
@ -42,7 +45,7 @@ import org.hibernate.ejb.test.pack.defaultpar.ApplicationServer;
|
|||
* @author Emmanuel Bernard
|
||||
* @author Hardy Ferentschik
|
||||
*/
|
||||
public class NativeScannerTest extends PackagingTestCase {
|
||||
public class ScannerTest extends PackagingTestCase {
|
||||
public void testNativeScanner() throws Exception {
|
||||
File defaultPar = buildDefaultPar();
|
||||
addPackageToClasspath( defaultPar );
|
||||
|
@ -71,4 +74,21 @@ public class NativeScannerTest extends PackagingTestCase {
|
|||
file.getStream().close();
|
||||
}
|
||||
}
|
||||
|
||||
public void testCustomScanner() throws Exception {
|
||||
File defaultPar = buildDefaultPar();
|
||||
File explicitPar = buildExplicitPar();
|
||||
addPackageToClasspath( defaultPar, explicitPar );
|
||||
|
||||
EntityManagerFactory emf;
|
||||
CustomScanner.resetUsed();
|
||||
emf = Persistence.createEntityManagerFactory( "defaultpar", new HashMap() );
|
||||
assertTrue( ! CustomScanner.isUsed() );
|
||||
emf.close();
|
||||
|
||||
CustomScanner.resetUsed();
|
||||
emf = Persistence.createEntityManagerFactory( "manager1", new HashMap() );
|
||||
assertTrue( CustomScanner.isUsed() );
|
||||
emf.close();
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue