From a30347552c008b5e68bc4c67570ce6b35151c244 Mon Sep 17 00:00:00 2001 From: Brett Meyer Date: Mon, 22 Apr 2013 14:00:54 -0400 Subject: [PATCH] HHH-7995 Auto-discovery of Hibernate extension points in OSGi --- .../hibernate/internal/CoreMessageLogger.java | 4 ++ .../OSGI-INF/blueprint/blueprint.xml | 10 ++++ hibernate-osgi/hibernate-osgi.gradle | 4 +- .../osgi/HibernateBundleActivator.java | 4 +- .../osgi/OsgiPersistenceProvider.java | 58 +++++++++++++------ .../osgi/OsgiPersistenceProviderService.java | 9 ++- .../osgi/OsgiSessionFactoryService.java | 18 +++++- .../hibernate/osgi/util/OsgiServiceUtil.java | 53 +++++++++++++++++ 8 files changed, 136 insertions(+), 24 deletions(-) create mode 100644 hibernate-envers/src/main/resources/OSGI-INF/blueprint/blueprint.xml create mode 100644 hibernate-osgi/src/main/java/org/hibernate/osgi/util/OsgiServiceUtil.java diff --git a/hibernate-core/src/main/java/org/hibernate/internal/CoreMessageLogger.java b/hibernate-core/src/main/java/org/hibernate/internal/CoreMessageLogger.java index 84d161b5a2..d59d12287c 100644 --- a/hibernate-core/src/main/java/org/hibernate/internal/CoreMessageLogger.java +++ b/hibernate-core/src/main/java/org/hibernate/internal/CoreMessageLogger.java @@ -1618,4 +1618,8 @@ void cannotResolveNonNullableTransientDependencies(String transientEntityString, @LogMessage(level = WARN) @Message(value = "Exception while loading a class or resource found during scanning", id = 449) void unableToLoadScannedClassOrResource(@Cause Exception e); + + @LogMessage(level = WARN) + @Message(value = "Exception while discovering OSGi service implementations : %s", id = 450) + void unableToDiscoverOsgiService(String service, @Cause Exception e); } diff --git a/hibernate-envers/src/main/resources/OSGI-INF/blueprint/blueprint.xml b/hibernate-envers/src/main/resources/OSGI-INF/blueprint/blueprint.xml new file mode 100644 index 0000000000..c88d9a8eae --- /dev/null +++ b/hibernate-envers/src/main/resources/OSGI-INF/blueprint/blueprint.xml @@ -0,0 +1,10 @@ + + + + + + + + diff --git a/hibernate-osgi/hibernate-osgi.gradle b/hibernate-osgi/hibernate-osgi.gradle index af99af5fd7..94236cbfe8 100644 --- a/hibernate-osgi/hibernate-osgi.gradle +++ b/hibernate-osgi/hibernate-osgi.gradle @@ -1,7 +1,9 @@ dependencies { compile( project( ':hibernate-core' ) ) compile( project( ':hibernate-entitymanager' ) ) - compile( "org.osgi:org.osgi.core:4.3.0" ) + // MUST use 4.3.1! 4.3.0 was compiled with "-target jsr14". + // http://blog.osgi.org/2012/10/43-companion-code-for-java-7.html + compile( "org.osgi:org.osgi.core:4.3.1" ) } jar { diff --git a/hibernate-osgi/src/main/java/org/hibernate/osgi/HibernateBundleActivator.java b/hibernate-osgi/src/main/java/org/hibernate/osgi/HibernateBundleActivator.java index e928197dcf..e6614c97fe 100644 --- a/hibernate-osgi/src/main/java/org/hibernate/osgi/HibernateBundleActivator.java +++ b/hibernate-osgi/src/main/java/org/hibernate/osgi/HibernateBundleActivator.java @@ -78,10 +78,10 @@ public void start(BundleContext context) throws Exception { // using the legacy provider name. properties.put( "javax.persistence.provider", HibernatePersistence.class.getName() ); context.registerService( PersistenceProvider.class.getName(), - new OsgiPersistenceProviderService( osgiClassLoader, osgiJtaPlatform ), properties ); + new OsgiPersistenceProviderService( osgiClassLoader, osgiJtaPlatform, context ), properties ); context.registerService( SessionFactory.class.getName(), - new OsgiSessionFactoryService( osgiClassLoader, osgiJtaPlatform ), new Hashtable()); + new OsgiSessionFactoryService( osgiClassLoader, osgiJtaPlatform, context ), new Hashtable()); } @Override diff --git a/hibernate-osgi/src/main/java/org/hibernate/osgi/OsgiPersistenceProvider.java b/hibernate-osgi/src/main/java/org/hibernate/osgi/OsgiPersistenceProvider.java index c529d07846..83c09f5c43 100644 --- a/hibernate-osgi/src/main/java/org/hibernate/osgi/OsgiPersistenceProvider.java +++ b/hibernate-osgi/src/main/java/org/hibernate/osgi/OsgiPersistenceProvider.java @@ -25,6 +25,7 @@ import java.util.Collection; import java.util.HashMap; +import java.util.List; import java.util.Map; import javax.persistence.EntityManagerFactory; @@ -33,8 +34,11 @@ import org.hibernate.cfg.AvailableSettings; import org.hibernate.ejb.Ejb3Configuration; import org.hibernate.ejb.HibernatePersistence; +import org.hibernate.integrator.spi.Integrator; +import org.hibernate.osgi.util.OsgiServiceUtil; import org.hibernate.service.BootstrapServiceRegistryBuilder; import org.osgi.framework.Bundle; +import org.osgi.framework.BundleContext; import org.osgi.framework.BundleReference; /** @@ -46,27 +50,32 @@ public class OsgiPersistenceProvider extends HibernatePersistence { private OsgiClassLoader osgiClassLoader; private OsgiJtaPlatform osgiJtaPlatform; - + private Bundle requestingBundle; - - public OsgiPersistenceProvider (OsgiClassLoader osgiClassLoader, - OsgiJtaPlatform osgiJtaPlatform, - Bundle requestingBundle ) { + + private BundleContext context; + + public OsgiPersistenceProvider(OsgiClassLoader osgiClassLoader, OsgiJtaPlatform osgiJtaPlatform, + Bundle requestingBundle, BundleContext context) { this.osgiClassLoader = osgiClassLoader; this.osgiJtaPlatform = osgiJtaPlatform; this.requestingBundle = requestingBundle; + this.context = context; } + + // TODO: Does "hibernate.classloaders" and osgiClassLoader need added to the + // EMFBuilder somehow? @Override public EntityManagerFactory createEntityManagerFactory(String persistenceUnitName, Map properties) { - if ( properties == null ) { - properties = new HashMap(); - } - properties.put( AvailableSettings.JTA_PLATFORM, osgiJtaPlatform ); + generateProperties( properties ); + // TODO: This needs tested. - properties.put( org.hibernate.ejb.AvailableSettings.SCANNER, - new OsgiScanner( requestingBundle ) ); - + properties.put( org.hibernate.ejb.AvailableSettings.SCANNER, new OsgiScanner( requestingBundle ) ); + // TODO: This is temporary -- for PersistenceXmlParser's use of + // ClassLoaderServiceImpl#fromConfigSettings + properties.put( AvailableSettings.ENVIRONMENT_CLASSLOADER, osgiClassLoader ); + osgiClassLoader.addBundle( requestingBundle ); Ejb3Configuration cfg = new Ejb3Configuration(); @@ -76,11 +85,9 @@ public EntityManagerFactory createEntityManagerFactory(String persistenceUnitNam @Override public EntityManagerFactory createContainerEntityManagerFactory(PersistenceUnitInfo info, Map properties) { - if ( properties == null ) { - properties = new HashMap(); - } - properties.put( AvailableSettings.JTA_PLATFORM, osgiJtaPlatform ); - // OSGi ClassLoaders must implement BundleReference + generateProperties( properties ); + + // OSGi ClassLoaders must implement BundleReference properties.put( org.hibernate.ejb.AvailableSettings.SCANNER, new OsgiScanner( ( (BundleReference) info.getClassLoader() ).getBundle() ) ); @@ -93,6 +100,7 @@ public EntityManagerFactory createContainerEntityManagerFactory(PersistenceUnitI private BootstrapServiceRegistryBuilder getBuilder(Map properties) { BootstrapServiceRegistryBuilder builder = new BootstrapServiceRegistryBuilder(); + final Collection classLoaders = (Collection) properties .get( AvailableSettings.CLASSLOADERS ); if ( classLoaders != null ) { @@ -101,6 +109,22 @@ private BootstrapServiceRegistryBuilder getBuilder(Map properties) { } } builder.with( osgiClassLoader ); + + final List integrators = OsgiServiceUtil.getServiceImpls( Integrator.class, context ); + for ( Integrator integrator : integrators ) { + builder.with( integrator ); + } + + // TODO: other types of services? + return builder; } + + private void generateProperties(Map properties) { + if ( properties == null ) { + properties = new HashMap(); + } + + properties.put( AvailableSettings.JTA_PLATFORM, osgiJtaPlatform ); + } } diff --git a/hibernate-osgi/src/main/java/org/hibernate/osgi/OsgiPersistenceProviderService.java b/hibernate-osgi/src/main/java/org/hibernate/osgi/OsgiPersistenceProviderService.java index bb9008c33b..5ab228568f 100644 --- a/hibernate-osgi/src/main/java/org/hibernate/osgi/OsgiPersistenceProviderService.java +++ b/hibernate-osgi/src/main/java/org/hibernate/osgi/OsgiPersistenceProviderService.java @@ -21,6 +21,7 @@ package org.hibernate.osgi; import org.osgi.framework.Bundle; +import org.osgi.framework.BundleContext; import org.osgi.framework.ServiceFactory; import org.osgi.framework.ServiceRegistration; @@ -37,14 +38,18 @@ public class OsgiPersistenceProviderService implements ServiceFactory { private OsgiJtaPlatform osgiJtaPlatform; - public OsgiPersistenceProviderService( OsgiClassLoader osgiClassLoader, OsgiJtaPlatform osgiJtaPlatform ) { + private BundleContext context; + + public OsgiPersistenceProviderService( OsgiClassLoader osgiClassLoader, + OsgiJtaPlatform osgiJtaPlatform, BundleContext context ) { this.osgiClassLoader = osgiClassLoader; this.osgiJtaPlatform = osgiJtaPlatform; + this.context = context; } @Override public Object getService(Bundle requestingBundle, ServiceRegistration registration) { - return new OsgiPersistenceProvider(osgiClassLoader, osgiJtaPlatform, requestingBundle); + return new OsgiPersistenceProvider(osgiClassLoader, osgiJtaPlatform, requestingBundle, context); } @Override diff --git a/hibernate-osgi/src/main/java/org/hibernate/osgi/OsgiSessionFactoryService.java b/hibernate-osgi/src/main/java/org/hibernate/osgi/OsgiSessionFactoryService.java index 6c00a85a63..b13f378212 100644 --- a/hibernate-osgi/src/main/java/org/hibernate/osgi/OsgiSessionFactoryService.java +++ b/hibernate-osgi/src/main/java/org/hibernate/osgi/OsgiSessionFactoryService.java @@ -20,13 +20,18 @@ */ package org.hibernate.osgi; +import java.util.List; + import org.hibernate.SessionFactory; import org.hibernate.cfg.AvailableSettings; import org.hibernate.cfg.Configuration; +import org.hibernate.integrator.spi.Integrator; +import org.hibernate.osgi.util.OsgiServiceUtil; import org.hibernate.service.BootstrapServiceRegistryBuilder; import org.hibernate.service.ServiceRegistry; import org.hibernate.service.ServiceRegistryBuilder; import org.osgi.framework.Bundle; +import org.osgi.framework.BundleContext; import org.osgi.framework.ServiceFactory; import org.osgi.framework.ServiceRegistration; @@ -54,9 +59,13 @@ public class OsgiSessionFactoryService implements ServiceFactory { private OsgiJtaPlatform osgiJtaPlatform; - public OsgiSessionFactoryService( OsgiClassLoader osgiClassLoader, OsgiJtaPlatform osgiJtaPlatform ) { + private BundleContext context; + + public OsgiSessionFactoryService( OsgiClassLoader osgiClassLoader, OsgiJtaPlatform osgiJtaPlatform, + BundleContext context ) { this.osgiClassLoader = osgiClassLoader; this.osgiJtaPlatform = osgiJtaPlatform; + this.context = context; } @Override @@ -70,8 +79,13 @@ public Object getService(Bundle requestingBundle, ServiceRegistration registrati BootstrapServiceRegistryBuilder builder = new BootstrapServiceRegistryBuilder(); builder.with( osgiClassLoader ); + List integrators = OsgiServiceUtil.getServiceImpls( Integrator.class, context ); + for (Integrator integrator : integrators) { + builder.with( integrator ); + } + ServiceRegistry serviceRegistry = new ServiceRegistryBuilder( builder.build() ) - .applySettings(configuration.getProperties()).buildServiceRegistry(); + .applySettings(configuration.getProperties()).buildServiceRegistry(); return configuration.buildSessionFactory(serviceRegistry); } diff --git a/hibernate-osgi/src/main/java/org/hibernate/osgi/util/OsgiServiceUtil.java b/hibernate-osgi/src/main/java/org/hibernate/osgi/util/OsgiServiceUtil.java new file mode 100644 index 0000000000..0b9ddc0ed4 --- /dev/null +++ b/hibernate-osgi/src/main/java/org/hibernate/osgi/util/OsgiServiceUtil.java @@ -0,0 +1,53 @@ +/* + * 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.util; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +import org.hibernate.internal.CoreMessageLogger; +import org.jboss.logging.Logger; +import org.osgi.framework.BundleContext; +import org.osgi.framework.ServiceReference; + +/** + * @author Brett Meyer + */ +public class OsgiServiceUtil { + + private static final CoreMessageLogger LOG = Logger.getMessageLogger( CoreMessageLogger.class, + OsgiServiceUtil.class.getName() ); + + public static List getServiceImpls(Class contract, BundleContext context) { + List serviceImpls = new ArrayList(); + try { + Collection> serviceRefs = context.getServiceReferences( contract, null ); + for ( ServiceReference serviceRef : serviceRefs ) { + serviceImpls.add( context.getService( serviceRef ) ); + } + } + catch ( Exception e ) { + LOG.unableToDiscoverOsgiService( contract.getName(), e ); + } + return serviceImpls; + } +}