Skip to content

Commit

Permalink
HHH-7942 Create Hibernate OSGi bundle activator and class loader
Browse files Browse the repository at this point in the history
services
  • Loading branch information
brmeyer committed Jan 29, 2013
1 parent c3cff63 commit acbf2b8
Show file tree
Hide file tree
Showing 8 changed files with 138 additions and 63 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -33,21 +33,25 @@
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)
*/
public class BootstrapServiceRegistryBuilder {
private final LinkedHashSet<Integrator> providedIntegrators = new LinkedHashSet<Integrator>();
private List<ClassLoader> providedClassLoaders;

private ClassLoaderService providedClassLoaderService;
private StrategySelectorBuilder strategySelectorBuilder = new StrategySelectorBuilder();



/**
* Add an {@link Integrator} to be applied to the bootstrap registry.
Expand Down Expand Up @@ -75,6 +79,18 @@ public BootstrapServiceRegistryBuilder with(ClassLoader classLoader) {
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
*
Expand Down Expand Up @@ -171,7 +187,12 @@ public <T> BootstrapServiceRegistryBuilder withStrategySelectors(AvailabilityAnn
* @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,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,7 @@
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;
Expand Down Expand Up @@ -97,6 +95,7 @@
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
Expand Down Expand Up @@ -127,7 +126,7 @@ public void addExplicitAvailability(Availability availability) {
explicitAvailabilities.add( availability );
}

public StrategySelector buildSelector(ClassLoaderServiceImpl classLoaderService) {
public StrategySelector buildSelector(ClassLoaderService classLoaderService) {
StrategySelectorImpl strategySelector = new StrategySelectorImpl( classLoaderService );

// build the baseline...
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,30 +23,32 @@
*/
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.jboss.logging.Logger;

import org.hibernate.jpa.internal.EntityManagerMessageLogger;
import org.hibernate.jpa.internal.util.PersistenceUtilHelper;
import org.hibernate.boot.registry.classloading.spi.ClassLoaderService;
import org.hibernate.jpa.boot.internal.ParsedPersistenceXmlDescriptor;
import org.hibernate.jpa.boot.internal.PersistenceXmlParser;
import org.hibernate.jpa.boot.spi.Bootstrap;
import org.hibernate.jpa.boot.spi.ProviderChecker;
import org.hibernate.jpa.internal.EntityManagerMessageLogger;
import org.hibernate.jpa.internal.util.PersistenceUtilHelper;
import org.jboss.logging.Logger;

/**
* The Hibernate {@link PersistenceProvider} implementation
*
* @author Gavin King
* @author Steve Ebersole
* @author Brett Meyer
*/
public class HibernatePersistenceProvider implements PersistenceProvider {
private static final EntityManagerMessageLogger LOG = Logger.getMessageLogger(
Expand All @@ -55,6 +57,14 @@ public class HibernatePersistenceProvider implements PersistenceProvider {
);

private final PersistenceUtilHelper.MetadataCache cache = new PersistenceUtilHelper.MetadataCache();

private ClassLoaderService providedClassLoaderService;

public HibernatePersistenceProvider() { }

public HibernatePersistenceProvider( ClassLoaderService providedClassLoaderService ) {
this.providedClassLoaderService = providedClassLoaderService;
}

/**
* {@inheritDoc}
Expand Down Expand Up @@ -82,7 +92,7 @@ public EntityManagerFactory createEntityManagerFactory(String persistenceUnitNam
continue;
}

return Bootstrap.getEntityManagerFactoryBuilder( persistenceUnit, integration ).build();
return Bootstrap.getEntityManagerFactoryBuilder( persistenceUnit, integration, providedClassLoaderService ).build();
}

return null;
Expand All @@ -100,7 +110,7 @@ private static Map wrap(Map properties) {
*/
@Override
public EntityManagerFactory createContainerEntityManagerFactory(PersistenceUnitInfo info, Map integration) {
return Bootstrap.getEntityManagerFactoryBuilder( info, integration ).build();
return Bootstrap.getEntityManagerFactoryBuilder( info, integration, providedClassLoaderService ).build();
}

private final ProviderUtil providerUtil = new ProviderUtil() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,8 @@ public class EntityManagerFactoryBuilderImpl implements EntityManagerFactoryBuil
private Configuration hibernateConfiguration;

private static EntityNotFoundDelegate jpaEntityNotFoundDelegate = new JpaEntityNotFoundDelegate();

private ClassLoaderService providedClassLoaderService;

private static class JpaEntityNotFoundDelegate implements EntityNotFoundDelegate, Serializable {
public void handleEntityNotFound(String entityName, Serializable id) {
Expand Down Expand Up @@ -204,6 +206,14 @@ public EntityManagerFactoryBuilderImpl(PersistenceUnitDescriptor persistenceUnit
}
}

public EntityManagerFactoryBuilderImpl(
PersistenceUnitDescriptor persistenceUnit,
Map integrationSettings,
ClassLoaderService providedClassLoaderService ) {
this( persistenceUnit, integrationSettings );
this.providedClassLoaderService = providedClassLoaderService;
}

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// temporary!
@SuppressWarnings("unchecked")
Expand Down Expand Up @@ -345,14 +355,19 @@ private BootstrapServiceRegistry buildBootstrapServiceRegistry(Map integrationSe
}
}

ClassLoader classLoader = (ClassLoader) integrationSettings.get( org.hibernate.cfg.AvailableSettings.APP_CLASSLOADER );
if ( classLoader != null ) {
integrationSettings.remove( org.hibernate.cfg.AvailableSettings.APP_CLASSLOADER );
if ( providedClassLoaderService == null ) {
ClassLoader classLoader = (ClassLoader) integrationSettings.get( org.hibernate.cfg.AvailableSettings.APP_CLASSLOADER );
if ( classLoader != null ) {
integrationSettings.remove( org.hibernate.cfg.AvailableSettings.APP_CLASSLOADER );
}
else {
classLoader = persistenceUnit.getClassLoader();
}
bootstrapServiceRegistryBuilder.with( classLoader );
}
else {
classLoader = persistenceUnit.getClassLoader();
bootstrapServiceRegistryBuilder.with( providedClassLoaderService );
}
bootstrapServiceRegistryBuilder.withApplicationClassLoader( classLoader );

return bootstrapServiceRegistryBuilder.build();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,26 +24,43 @@
package org.hibernate.jpa.boot.spi;

import javax.persistence.spi.PersistenceUnitInfo;

import java.util.List;
import java.util.Map;

import org.hibernate.boot.registry.classloading.spi.ClassLoaderService;
import org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl;
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(
PersistenceUnitDescriptor persistenceUnitDescriptor,
Map integration) {
return new EntityManagerFactoryBuilderImpl( persistenceUnitDescriptor, integration );
}
public static EntityManagerFactoryBuilder getEntityManagerFactoryBuilder(
PersistenceUnitDescriptor persistenceUnitDescriptor,
Map integration,
ClassLoaderService providedClassLoaderService) {
return new EntityManagerFactoryBuilderImpl( persistenceUnitDescriptor, integration, providedClassLoaderService );
}

public static EntityManagerFactoryBuilder getEntityManagerFactoryBuilder(
PersistenceUnitInfo persistenceUnitInfo,
Map integration) {
return getEntityManagerFactoryBuilder( new PersistenceUnitInfoDescriptor( persistenceUnitInfo ), integration );
}

public static EntityManagerFactoryBuilder getEntityManagerFactoryBuilder(
PersistenceUnitInfo persistenceUnitInfo,
Map integration,
ClassLoaderService providedClassLoaderService) {
return getEntityManagerFactoryBuilder( new PersistenceUnitInfoDescriptor( persistenceUnitInfo ), integration, providedClassLoaderService );
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,81 +23,96 @@
*/
package org.hibernate.osgi.internal;

import java.util.Properties;

import javax.persistence.spi.PersistenceProvider;

import org.hibernate.jpa.HibernatePersistenceProvider;
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;
import org.osgi.framework.Constants;
import org.osgi.framework.ServiceEvent;
import org.osgi.framework.ServiceListener;
import org.osgi.framework.ServiceReference;

/**
* @author Brett Meyer
* @author Martin Neimeier
*/
public class HibernateBundleActivator implements
BundleActivator,
ServiceListener,
// ServiceListener,
BundleListener {

private OsgiClassLoaderService osgiClassLoaderService;

public HibernateBundleActivator() {
// create the class loader service
osgiClassLoaderService = new OsgiClassLoaderServiceImpl();

}

@Override
public void start(BundleContext context) throws Exception {
// TODO: register this ClassLoaderService with Hibernate
osgiClassLoaderService = new OsgiClassLoaderServiceImpl();

Properties properties = new Properties();
properties.put( "javax.persistence.provider", HibernatePersistenceProvider.class.getName() );
context.registerService(
PersistenceProvider.class.getName(),
new HibernatePersistenceProvider( osgiClassLoaderService ),
properties
);

// register this instance as a service listener - we are only interested
// on services which implement the interface
// org.hibernate.service.Service
context.addServiceListener(this, "(" + Constants.OBJECTCLASS
+ "="
+ org.hibernate.service.Service.class.getName()
+ ")");
// TODO: Is this needed? Do we care more about scanning the bundles instead?
// context.addServiceListener(this, "(" + Constants.OBJECTCLASS
// + "=" + org.hibernate.service.Service.class.getName() + ")");

// register this instance as a bundle listener to get informed about all
// bundle live cycle events
context.addBundleListener(this);

// TODO: do a initial scan for interesting services and bundles and
// register the bundles with the class loader
for ( Bundle bundle : context.getBundles() ) {
scanBundle( bundle );
}
}

@Override
public void stop(BundleContext context) throws Exception {
context.removeBundleListener(this);
context.removeServiceListener(this);
// context.removeServiceListener(this);

// and finally
// TODO: unregister this ClassLoaderService from Hibernate
// TODO: I'm assuming it'd be disastrous to blow away the
// osgiClassLoaderService. Instead, unregister the bundles in it?
}

@Override
public void bundleChanged(BundleEvent event) {
// Analyze the bundle-event and react

// TODO: scan bundle for interesting resources - could be used to add
// all bundles which contain persistence units to the class loader
scanBundle( event.getBundle() );

}

@Override
public void serviceChanged(ServiceEvent event) {
// Analyze the service-event and react
ServiceReference reference = event.getServiceReference();
if ((event.getType() & ServiceEvent.REGISTERED) != 0) {
// new interesting service .. register bundle implementing the
// service
osgiClassLoaderService.registerBundle(reference.getBundle());
} else if ((event.getType() & ServiceEvent.UNREGISTERING) != 0) {
// interesting service is nearly gone .. unregister the bundle
// implementing the service
osgiClassLoaderService.unregisterBundle(reference.getBundle());
}
// @Override
// public void serviceChanged(ServiceEvent event) {
// // Analyze the service-event and react
// ServiceReference reference = event.getServiceReference();
// if ((event.getType() & ServiceEvent.REGISTERED) != 0) {
// // new interesting service .. register bundle implementing the
// // service
// osgiClassLoaderService.registerBundle(reference.getBundle());
// } else if ((event.getType() & ServiceEvent.UNREGISTERING) != 0) {
// // interesting service is nearly gone .. unregister the bundle
// // implementing the service
// osgiClassLoaderService.unregisterBundle(reference.getBundle());
// }
// }

private void scanBundle( Bundle bundle ) {
if ( bundle.getState() == Bundle.ACTIVE ) {
// TODO: scan?
// TODO: register only if the bundle has a persistence context?
osgiClassLoaderService.registerBundle(bundle);
} else {
osgiClassLoaderService.unregisterBundle(bundle);
// TODO: since the env. is dynamic, will we need to "cleanup"
// any bundles that go down?
}
}

}

0 comments on commit acbf2b8

Please sign in to comment.