From 02f1be26e36d0fc802de77a67e10d71a2c11e746 Mon Sep 17 00:00:00 2001 From: Brett Meyer Date: Fri, 8 Feb 2013 19:02:11 -0500 Subject: [PATCH] HHH-7527 Enterprise OSGi JPA support --- build.gradle | 54 +++++- hibernate-c3p0/hibernate-c3p0.gradle | 7 + hibernate-core/hibernate-core.gradle | 13 ++ .../hibernate/engine/spi/CascadeStyle.java | 2 +- .../engine/spi/SessionImplementor.java | 5 +- .../org/hibernate/internal/SessionImpl.java | 20 ++- .../internal/StatelessSessionImpl.java | 21 ++- .../internal/util/ReflectHelper.java | 25 ++- hibernate-ehcache/hibernate-ehcache.gradle | 7 + .../hibernate-entitymanager.gradle | 19 ++ .../org/hibernate/ejb/Ejb3Configuration.java | 41 ++++- .../hibernate/ejb/HibernatePersistence.java | 4 +- .../engine/spi/EJB3CascadeStyle.java | 7 +- .../engine/spi/EJB3CascadingAction.java | 3 +- .../ejb/event/EJB3PersistEventListener.java | 4 +- hibernate-envers/hibernate-envers.gradle | 6 + .../AbstractDelegateSessionImplementor.java | 6 +- .../hibernate-infinispan.gradle | 9 +- hibernate-osgi/hibernate-osgi.gradle | 13 ++ .../osgi/HibernateBundleActivator.java | 113 ++++++++++++ .../org/hibernate/osgi/OsgiClassLoader.java | 168 ++++++++++++++++++ .../org/hibernate/osgi/OsgiJtaPlatform.java | 84 +++++++++ hibernate-proxool/hibernate-proxool.gradle | 8 +- hibernate-testing/hibernate-testing.gradle | 7 + libraries.gradle | 5 +- release/release.gradle | 16 +- settings.gradle | 2 + utilities.gradle | 49 +++++ 28 files changed, 650 insertions(+), 68 deletions(-) rename hibernate-entitymanager/src/main/java/org/hibernate/{ => ejb}/engine/spi/EJB3CascadeStyle.java (90%) rename hibernate-entitymanager/src/main/java/org/hibernate/{ => ejb}/engine/spi/EJB3CascadingAction.java (96%) create mode 100644 hibernate-osgi/hibernate-osgi.gradle create mode 100644 hibernate-osgi/src/main/java/org/hibernate/osgi/HibernateBundleActivator.java create mode 100644 hibernate-osgi/src/main/java/org/hibernate/osgi/OsgiClassLoader.java create mode 100644 hibernate-osgi/src/main/java/org/hibernate/osgi/OsgiJtaPlatform.java create mode 100644 utilities.gradle diff --git a/build.gradle b/build.gradle index 78bb310f29ca..0d4ddd2574ed 100644 --- a/build.gradle +++ b/build.gradle @@ -59,6 +59,8 @@ subprojects { subProject -> apply plugin: 'java' apply plugin: 'maven' // for install task as well as deploy dependencies apply plugin: 'uploadAuth' + apply plugin: 'osgi' + apply from: "../utilities.gradle" configurations { provided { @@ -155,13 +157,51 @@ subprojects { subProject -> compileJava.options.define(compilerArgs: ["-proc:none", "-encoding", "UTF-8"]) compileTestJava.options.define(compilerArgs: ["-proc:none", "-encoding", "UTF-8"]) - manifest.mainAttributes( - provider: 'gradle', - 'Implementation-Url': 'http://hibernate.org', - 'Implementation-Version': version, - 'Implementation-Vendor': 'Hibernate.org', - 'Implementation-Vendor-Id': 'org.hibernate' - ) + jar { + Set exportPackages = new HashSet() + Set privatePackages = new HashSet() + + // TODO: Could more of this be pulled into utilities.gradle? + sourceSets.each { SourceSet sourceSet -> + // skip certain source sets + if ( ! ['test','matrix'].contains( sourceSet.name ) ) { + sourceSet.java.each { javaFile -> + // - .util for external module use (especially envers) + final String[] temporaryExports = [ + 'org.hibernate.internal.util' ] + + final String packageName = determinePackageName( sourceSet.java, javaFile ); + if ( ! temporaryExports.contains( packageName ) + && ( packageName.endsWith( ".internal" ) + || packageName.contains( ".internal." ) + || packageName.endsWith( ".test" ) + || packageName.contains( ".test." ) ) ) { + privatePackages.add( packageName ); + } + else { + exportPackages.add( packageName ); + } + } + } + } + + manifest = osgiManifest { + // GRADLE-1411: Even if we override Imports and Exports + // auto-generation with instructions, classesDir and classpath + // need to be here (temporarily). + classesDir = sourceSets.main.output.classesDir + classpath = configurations.runtime + + instruction 'Export-Package', exportPackages.toArray(new String[0]) + instruction 'Private-Package', privatePackages.toArray(new String[0]) + instruction 'Bundle-Vendor', 'Hibernate.org' + + instruction 'Implementation-Url', 'http://hibernate.org' + instruction 'Implementation-Version', version + instruction 'Implementation-Vendor', 'Hibernate.org' + instruction 'Implementation-Vendor-Id', 'org.hibernate' + } + } test { // pass along command line defined system props (-D) to the test diff --git a/hibernate-c3p0/hibernate-c3p0.gradle b/hibernate-c3p0/hibernate-c3p0.gradle index c68d582ff03d..3d19fe5db243 100644 --- a/hibernate-c3p0/hibernate-c3p0.gradle +++ b/hibernate-c3p0/hibernate-c3p0.gradle @@ -8,4 +8,11 @@ dependencies { transitive = true } testCompile project( ':hibernate-testing' ) +} + +jar { + manifest { + instruction 'Bundle-Description', 'Hibernate ORM C3P0' + instruction 'Bundle-SymbolicName', 'org.hibernate.c3p0' + } } \ No newline at end of file diff --git a/hibernate-core/hibernate-core.gradle b/hibernate-core/hibernate-core.gradle index 789ba096b01d..5fa4e0b3e38b 100644 --- a/hibernate-core/hibernate-core.gradle +++ b/hibernate-core/hibernate-core.gradle @@ -37,6 +37,19 @@ manifest.mainAttributes( 'Main-Class': 'org.hibernate.Version' ) +jar { + manifest { + instruction 'Bundle-Description', 'Hibernate ORM Core' + instruction 'Bundle-SymbolicName', 'org.hibernate.core' + + // TODO: Uncomment once EntityManagerFactoryBuilderImpl no longer + // uses ClassLoaderServiceImpl. + instruction 'Export-Package', + 'org.hibernate.boot.registry.classloading.internal', + '*' + } +} + sourceSets.main { ext.jaxbTargetDir = file( "${buildDir}/generated-src/jaxb/main" ) java.srcDir jaxbTargetDir diff --git a/hibernate-core/src/main/java/org/hibernate/engine/spi/CascadeStyle.java b/hibernate-core/src/main/java/org/hibernate/engine/spi/CascadeStyle.java index c39f0f684039..d1fd79902a7f 100755 --- a/hibernate-core/src/main/java/org/hibernate/engine/spi/CascadeStyle.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/spi/CascadeStyle.java @@ -285,7 +285,7 @@ public String toString() { public CascadeStyle() { } - static final Map STYLES = new HashMap(); + public static final Map STYLES = new HashMap(); static { STYLES.put( "all", ALL ); diff --git a/hibernate-core/src/main/java/org/hibernate/engine/spi/SessionImplementor.java b/hibernate-core/src/main/java/org/hibernate/engine/spi/SessionImplementor.java index 658f58a930ae..498a838f3758 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/spi/SessionImplementor.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/spi/SessionImplementor.java @@ -30,6 +30,7 @@ import java.util.Map; import org.hibernate.CacheMode; +import org.hibernate.Criteria; import org.hibernate.FlushMode; import org.hibernate.HibernateException; import org.hibernate.Interceptor; @@ -170,11 +171,11 @@ public Object internalLoad(String entityName, Serializable id, boolean eager, bo /** * Execute a criteria query */ - public ScrollableResults scroll(CriteriaImpl criteria, ScrollMode scrollMode); + public ScrollableResults scroll(Criteria criteria, ScrollMode scrollMode); /** * Execute a criteria query */ - public List list(CriteriaImpl criteria); + public List list(Criteria criteria); /** * Execute a filter diff --git a/hibernate-core/src/main/java/org/hibernate/internal/SessionImpl.java b/hibernate-core/src/main/java/org/hibernate/internal/SessionImpl.java index ee66a6cb1699..f489979f458e 100644 --- a/hibernate-core/src/main/java/org/hibernate/internal/SessionImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/internal/SessionImpl.java @@ -1561,14 +1561,17 @@ public Criteria createCriteria(String entityName) { return new CriteriaImpl(entityName, this); } - public ScrollableResults scroll(CriteriaImpl criteria, ScrollMode scrollMode) { + public ScrollableResults scroll(Criteria criteria, ScrollMode scrollMode) { + // TODO: Is this guaranteed to always be CriteriaImpl? + CriteriaImpl criteriaImpl = (CriteriaImpl) criteria; + errorIfClosed(); checkTransactionSynchStatus(); - String entityName = criteria.getEntityOrClassName(); + String entityName = criteriaImpl.getEntityOrClassName(); CriteriaLoader loader = new CriteriaLoader( getOuterJoinLoadable(entityName), factory, - criteria, + criteriaImpl, entityName, getLoadQueryInfluencers() ); @@ -1582,8 +1585,11 @@ public ScrollableResults scroll(CriteriaImpl criteria, ScrollMode scrollMode) { } } - public List list(CriteriaImpl criteria) throws HibernateException { - final NaturalIdLoadAccess naturalIdLoadAccess = this.tryNaturalIdLoadAccess( criteria ); + public List list(Criteria criteria) throws HibernateException { + // TODO: Is this guaranteed to always be CriteriaImpl? + CriteriaImpl criteriaImpl = (CriteriaImpl) criteria; + + final NaturalIdLoadAccess naturalIdLoadAccess = this.tryNaturalIdLoadAccess( criteriaImpl ); if ( naturalIdLoadAccess != null ) { // EARLY EXIT! return Arrays.asList( naturalIdLoadAccess.load() ); @@ -1591,7 +1597,7 @@ public List list(CriteriaImpl criteria) throws HibernateException { errorIfClosed(); checkTransactionSynchStatus(); - String[] implementors = factory.getImplementors( criteria.getEntityOrClassName() ); + String[] implementors = factory.getImplementors( criteriaImpl.getEntityOrClassName() ); int size = implementors.length; CriteriaLoader[] loaders = new CriteriaLoader[size]; @@ -1601,7 +1607,7 @@ public List list(CriteriaImpl criteria) throws HibernateException { loaders[i] = new CriteriaLoader( getOuterJoinLoadable( implementors[i] ), factory, - criteria, + criteriaImpl, implementors[i], getLoadQueryInfluencers() ); diff --git a/hibernate-core/src/main/java/org/hibernate/internal/StatelessSessionImpl.java b/hibernate-core/src/main/java/org/hibernate/internal/StatelessSessionImpl.java index 9ad53a566f1b..2ee8dfca9f20 100755 --- a/hibernate-core/src/main/java/org/hibernate/internal/StatelessSessionImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/internal/StatelessSessionImpl.java @@ -30,8 +30,6 @@ import java.util.List; import java.util.Map; -import org.jboss.logging.Logger; - import org.hibernate.CacheMode; import org.hibernate.ConnectionReleaseMode; import org.hibernate.Criteria; @@ -73,6 +71,7 @@ import org.hibernate.pretty.MessageHelper; import org.hibernate.proxy.HibernateProxy; import org.hibernate.type.Type; +import org.jboss.logging.Logger; /** * @author Gavin King @@ -618,13 +617,16 @@ public Criteria createCriteria(String entityName) { } @Override - public ScrollableResults scroll(CriteriaImpl criteria, ScrollMode scrollMode) { + public ScrollableResults scroll(Criteria criteria, ScrollMode scrollMode) { + // TODO: Is this guaranteed to always be CriteriaImpl? + CriteriaImpl criteriaImpl = (CriteriaImpl) criteria; + errorIfClosed(); - String entityName = criteria.getEntityOrClassName(); + String entityName = criteriaImpl.getEntityOrClassName(); CriteriaLoader loader = new CriteriaLoader( getOuterJoinLoadable( entityName ), factory, - criteria, + criteriaImpl, entityName, getLoadQueryInfluencers() ); @@ -633,9 +635,12 @@ public ScrollableResults scroll(CriteriaImpl criteria, ScrollMode scrollMode) { @Override @SuppressWarnings( {"unchecked"}) - public List list(CriteriaImpl criteria) throws HibernateException { + public List list(Criteria criteria) throws HibernateException { + // TODO: Is this guaranteed to always be CriteriaImpl? + CriteriaImpl criteriaImpl = (CriteriaImpl) criteria; + errorIfClosed(); - String[] implementors = factory.getImplementors( criteria.getEntityOrClassName() ); + String[] implementors = factory.getImplementors( criteriaImpl.getEntityOrClassName() ); int size = implementors.length; CriteriaLoader[] loaders = new CriteriaLoader[size]; @@ -643,7 +648,7 @@ public List list(CriteriaImpl criteria) throws HibernateException { loaders[i] = new CriteriaLoader( getOuterJoinLoadable( implementors[i] ), factory, - criteria, + criteriaImpl, implementors[i], getLoadQueryInfluencers() ); diff --git a/hibernate-core/src/main/java/org/hibernate/internal/util/ReflectHelper.java b/hibernate-core/src/main/java/org/hibernate/internal/util/ReflectHelper.java index 7048fe371c1a..f26659108239 100644 --- a/hibernate-core/src/main/java/org/hibernate/internal/util/ReflectHelper.java +++ b/hibernate-core/src/main/java/org/hibernate/internal/util/ReflectHelper.java @@ -72,6 +72,9 @@ public final class ReflectHelper { OBJECT_EQUALS = eq; OBJECT_HASHCODE = hash; } + + // TODO: Better way to do this? + public static ClassLoader overridenClassLoader = null; /** * Disallow instantiation of ReflectHelper. @@ -160,9 +163,14 @@ public static boolean implementsInterface(Class clazz, Class intf) { */ public static Class classForName(String name, Class caller) throws ClassNotFoundException { try { - ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader(); - if ( contextClassLoader != null ) { - return contextClassLoader.loadClass( name ); + if (overridenClassLoader != null) { + return overridenClassLoader.loadClass( name ); + } + else { + ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader(); + if ( contextClassLoader != null ) { + return contextClassLoader.loadClass( name ); + } } } catch ( Throwable ignore ) { @@ -182,9 +190,14 @@ public static Class classForName(String name, Class caller) throws ClassNotFound */ public static Class classForName(String name) throws ClassNotFoundException { try { - ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader(); - if ( contextClassLoader != null ) { - return contextClassLoader.loadClass(name); + if (overridenClassLoader != null) { + return overridenClassLoader.loadClass( name ); + } + else { + ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader(); + if ( contextClassLoader != null ) { + return contextClassLoader.loadClass(name); + } } } catch ( Throwable ignore ) { diff --git a/hibernate-ehcache/hibernate-ehcache.gradle b/hibernate-ehcache/hibernate-ehcache.gradle index 24b887f9d7f6..0f867673eb29 100644 --- a/hibernate-ehcache/hibernate-ehcache.gradle +++ b/hibernate-ehcache/hibernate-ehcache.gradle @@ -4,3 +4,10 @@ dependencies { testCompile project( ':hibernate-testing' ) } + +jar { + manifest { + instruction 'Bundle-Description', 'Hibernate ORM EHCache' + instruction 'Bundle-SymbolicName', 'org.hibernate.ehcache' + } +} \ No newline at end of file diff --git a/hibernate-entitymanager/hibernate-entitymanager.gradle b/hibernate-entitymanager/hibernate-entitymanager.gradle index 393f8c9b1083..18545da54aa4 100644 --- a/hibernate-entitymanager/hibernate-entitymanager.gradle +++ b/hibernate-entitymanager/hibernate-entitymanager.gradle @@ -16,6 +16,25 @@ dependencies { testRuntime( libraries.validator ) } +jar { + manifest { + instruction 'Bundle-Description', 'Hibernate ORM JPA Entity Manager' + instruction 'Bundle-SymbolicName', 'org.hibernate.entitymanager' + + // A cdi-api OSGi bundle does not currently exist. For now, explicitly + // ignore its packages. This will only cause issues if an app tries + // to use the BeanManagerListenerFactory functionality. + // NOTE: The "!" negates the package, keeping it out of Import-Package + // and including it in Ignore-Package. Also note that '*' does not mean + // * will occur. This is simply a + // BND instruction -- the auto-discovery of imported packages still + // occurs. + instruction 'Import-Package', + '!javax.enterprise*', + '*' + } +} + //////////////////////////////////////////////////////////////////////////////////////////////////////// // JPA model-gen set up //////////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/hibernate-entitymanager/src/main/java/org/hibernate/ejb/Ejb3Configuration.java b/hibernate-entitymanager/src/main/java/org/hibernate/ejb/Ejb3Configuration.java index 4accb666bf5c..ec71e79f6f40 100644 --- a/hibernate-entitymanager/src/main/java/org/hibernate/ejb/Ejb3Configuration.java +++ b/hibernate-entitymanager/src/main/java/org/hibernate/ejb/Ejb3Configuration.java @@ -169,6 +169,12 @@ public void handleEntityNotFound(String entityName, Serializable id) { public Ejb3Configuration() { + this(null); + } + + + public Ejb3Configuration(ClassLoader overridenClassLoader) { + this.overridenClassLoader = overridenClassLoader; cfg = new Configuration(); cfg.setEntityNotFoundDelegate( ejb3EntityNotFoundDelegate ); } @@ -541,20 +547,27 @@ public Ejb3Configuration configure(PersistenceUnitInfo info, Map integration) { // set the classloader, passed in by the container in info, to set as the TCCL so that // Hibernate uses it to properly resolve class references. - if ( info.getClassLoader() == null ) { - throw new IllegalStateException( - "[PersistenceUnit: " + info.getPersistenceUnitName() == null ? "" : info.getPersistenceUnitName() - + "] " + "PersistenceUnitInfo.getClassLoader() id null" ); - } Thread thread = Thread.currentThread(); ClassLoader contextClassLoader = thread.getContextClassLoader(); - boolean sameClassLoader = info.getClassLoader().equals( contextClassLoader ); - if ( ! sameClassLoader ) { - overridenClassLoader = info.getClassLoader(); + boolean sameClassLoader = true; + if (overridenClassLoader != null) { thread.setContextClassLoader( overridenClassLoader ); + sameClassLoader = false; } else { - overridenClassLoader = null; + if ( info.getClassLoader() == null ) { + throw new IllegalStateException( + "[PersistenceUnit: " + info.getPersistenceUnitName() == null ? "" : info.getPersistenceUnitName() + + "] " + "PersistenceUnitInfo.getClassLoader() id null" ); + } + sameClassLoader = info.getClassLoader().equals( contextClassLoader ); + if ( ! sameClassLoader ) { + overridenClassLoader = info.getClassLoader(); + thread.setContextClassLoader( overridenClassLoader ); + } + else { + overridenClassLoader = null; + } } // Best I can tell, 'workingVars' is some form of additional configuration contract. @@ -848,6 +861,12 @@ private void scanForClasses(ScanningContext scanningContext, List packag LOG.containerProvidingNullPersistenceUnitRootUrl(); return; } + if ( scanningContext.url.getProtocol().equalsIgnoreCase( "bundle" ) ) { + // TODO: Is there a way to scan the root bundle URL in OSGi containers? + // Although the URL provides a stream handler that works for finding + // resources in a specific Bundle, the root one does not work. + return; + } try { addScannedEntries( scanningContext, entities, packages, hbmFiles, null ); } @@ -898,6 +917,10 @@ public EntityManagerFactory buildEntityManagerFactory(BootstrapServiceRegistryBu thread = Thread.currentThread(); contextClassLoader = thread.getContextClassLoader(); thread.setContextClassLoader( overridenClassLoader ); + builder.withApplicationClassLoader( overridenClassLoader ); + builder.withEnvironmentClassLoader( overridenClassLoader ); + builder.withHibernateClassLoader( overridenClassLoader ); + builder.withResourceClassLoader( overridenClassLoader ); } try { diff --git a/hibernate-entitymanager/src/main/java/org/hibernate/ejb/HibernatePersistence.java b/hibernate-entitymanager/src/main/java/org/hibernate/ejb/HibernatePersistence.java index f3c32040fd7c..e985566ab674 100755 --- a/hibernate-entitymanager/src/main/java/org/hibernate/ejb/HibernatePersistence.java +++ b/hibernate-entitymanager/src/main/java/org/hibernate/ejb/HibernatePersistence.java @@ -24,6 +24,7 @@ package org.hibernate.ejb; import java.util.Map; + import javax.persistence.EntityManagerFactory; import javax.persistence.spi.LoadState; import javax.persistence.spi.PersistenceProvider; @@ -38,8 +39,9 @@ * @author Gavin King */ public class HibernatePersistence extends AvailableSettings implements PersistenceProvider { + private final PersistenceUtilHelper.MetadataCache cache = new PersistenceUtilHelper.MetadataCache(); - + /** * Get an entity manager factory by its entity manager name, using the specified * properties (they override any found in the peristence.xml file). diff --git a/hibernate-entitymanager/src/main/java/org/hibernate/engine/spi/EJB3CascadeStyle.java b/hibernate-entitymanager/src/main/java/org/hibernate/ejb/engine/spi/EJB3CascadeStyle.java similarity index 90% rename from hibernate-entitymanager/src/main/java/org/hibernate/engine/spi/EJB3CascadeStyle.java rename to hibernate-entitymanager/src/main/java/org/hibernate/ejb/engine/spi/EJB3CascadeStyle.java index b5903bed8d69..5616edd73908 100644 --- a/hibernate-entitymanager/src/main/java/org/hibernate/engine/spi/EJB3CascadeStyle.java +++ b/hibernate-entitymanager/src/main/java/org/hibernate/ejb/engine/spi/EJB3CascadeStyle.java @@ -19,7 +19,12 @@ * 51 Franklin Street, Fifth Floor * Boston, MA 02110-1301 USA */ -package org.hibernate.engine.spi; +package org.hibernate.ejb.engine.spi; + +import static org.hibernate.engine.spi.CascadeStyle.STYLES; + +import org.hibernate.engine.spi.CascadeStyle; +import org.hibernate.engine.spi.CascadingAction; /** * Becasue CascadeStyle is not opened and package protected, diff --git a/hibernate-entitymanager/src/main/java/org/hibernate/engine/spi/EJB3CascadingAction.java b/hibernate-entitymanager/src/main/java/org/hibernate/ejb/engine/spi/EJB3CascadingAction.java similarity index 96% rename from hibernate-entitymanager/src/main/java/org/hibernate/engine/spi/EJB3CascadingAction.java rename to hibernate-entitymanager/src/main/java/org/hibernate/ejb/engine/spi/EJB3CascadingAction.java index d86641a1ba5c..091d3979bbd6 100644 --- a/hibernate-entitymanager/src/main/java/org/hibernate/engine/spi/EJB3CascadingAction.java +++ b/hibernate-entitymanager/src/main/java/org/hibernate/ejb/engine/spi/EJB3CascadingAction.java @@ -19,7 +19,7 @@ * 51 Franklin Street, Fifth Floor * Boston, MA 02110-1301 USA */ -package org.hibernate.engine.spi; +package org.hibernate.ejb.engine.spi; import java.util.Iterator; import java.util.Map; @@ -28,6 +28,7 @@ import org.hibernate.HibernateException; import org.hibernate.ejb.internal.EntityManagerMessageLogger; +import org.hibernate.engine.spi.CascadingAction; import org.hibernate.event.spi.EventSource; import org.hibernate.type.CollectionType; diff --git a/hibernate-entitymanager/src/main/java/org/hibernate/ejb/event/EJB3PersistEventListener.java b/hibernate-entitymanager/src/main/java/org/hibernate/ejb/event/EJB3PersistEventListener.java index 9025130e7e80..f2349ce1cbe3 100644 --- a/hibernate-entitymanager/src/main/java/org/hibernate/ejb/event/EJB3PersistEventListener.java +++ b/hibernate-entitymanager/src/main/java/org/hibernate/ejb/event/EJB3PersistEventListener.java @@ -25,9 +25,9 @@ import java.io.Serializable; +import org.hibernate.ejb.engine.spi.EJB3CascadeStyle; +import org.hibernate.ejb.engine.spi.EJB3CascadingAction; import org.hibernate.engine.spi.CascadingAction; -import org.hibernate.engine.spi.EJB3CascadeStyle; -import org.hibernate.engine.spi.EJB3CascadingAction; import org.hibernate.event.internal.DefaultPersistEventListener; import org.hibernate.event.spi.EventSource; diff --git a/hibernate-envers/hibernate-envers.gradle b/hibernate-envers/hibernate-envers.gradle index 84e22c0cc018..611e7bad9bb5 100644 --- a/hibernate-envers/hibernate-envers.gradle +++ b/hibernate-envers/hibernate-envers.gradle @@ -37,3 +37,9 @@ task generateJpaMetamodelClasses(type: Compile) { } compileJava.dependsOn generateJpaMetamodelClasses +jar { + manifest { + instruction 'Bundle-Description', 'Hibernate ORM Envers' + instruction 'Bundle-SymbolicName', 'org.hibernate.envers' + } +} diff --git a/hibernate-envers/src/main/java/org/hibernate/envers/entities/mapper/relation/lazy/AbstractDelegateSessionImplementor.java b/hibernate-envers/src/main/java/org/hibernate/envers/entities/mapper/relation/lazy/AbstractDelegateSessionImplementor.java index da282705bd3d..59f2a92fa8ff 100644 --- a/hibernate-envers/src/main/java/org/hibernate/envers/entities/mapper/relation/lazy/AbstractDelegateSessionImplementor.java +++ b/hibernate-envers/src/main/java/org/hibernate/envers/entities/mapper/relation/lazy/AbstractDelegateSessionImplementor.java @@ -30,6 +30,7 @@ import java.util.Map; import org.hibernate.CacheMode; +import org.hibernate.Criteria; import org.hibernate.FlushMode; import org.hibernate.HibernateException; import org.hibernate.Interceptor; @@ -48,7 +49,6 @@ import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.engine.spi.SessionImplementor; import org.hibernate.engine.transaction.spi.TransactionCoordinator; -import org.hibernate.internal.CriteriaImpl; import org.hibernate.loader.custom.CustomQuery; import org.hibernate.persister.entity.EntityPersister; import org.hibernate.type.Type; @@ -160,12 +160,12 @@ public ScrollableResults scroll(String query, QueryParameters queryParameters) t } @Override - public ScrollableResults scroll(CriteriaImpl criteria, ScrollMode scrollMode) { + public ScrollableResults scroll(Criteria criteria, ScrollMode scrollMode) { return delegate.scroll(criteria, scrollMode); } @Override - public List list(CriteriaImpl criteria) { + public List list(Criteria criteria) { return delegate.list(criteria); } diff --git a/hibernate-infinispan/hibernate-infinispan.gradle b/hibernate-infinispan/hibernate-infinispan.gradle index 298883e5f14d..69ab1359fa6b 100644 --- a/hibernate-infinispan/hibernate-infinispan.gradle +++ b/hibernate-infinispan/hibernate-infinispan.gradle @@ -40,4 +40,11 @@ task sourcesTestJar(type: Jar, dependsOn:classes) { } artifacts.archives packageTests -artifacts.archives sourcesTestJar \ No newline at end of file +artifacts.archives sourcesTestJar + +jar { + manifest { + instruction 'Bundle-Description', 'Hibernate ORM Infinispan' + instruction 'Bundle-SymbolicName', 'org.hibernate.infinispan' + } +} diff --git a/hibernate-osgi/hibernate-osgi.gradle b/hibernate-osgi/hibernate-osgi.gradle new file mode 100644 index 000000000000..a9c0ce376ddd --- /dev/null +++ b/hibernate-osgi/hibernate-osgi.gradle @@ -0,0 +1,13 @@ +dependencies { + compile( project( ':hibernate-core' ) ) + compile( project( ':hibernate-entitymanager' ) ) + compile( "org.osgi:org.osgi.core:4.2.0" ) +} + +jar { + manifest { + instruction 'Bundle-Activator', 'org.hibernate.osgi.HibernateBundleActivator' + instruction 'Bundle-Description', 'Hibernate ORM OSGi' + instruction 'Bundle-SymbolicName', 'org.hibernate.osgi' + } +} diff --git a/hibernate-osgi/src/main/java/org/hibernate/osgi/HibernateBundleActivator.java b/hibernate-osgi/src/main/java/org/hibernate/osgi/HibernateBundleActivator.java new file mode 100644 index 000000000000..f974264fac4d --- /dev/null +++ b/hibernate-osgi/src/main/java/org/hibernate/osgi/HibernateBundleActivator.java @@ -0,0 +1,113 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2010, Red Hat Inc. 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 Inc. + * + * 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.osgi; + +import java.util.Map; +import java.util.Properties; + +import javax.persistence.EntityManagerFactory; +import javax.persistence.spi.PersistenceProvider; +import javax.persistence.spi.PersistenceUnitInfo; +import javax.persistence.spi.PersistenceUnitTransactionType; + +import org.hibernate.cfg.AvailableSettings; +import org.hibernate.ejb.Ejb3Configuration; +import org.hibernate.ejb.HibernatePersistence; +import org.hibernate.internal.util.ReflectHelper; +import org.osgi.framework.Bundle; +import org.osgi.framework.BundleActivator; +import org.osgi.framework.BundleContext; +import org.osgi.framework.BundleEvent; +import org.osgi.framework.BundleListener; + +/** + * @author Brett Meyer + * @author Martin Neimeier + */ +public class HibernateBundleActivator + extends HibernatePersistence + implements BundleActivator, /*ServiceListener,*/ BundleListener { + + private BundleContext context; + + private OsgiClassLoader osgiClassLoader; + + @Override + public void start(BundleContext context) throws Exception { + + this.context = context; + + // register this instance as a bundle listener to get informed about all + // bundle live cycle events + context.addBundleListener(this); + + osgiClassLoader = new OsgiClassLoader(); + ReflectHelper.overridenClassLoader = osgiClassLoader; + + for ( Bundle bundle : context.getBundles() ) { + handleBundleChange( bundle ); + } + + Properties properties = new Properties(); + properties.put( "javax.persistence.provider", HibernateBundleActivator.class.getName() ); + context.registerService( + PersistenceProvider.class.getName(), + this, + properties + ); + } + + @Override + public void stop(BundleContext context) throws Exception { + context.removeBundleListener(this); + + // Nothing else to do. When re-activated, this Activator will be + // re-started and the EMF re-created. + } + + @Override + public void bundleChanged(BundleEvent event) { + handleBundleChange( event.getBundle() ); + + } + + private void handleBundleChange( Bundle bundle ) { + if ( bundle.getState() == Bundle.ACTIVE ) { + osgiClassLoader.registerBundle(bundle); + } else { + osgiClassLoader.unregisterBundle(bundle); + } + } + + @Override + public EntityManagerFactory createContainerEntityManagerFactory(PersistenceUnitInfo info, Map map) { + Ejb3Configuration cfg = new Ejb3Configuration(osgiClassLoader); + if ( info.getTransactionType().equals( PersistenceUnitTransactionType.JTA ) ) { + map.put( AvailableSettings.JTA_PLATFORM, new OsgiJtaPlatform( context ) ); + } + Ejb3Configuration configured = cfg.configure( info, map ); + return configured != null ? configured.buildEntityManagerFactory() : null; + } + +} \ No newline at end of file diff --git a/hibernate-osgi/src/main/java/org/hibernate/osgi/OsgiClassLoader.java b/hibernate-osgi/src/main/java/org/hibernate/osgi/OsgiClassLoader.java new file mode 100644 index 000000000000..24bee34bbafd --- /dev/null +++ b/hibernate-osgi/src/main/java/org/hibernate/osgi/OsgiClassLoader.java @@ -0,0 +1,168 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2010, Red Hat Inc. 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 Inc. + * + * 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.osgi; + +import java.net.URL; +import java.util.Enumeration; +import java.util.HashMap; + +import org.osgi.framework.Bundle; + +/** + * Custom OSGI ClassLoader helper which knows all the "interesting" bundles and + * encapsulates the OSGi related capabilities. + * + * @author Brett Meyer + */ +public class OsgiClassLoader extends ClassLoader { + + private HashMap bundles; + + public OsgiClassLoader() { + bundles = new HashMap(); + } + + /** + * Load the class and break on first found match. + * TODO: Should this throw a different exception or warn if multiple + * classes were found? Naming collisions can and do happen in OSGi... + */ + @SuppressWarnings("rawtypes") + @Override + protected Class findClass(String name) throws ClassNotFoundException { + // TODO: This is horrible -- we shouldn't iterate over all the + // classloaders every time we need to construct an entity, etc. Instead, + // keep references to all classes/resources found in active bundles + // in memory? Find a way to identify what we "care about" and keep + // only those? Discover them the first time and then cache the + // reference? + for ( Bundle bundle : bundles.values() ) { + try { + Class clazz = bundle.loadClass( name ); + if ( clazz != null ) { + return clazz; + } + } + catch ( Exception ignore ) { + } + } + + throw new ClassNotFoundException( "Could not load requested class : " + name ); + } + + /** + * Load the class and break on first found match. + * TODO: Should this throw a different exception or warn if multiple + * classes were found? Naming collisions can and do happen in OSGi... + */ + @Override + protected URL findResource(String name) { + // TODO: This is horrible -- we shouldn't iterate over all the + // classloaders every time we need to construct an entity, etc. Instead, + // keep references to all classes/resources found in active bundles + // in memory? Find a way to identify what we "care about" and keep + // only those? Discover them the first time and then cache the + // reference? + for ( Bundle bundle : bundles.values() ) { + try { + URL resource = bundle.getResource( name ); + if ( resource != null ) { + return resource; + } + } + catch ( Exception ignore ) { + } + } + // TODO: Error? + return null; + } + + /** + * Load the class and break on first found match. + * TODO: Should this throw a different exception or warn if multiple + * classes were found? Naming collisions can and do happen in OSGi... + */ + @SuppressWarnings("unchecked") + @Override + protected Enumeration findResources(String name) { + // TODO: This is horrible -- we shouldn't iterate over all the + // classloaders every time we need to construct an entity, etc. Instead, + // keep references to all classes/resources found in active bundles + // in memory? Find a way to identify what we "care about" and keep + // only those? Discover them the first time and then cache the + // reference? + for ( Bundle bundle : bundles.values() ) { + try { + Enumeration resources = bundle.getResources( name ); + if ( resources != null ) { + return resources; + } + } + catch ( Exception ignore ) { + } + } + // TODO: Error? + return null; + } + + /** + * Register the bundle with this class loader + */ + public void registerBundle(Bundle bundle) { + if ( bundle != null ) { + synchronized ( bundles ) { + // create a bundle classloader and add it to the list of + // classloaders + String key = getBundleKey( bundle ); + if ( !bundles.containsKey( key ) ) { + bundles.put( key, bundle ); + } + } + } + } + + /** + * Unregister the bundle from this class loader + */ + public void unregisterBundle(Bundle bundle) { + if ( bundle != null ) { + synchronized ( bundles ) { + // remove a bundle classloader for a given bundle + String key = getBundleKey( bundle ); + if ( bundles.containsKey( key ) ) { + bundles.remove( key ); + } + } + } + } + + public void clear() { + bundles.clear(); + } + + protected static String getBundleKey(Bundle bundle) { + return bundle.getSymbolicName() + " " + bundle.getVersion().toString(); + } + +} diff --git a/hibernate-osgi/src/main/java/org/hibernate/osgi/OsgiJtaPlatform.java b/hibernate-osgi/src/main/java/org/hibernate/osgi/OsgiJtaPlatform.java new file mode 100644 index 000000000000..09e7524fda2f --- /dev/null +++ b/hibernate-osgi/src/main/java/org/hibernate/osgi/OsgiJtaPlatform.java @@ -0,0 +1,84 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * JBoss, Home of Professional Open Source + * Copyright 2013 Red Hat Inc. and/or its affiliates and other contributors + * as indicated by the @authors tag. All rights reserved. + * See the copyright.txt in the distribution for a + * full listing of individual contributors. + * + * 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, v. 2.1. + * This program is distributed in the hope that it will be useful, but WITHOUT A + * 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, + * v.2.1 along with this distribution; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ +package org.hibernate.osgi; + +import javax.transaction.Synchronization; +import javax.transaction.SystemException; +import javax.transaction.Transaction; +import javax.transaction.TransactionManager; +import javax.transaction.UserTransaction; + +import org.hibernate.service.jta.platform.spi.JtaPlatform; +import org.osgi.framework.BundleContext; +import org.osgi.framework.ServiceReference; + +/** + * Offers the JTA Platform provided by the OSGi container. The Enterprise + * OSGi spec requires all containers to register UserTransaction + * and TransactionManager OSGi services. + * + * @author Brett Meyer + */ +public class OsgiJtaPlatform implements JtaPlatform { + + private static final long serialVersionUID = 1L; + + private BundleContext bundleContext; + + public OsgiJtaPlatform(BundleContext bundleContext) { + this.bundleContext = bundleContext; + } + + @Override + public TransactionManager retrieveTransactionManager() { + ServiceReference sr = bundleContext.getServiceReference( TransactionManager.class.getName() ); + return (TransactionManager) bundleContext.getService( sr ); + } + + @Override + public UserTransaction retrieveUserTransaction() { + ServiceReference sr = bundleContext.getServiceReference( UserTransaction.class.getName() ); + return (UserTransaction) bundleContext.getService( sr ); + } + + @Override + public Object getTransactionIdentifier(Transaction transaction) { + // AbstractJtaPlatform just uses the transaction itself. + return transaction; + } + + @Override + public boolean canRegisterSynchronization() { + // TODO + return false; + } + + @Override + public void registerSynchronization(Synchronization synchronization) { + // TODO + } + + @Override + public int getCurrentStatus() throws SystemException { + return retrieveTransactionManager().getStatus(); + } + +} diff --git a/hibernate-proxool/hibernate-proxool.gradle b/hibernate-proxool/hibernate-proxool.gradle index f57746b053ff..c6b0bcb1331f 100644 --- a/hibernate-proxool/hibernate-proxool.gradle +++ b/hibernate-proxool/hibernate-proxool.gradle @@ -1,6 +1,12 @@ - dependencies { compile project( ':hibernate-core' ) compile( libraries.proxool ) testCompile project( ':hibernate-testing' ) } + +jar { + manifest { + instruction 'Bundle-Description', 'Hibernate ORM Proxool' + instruction 'Bundle-SymbolicName', 'org.hibernate.proxool' + } +} \ No newline at end of file diff --git a/hibernate-testing/hibernate-testing.gradle b/hibernate-testing/hibernate-testing.gradle index 9a5c3e2c5441..28a3dd3a7658 100644 --- a/hibernate-testing/hibernate-testing.gradle +++ b/hibernate-testing/hibernate-testing.gradle @@ -8,4 +8,11 @@ dependencies { compile ( libraries.jboss_jta ) { transitive=false; } +} + +jar { + manifest { + instruction 'Bundle-Description', 'Hibernate ORM Testing' + instruction 'Bundle-SymbolicName', 'org.hibernate.testing' + } } \ No newline at end of file diff --git a/libraries.gradle b/libraries.gradle index 289627b5668f..6b46efe33ae1 100644 --- a/libraries.gradle +++ b/libraries.gradle @@ -32,7 +32,7 @@ libraries = [ jpa: 'org.hibernate.javax.persistence:hibernate-jpa-2.0-api:1.0.1.Final', jta: 'org.jboss.spec.javax.transaction:jboss-transaction-api_1.1_spec:1.0.0.Final', validation: 'javax.validation:validation-api:1.0.0.GA', - jacc: 'org.jboss.spec.javax.security.jacc:jboss-jacc-api_1.4_spec:1.0.0.Final', + jacc: 'org.jboss.spec.javax.security.jacc:jboss-jacc-api_1.4_spec:1.0.2.Final', // logging logging: 'org.jboss.logging:jboss-logging:3.1.0.GA', @@ -77,8 +77,7 @@ libraries = [ // ~~~~~~~~~~~~~~~~~~~~~~~~~~~ c3p0 c3p0: "c3p0:c3p0:0.9.1", ehcache: "net.sf.ehcache:ehcache-core:2.4.3", - proxool: "proxool:proxool:0.8.3", - + proxool: "proxool:proxool:0.8.3" ] } diff --git a/release/release.gradle b/release/release.gradle index cac16e19491a..d86a2427d660 100644 --- a/release/release.gradle +++ b/release/release.gradle @@ -1,5 +1,6 @@ apply plugin: 'base' apply plugin: 'idea' +apply from: "../utilities.gradle" buildDir = "target" @@ -83,21 +84,6 @@ task aggregateJavadocs(type: Javadoc) { } } -String determinePackageName(SourceDirectorySet sourceDirectorySet, File javaFile) { - final javaFileAbsolutePath = javaFile.absolutePath; - for ( File sourceDirectory : sourceDirectorySet.srcDirs ) { - final String sourceDirectoryAbsolutePath = sourceDirectory.absolutePath; - if ( javaFileAbsolutePath.startsWith( sourceDirectoryAbsolutePath ) ) { - final String javaFileRelativePath = javaFileAbsolutePath.substring( - sourceDirectoryAbsolutePath.length() + 1, - javaFileAbsolutePath.lastIndexOf( File.separator ) - ); - return javaFileRelativePath.replace( File.separator, "." ); - } - } - throw new RuntimeException( "ugh" ); -} - aggregateJavadocs.doLast { copy { from new File( projectDir, 'src/javadoc/images' ) diff --git a/settings.gradle b/settings.gradle index 2e17736604fa..c6fb9085db72 100644 --- a/settings.gradle +++ b/settings.gradle @@ -3,6 +3,8 @@ include 'hibernate-testing' include 'hibernate-entitymanager' include 'hibernate-envers' +include 'hibernate-osgi' + include 'hibernate-c3p0' include 'hibernate-proxool' diff --git a/utilities.gradle b/utilities.gradle new file mode 100644 index 000000000000..1154ea1986cd --- /dev/null +++ b/utilities.gradle @@ -0,0 +1,49 @@ + +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2012, Red Hat Inc. 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 Inc. + * + * 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 + */ + +apply plugin: UtilitiesPlugin + +class UtilitiesPlugin implements Plugin { + def void apply(Object project) { + project.convention.plugins.utilities = new UtilitiesPluginDef() + } +} + +class UtilitiesPluginDef { + public String determinePackageName(SourceDirectorySet sourceDirectorySet, File javaFile) { + final javaFileAbsolutePath = javaFile.absolutePath; + for ( File sourceDirectory : sourceDirectorySet.srcDirs ) { + final String sourceDirectoryAbsolutePath = sourceDirectory.absolutePath; + if ( javaFileAbsolutePath.startsWith( sourceDirectoryAbsolutePath ) ) { + final String javaFileRelativePath = javaFileAbsolutePath.substring( + sourceDirectoryAbsolutePath.length() + 1, + javaFileAbsolutePath.lastIndexOf( File.separator ) + ); + return javaFileRelativePath.replace( File.separator, "." ); + } + } + throw new RuntimeException( "ugh" ); + } +}