From 56867417e283b235aa0832affd43207cb9ea5327 Mon Sep 17 00:00:00 2001 From: Brett Meyer Date: Wed, 23 Jan 2013 18:22:03 -0500 Subject: [PATCH] HHH-7527 Enterprise OSGi JPA support --- build.gradle | 57 +++++- hibernate-c3p0/hibernate-c3p0.gradle | 7 + hibernate-core/hibernate-core.gradle | 13 ++ .../BootstrapServiceRegistryBuilder.java | 25 ++- .../internal/StrategySelectorBuilder.java | 7 +- .../engine/spi/SessionImplementor.java | 5 +- .../org/hibernate/internal/SessionImpl.java | 24 ++- .../internal/StatelessSessionImpl.java | 21 ++- hibernate-ehcache/hibernate-ehcache.gradle | 7 + .../hibernate-entitymanager.gradle | 19 ++ .../jpa/HibernatePersistenceProvider.java | 10 +- .../EntityManagerFactoryBuilderImpl.java | 32 +++- .../org/hibernate/jpa/boot/spi/Bootstrap.java | 17 +- hibernate-envers/hibernate-envers.gradle | 6 + .../AbstractDelegateSessionImplementor.java | 6 +- .../hibernate-infinispan.gradle | 7 + hibernate-osgi/hibernate-osgi.gradle | 13 ++ .../osgi/HibernateBundleActivator.java | 109 ++++++++++++ .../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 | 4 +- release/release.gradle | 16 +- settings.gradle | 2 + utilities.gradle | 49 +++++ 26 files changed, 662 insertions(+), 61 deletions(-) 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 f768fee861..3b2b459e1b 100644 --- a/build.gradle +++ b/build.gradle @@ -68,6 +68,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 { @@ -169,13 +171,54 @@ 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 -> + // - org.hibernate.boot.registry.classloading.internal + // until EntityManagerFactoryBuilderImpl no longer imports ClassLoaderServiceImpl + // - .util for external module use (especially envers) + final String[] temporaryExports = [ + 'org.hibernate.boot.registry.classloading.internal', + '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 { systemProperties['hibernate.test.validatefailureexpected'] = true diff --git a/hibernate-c3p0/hibernate-c3p0.gradle b/hibernate-c3p0/hibernate-c3p0.gradle index c68d582ff0..3d19fe5db2 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 620c95f837..0d842ce8e6 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/boot/registry/BootstrapServiceRegistryBuilder.java b/hibernate-core/src/main/java/org/hibernate/boot/registry/BootstrapServiceRegistryBuilder.java index eb7685f634..7bbad4a498 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/registry/BootstrapServiceRegistryBuilder.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/registry/BootstrapServiceRegistryBuilder.java @@ -33,12 +33,14 @@ import org.hibernate.boot.registry.selector.AvailabilityAnnouncer; import org.hibernate.integrator.internal.IntegratorServiceImpl; import org.hibernate.integrator.spi.Integrator; import org.hibernate.boot.registry.classloading.internal.ClassLoaderServiceImpl; +import org.hibernate.boot.registry.classloading.spi.ClassLoaderService; import org.hibernate.boot.registry.selector.internal.StrategySelectorBuilder; /** * Builder for bootstrap {@link org.hibernate.service.ServiceRegistry} instances. * * @author Steve Ebersole + * @author Brett Meyer * * @see BootstrapServiceRegistryImpl * @see StandardServiceRegistryBuilder#StandardServiceRegistryBuilder(org.hibernate.boot.registry.BootstrapServiceRegistry) @@ -46,8 +48,10 @@ import org.hibernate.boot.registry.selector.internal.StrategySelectorBuilder; public class BootstrapServiceRegistryBuilder { private final LinkedHashSet providedIntegrators = new LinkedHashSet(); private List providedClassLoaders; - + private ClassLoaderService providedClassLoaderService; private StrategySelectorBuilder strategySelectorBuilder = new StrategySelectorBuilder(); + + /** * Add an {@link Integrator} to be applied to the bootstrap registry. @@ -75,6 +79,18 @@ public class BootstrapServiceRegistryBuilder { return this; } + /** + * Adds a provided {@link ClassLoaderService} for use in class-loading and resource-lookup + * + * @param classLoader The class loader to use + * + * @return {@code this}, for method chaining + */ + public BootstrapServiceRegistryBuilder with(ClassLoaderService classLoaderService) { + providedClassLoaderService = classLoaderService; + return this; + } + /** * Applies the specified {@link ClassLoader} as the application class loader for the bootstrap registry * @@ -171,7 +187,12 @@ public class BootstrapServiceRegistryBuilder { * @return The built bootstrap registry */ public BootstrapServiceRegistry build() { - final ClassLoaderServiceImpl classLoaderService = new ClassLoaderServiceImpl( providedClassLoaders ); + final ClassLoaderService classLoaderService; + if ( providedClassLoaderService == null ) { + classLoaderService = new ClassLoaderServiceImpl( providedClassLoaders ); + } else { + classLoaderService = providedClassLoaderService; + } final IntegratorServiceImpl integratorService = new IntegratorServiceImpl( providedIntegrators, diff --git a/hibernate-core/src/main/java/org/hibernate/boot/registry/selector/internal/StrategySelectorBuilder.java b/hibernate-core/src/main/java/org/hibernate/boot/registry/selector/internal/StrategySelectorBuilder.java index d24b50f3f1..b248afba3b 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/registry/selector/internal/StrategySelectorBuilder.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/registry/selector/internal/StrategySelectorBuilder.java @@ -26,9 +26,7 @@ package org.hibernate.boot.registry.selector.internal; import java.util.ArrayList; import java.util.List; -import org.jboss.logging.Logger; - -import org.hibernate.boot.registry.classloading.internal.ClassLoaderServiceImpl; +import org.hibernate.boot.registry.classloading.spi.ClassLoaderService; import org.hibernate.boot.registry.selector.Availability; import org.hibernate.boot.registry.selector.AvailabilityAnnouncer; import org.hibernate.boot.registry.selector.SimpleAvailabilityImpl; @@ -97,6 +95,7 @@ import org.hibernate.engine.transaction.spi.TransactionFactory; import org.hibernate.hql.spi.MultiTableBulkIdStrategy; import org.hibernate.hql.spi.PersistentTableBulkIdStrategy; import org.hibernate.hql.spi.TemporaryTableBulkIdStrategy; +import org.jboss.logging.Logger; /** * @author Steve Ebersole @@ -127,7 +126,7 @@ public class StrategySelectorBuilder { explicitAvailabilities.add( availability ); } - public StrategySelector buildSelector(ClassLoaderServiceImpl classLoaderService) { + public StrategySelector buildSelector(ClassLoaderService classLoaderService) { StrategySelectorImpl strategySelector = new StrategySelectorImpl( classLoaderService ); // build the baseline... 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 658f58a930..498a838f37 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.List; 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 interface SessionImplementor extends Serializable, LobCreationContext { /** * 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 7030f5d3c8..64932898bc 100644 --- a/hibernate-core/src/main/java/org/hibernate/internal/SessionImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/internal/SessionImpl.java @@ -74,8 +74,6 @@ import org.hibernate.ScrollableResults; import org.hibernate.Session; import org.hibernate.SessionBuilder; import org.hibernate.SessionException; -import org.hibernate.procedure.ProcedureCall; -import org.hibernate.engine.spi.SessionOwner; import org.hibernate.SharedSessionBuilder; import org.hibernate.SimpleNaturalIdLoadAccess; import org.hibernate.Transaction; @@ -100,6 +98,7 @@ import org.hibernate.engine.spi.NonFlushedChanges; import org.hibernate.engine.spi.PersistenceContext; import org.hibernate.engine.spi.QueryParameters; import org.hibernate.engine.spi.SessionFactoryImplementor; +import org.hibernate.engine.spi.SessionOwner; import org.hibernate.engine.spi.Status; import org.hibernate.engine.transaction.internal.TransactionCoordinatorImpl; import org.hibernate.engine.transaction.spi.TransactionCoordinator; @@ -150,6 +149,7 @@ import org.hibernate.persister.collection.CollectionPersister; import org.hibernate.persister.entity.EntityPersister; import org.hibernate.persister.entity.OuterJoinLoadable; import org.hibernate.pretty.MessageHelper; +import org.hibernate.procedure.ProcedureCall; import org.hibernate.proxy.HibernateProxy; import org.hibernate.proxy.LazyInitializer; import org.hibernate.stat.SessionStatistics; @@ -1562,14 +1562,17 @@ public final class SessionImpl extends AbstractSessionImpl implements EventSourc 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() ); @@ -1583,8 +1586,11 @@ public final class SessionImpl extends AbstractSessionImpl implements EventSourc } } - 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() ); @@ -1592,7 +1598,7 @@ public final class SessionImpl extends AbstractSessionImpl implements EventSourc errorIfClosed(); checkTransactionSynchStatus(); - String[] implementors = factory.getImplementors( criteria.getEntityOrClassName() ); + String[] implementors = factory.getImplementors( criteriaImpl.getEntityOrClassName() ); int size = implementors.length; CriteriaLoader[] loaders = new CriteriaLoader[size]; @@ -1602,7 +1608,7 @@ public final class SessionImpl extends AbstractSessionImpl implements EventSourc 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 9ad53a566f..2ee8dfca9f 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.Iterator; 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.persister.entity.OuterJoinLoadable; 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 class StatelessSessionImpl extends AbstractSessionImpl implements Statele } @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 class StatelessSessionImpl extends AbstractSessionImpl implements Statele @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 class StatelessSessionImpl extends AbstractSessionImpl implements Statele loaders[i] = new CriteriaLoader( getOuterJoinLoadable( implementors[i] ), factory, - criteria, + criteriaImpl, implementors[i], getLoadQueryInfluencers() ); diff --git a/hibernate-ehcache/hibernate-ehcache.gradle b/hibernate-ehcache/hibernate-ehcache.gradle index 24b887f9d7..0f867673eb 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 617ce7a0d3..7266a4f652 100644 --- a/hibernate-entitymanager/hibernate-entitymanager.gradle +++ b/hibernate-entitymanager/hibernate-entitymanager.gradle @@ -21,6 +21,25 @@ dependencies { testRuntime( "org.jboss.ejb3:jboss-ejb3-api:3.1.0" ) } +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/jpa/HibernatePersistenceProvider.java b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/HibernatePersistenceProvider.java index 1e54878404..f04450bebb 100755 --- a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/HibernatePersistenceProvider.java +++ b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/HibernatePersistenceProvider.java @@ -23,15 +23,16 @@ */ package org.hibernate.jpa; +import java.util.Collections; +import java.util.List; +import java.util.Map; + import javax.persistence.EntityManagerFactory; import javax.persistence.PersistenceException; import javax.persistence.spi.LoadState; import javax.persistence.spi.PersistenceProvider; import javax.persistence.spi.PersistenceUnitInfo; import javax.persistence.spi.ProviderUtil; -import java.util.Collections; -import java.util.List; -import java.util.Map; import org.hibernate.jpa.boot.internal.ParsedPersistenceXmlDescriptor; import org.hibernate.jpa.boot.internal.PersistenceXmlParser; @@ -45,6 +46,7 @@ import org.hibernate.jpa.internal.util.PersistenceUtilHelper; * * @author Gavin King * @author Steve Ebersole + * @author Brett Meyer */ public class HibernatePersistenceProvider implements PersistenceProvider { @@ -138,4 +140,4 @@ public class HibernatePersistenceProvider implements PersistenceProvider { return providerUtil; } -} \ No newline at end of file +} diff --git a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/boot/internal/EntityManagerFactoryBuilderImpl.java b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/boot/internal/EntityManagerFactoryBuilderImpl.java index 46a3167632..2098a2908e 100644 --- a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/boot/internal/EntityManagerFactoryBuilderImpl.java +++ b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/boot/internal/EntityManagerFactoryBuilderImpl.java @@ -156,6 +156,8 @@ public class EntityManagerFactoryBuilderImpl implements EntityManagerFactoryBuil private Configuration hibernateConfiguration; private static EntityNotFoundDelegate jpaEntityNotFoundDelegate = new JpaEntityNotFoundDelegate(); + + private ClassLoader providedClassLoader; private static class JpaEntityNotFoundDelegate implements EntityNotFoundDelegate, Serializable { public void handleEntityNotFound(String entityName, Serializable id) { @@ -164,6 +166,14 @@ public class EntityManagerFactoryBuilderImpl implements EntityManagerFactoryBuil } public EntityManagerFactoryBuilderImpl(PersistenceUnitDescriptor persistenceUnit, Map integrationSettings) { + this( persistenceUnit, integrationSettings, null ); + } + + public EntityManagerFactoryBuilderImpl( + PersistenceUnitDescriptor persistenceUnit, + Map integrationSettings, + ClassLoader providedClassLoader ) { + LogHelper.logPersistenceUnitInformation( persistenceUnit ); this.persistenceUnit = persistenceUnit; @@ -171,6 +181,8 @@ public class EntityManagerFactoryBuilderImpl implements EntityManagerFactoryBuil if ( integrationSettings == null ) { integrationSettings = Collections.emptyMap(); } + + this.providedClassLoader = providedClassLoader; // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // First we build the boot-strap service registry, which mainly handles class loader interactions @@ -346,14 +358,22 @@ public class EntityManagerFactoryBuilderImpl implements EntityManagerFactoryBuil } } - ClassLoader classLoader = (ClassLoader) integrationSettings.get( org.hibernate.cfg.AvailableSettings.APP_CLASSLOADER ); - if ( classLoader != null ) { + // TODO: If providedClassLoader is present (OSGi, etc.) *and* + // an APP_CLASSLOADER is provided, should throw an exception or + // warn? + ClassLoader classLoader; + ClassLoader appClassLoader = (ClassLoader) integrationSettings.get( org.hibernate.cfg.AvailableSettings.APP_CLASSLOADER ); + if ( providedClassLoader != null ) { + classLoader = providedClassLoader; + } + else if ( appClassLoader != null ) { + classLoader = appClassLoader; integrationSettings.remove( org.hibernate.cfg.AvailableSettings.APP_CLASSLOADER ); } else { classLoader = persistenceUnit.getClassLoader(); } - bootstrapServiceRegistryBuilder.withApplicationClassLoader( classLoader ); + bootstrapServiceRegistryBuilder.with( classLoader ); return bootstrapServiceRegistryBuilder.build(); } @@ -664,6 +684,12 @@ public class EntityManagerFactoryBuilderImpl implements EntityManagerFactoryBuil LOG.containerProvidingNullPersistenceUnitRootUrl(); return; } + if ( scanningContext.getUrl().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 { if ( scanningContext.isDetectClasses() ) { diff --git a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/boot/spi/Bootstrap.java b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/boot/spi/Bootstrap.java index 67e6ae38cd..6c7434a3f3 100644 --- a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/boot/spi/Bootstrap.java +++ b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/boot/spi/Bootstrap.java @@ -23,9 +23,10 @@ */ package org.hibernate.jpa.boot.spi; -import javax.persistence.spi.PersistenceUnitInfo; import java.util.Map; +import javax.persistence.spi.PersistenceUnitInfo; + import org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl; import org.hibernate.jpa.boot.internal.PersistenceUnitInfoDescriptor; @@ -33,6 +34,7 @@ import org.hibernate.jpa.boot.internal.PersistenceUnitInfoDescriptor; * Entry into the bootstrap process. * * @author Steve Ebersole + * @author Brett Meyer */ public final class Bootstrap { public static EntityManagerFactoryBuilder getEntityManagerFactoryBuilder( @@ -40,10 +42,23 @@ public final class Bootstrap { Map integration) { return new EntityManagerFactoryBuilderImpl( persistenceUnitDescriptor, integration ); } + public static EntityManagerFactoryBuilder getEntityManagerFactoryBuilder( + PersistenceUnitDescriptor persistenceUnitDescriptor, + Map integration, + ClassLoader providedClassLoader) { + return new EntityManagerFactoryBuilderImpl( persistenceUnitDescriptor, integration, providedClassLoader ); + } public static EntityManagerFactoryBuilder getEntityManagerFactoryBuilder( PersistenceUnitInfo persistenceUnitInfo, Map integration) { return getEntityManagerFactoryBuilder( new PersistenceUnitInfoDescriptor( persistenceUnitInfo ), integration ); } + + public static EntityManagerFactoryBuilder getEntityManagerFactoryBuilder( + PersistenceUnitInfo persistenceUnitInfo, + Map integration, + ClassLoader providedClassLoader) { + return getEntityManagerFactoryBuilder( new PersistenceUnitInfoDescriptor( persistenceUnitInfo ), integration, providedClassLoader ); + } } diff --git a/hibernate-envers/hibernate-envers.gradle b/hibernate-envers/hibernate-envers.gradle index 28fa978cac..eb2acb42fd 100644 --- a/hibernate-envers/hibernate-envers.gradle +++ b/hibernate-envers/hibernate-envers.gradle @@ -48,3 +48,9 @@ task generateJpaMetamodelClasses(type: Compile) { } compileJava.dependsOn generateJpaMetamodelClasses +jar { + manifest { + instruction 'Bundle-Description', 'Hibernate ORM Envers' + instruction 'Bundle-SymbolicName', 'org.hibernate.envers' + } +} \ No newline at end of file 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 da282705bd..59f2a92fa8 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.List; 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.QueryParameters; 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 abstract class AbstractDelegateSessionImplementor implements SessionImple } @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 386d2e44d3..a679910470 100644 --- a/hibernate-infinispan/hibernate-infinispan.gradle +++ b/hibernate-infinispan/hibernate-infinispan.gradle @@ -40,3 +40,10 @@ task sourcesTestJar(type: Jar, dependsOn:classes) { artifacts.archives packageTests artifacts.archives sourcesTestJar + +jar { + manifest { + instruction 'Bundle-Description', 'Hibernate ORM Infinispan' + instruction 'Bundle-SymbolicName', 'org.hibernate.infinispan' + } +} \ No newline at end of file diff --git a/hibernate-osgi/hibernate-osgi.gradle b/hibernate-osgi/hibernate-osgi.gradle new file mode 100644 index 0000000000..a9c0ce376d --- /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 0000000000..b2cc73fb42 --- /dev/null +++ b/hibernate-osgi/src/main/java/org/hibernate/osgi/HibernateBundleActivator.java @@ -0,0 +1,109 @@ +/* + * 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.jpa.HibernatePersistenceProvider; +import org.hibernate.jpa.boot.spi.Bootstrap; +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 HibernatePersistenceProvider + 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(); + + 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) { + if ( info.getTransactionType().equals( PersistenceUnitTransactionType.JTA ) ) { + map.put( AvailableSettings.JTA_PLATFORM, new OsgiJtaPlatform( context ) ); + } + return Bootstrap.getEntityManagerFactoryBuilder( info, map, osgiClassLoader ).build(); + } + +} \ 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 0000000000..24bee34bba --- /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 0000000000..29ae4707d4 --- /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.engine.transaction.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 f57746b053..c6b0bcb133 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 9a5c3e2c54..28a3dd3a76 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 d1b69de095..25c34c655d 100644 --- a/libraries.gradle +++ b/libraries.gradle @@ -57,7 +57,7 @@ ext { jpa: 'org.hibernate.javax.persistence:hibernate-jpa-2.1-api:1.0.0.Draft-10', 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', @@ -102,7 +102,7 @@ ext { // ~~~~~~~~~~~~~~~~~~~~~~~~~~~ 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 cac16e1949..d86a2427d6 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 2e17736604..c6fb9085db 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 0000000000..1154ea1986 --- /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" ); + } +}