From ab64f5c3be0fbe757b49dfa7a39d9c2bf9903d80 Mon Sep 17 00:00:00 2001 From: Steve Ebersole Date: Fri, 31 Aug 2012 16:20:05 -0500 Subject: [PATCH] HHH-7552 - New StrategySelectorService : initial auto-detection --- .../BootstrapServiceRegistryBuilder.java | 21 +++++- .../boot/registry/selector/Availability.java | 33 +++++++++ .../selector/AvailabilityAnnouncer.java | 36 ++++++++++ .../selector/SimpleAvailabilityImpl.java | 66 ++++++++++++++++++ .../internal/StrategySelectorBuilder.java | 62 +++++++++-------- .../internal/NoCachingRegionFactory.java | 2 + .../internal/RegionFactoryInitiator.java | 58 +++++++++------- .../ehcache/AvailabilityAnnouncerImpl.java | 68 +++++++++++++++++++ ...ot.registry.selector.AvailabilityAnnouncer | 1 + .../infinispan/AvailabilityAnnouncerImpl.java | 65 ++++++++++++++++++ ...ot.registry.selector.AvailabilityAnnouncer | 0 11 files changed, 358 insertions(+), 54 deletions(-) create mode 100644 hibernate-core/src/main/java/org/hibernate/boot/registry/selector/Availability.java create mode 100644 hibernate-core/src/main/java/org/hibernate/boot/registry/selector/AvailabilityAnnouncer.java create mode 100644 hibernate-core/src/main/java/org/hibernate/boot/registry/selector/SimpleAvailabilityImpl.java create mode 100644 hibernate-ehcache/src/main/java/org/hibernate/cache/ehcache/AvailabilityAnnouncerImpl.java create mode 100644 hibernate-ehcache/src/main/resources/META-INF/services/org.hibernate.boot.registry.selector.AvailabilityAnnouncer create mode 100644 hibernate-infinispan/src/main/java/org/hibernate/cache/infinispan/AvailabilityAnnouncerImpl.java create mode 100644 hibernate-infinispan/src/main/resources/META-INF/services/org.hibernate.boot.registry.selector.AvailabilityAnnouncer 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 db33fef5eb..c8a97c0660 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 @@ -26,6 +26,8 @@ package org.hibernate.boot.registry; import java.util.LinkedHashSet; import org.hibernate.boot.registry.internal.BootstrapServiceRegistryImpl; +import org.hibernate.boot.registry.selector.Availability; +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; @@ -120,7 +122,24 @@ public class BootstrapServiceRegistryBuilder { */ @SuppressWarnings( {"UnusedDeclaration"}) public BootstrapServiceRegistryBuilder withStrategySelector(Class strategy, String name, Class implementation) { - this.strategySelectorBuilder.addCustomRegistration( strategy, name, implementation ); + this.strategySelectorBuilder.addExplicitAvailability( strategy, implementation, name ); + return this; + } + + /** + * Applies one or more strategy selectors announced as available by the passed announcer. + * + * @param availabilityAnnouncer An announcer for one or more available selectors + * + * @return {@code this}, for method chaining + * + * @see org.hibernate.boot.registry.selector.spi.StrategySelector#registerStrategyImplementor(Class, String, Class) + */ + @SuppressWarnings( {"UnusedDeclaration"}) + public BootstrapServiceRegistryBuilder withStrategySelectors(AvailabilityAnnouncer availabilityAnnouncer) { + for ( Availability availability : availabilityAnnouncer.getAvailabilities() ) { + this.strategySelectorBuilder.addExplicitAvailability( availability ); + } return this; } diff --git a/hibernate-core/src/main/java/org/hibernate/boot/registry/selector/Availability.java b/hibernate-core/src/main/java/org/hibernate/boot/registry/selector/Availability.java new file mode 100644 index 0000000000..658bbb7bed --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/boot/registry/selector/Availability.java @@ -0,0 +1,33 @@ +/* + * 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 + */ +package org.hibernate.boot.registry.selector; + +/** + * @author Steve Ebersole + */ +public interface Availability { + public Class getStrategyRole(); + public Iterable getSelectorNames(); + public Class getStrategyImplementation(); +} diff --git a/hibernate-core/src/main/java/org/hibernate/boot/registry/selector/AvailabilityAnnouncer.java b/hibernate-core/src/main/java/org/hibernate/boot/registry/selector/AvailabilityAnnouncer.java new file mode 100644 index 0000000000..eddc5b3e7e --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/boot/registry/selector/AvailabilityAnnouncer.java @@ -0,0 +1,36 @@ +/* + * 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 + */ +package org.hibernate.boot.registry.selector; + +/** + * Responsible for announcing the availability of strategy selector(s). Can be registered directly with the + * {@link org.hibernate.boot.registry.BootstrapServiceRegistry} or located via discovery + * + * todo : better name? + * + * @author Steve Ebersole + */ +public interface AvailabilityAnnouncer { + public Iterable getAvailabilities(); +} diff --git a/hibernate-core/src/main/java/org/hibernate/boot/registry/selector/SimpleAvailabilityImpl.java b/hibernate-core/src/main/java/org/hibernate/boot/registry/selector/SimpleAvailabilityImpl.java new file mode 100644 index 0000000000..ad515ce1ab --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/boot/registry/selector/SimpleAvailabilityImpl.java @@ -0,0 +1,66 @@ +/* + * 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 + */ +package org.hibernate.boot.registry.selector; + +import java.util.Arrays; + +/** + * @author Steve Ebersole + */ +public class SimpleAvailabilityImpl implements Availability { + private final Class strategyRole; + private final Class strategyImplementation; + private final Iterable selectorNames; + + public SimpleAvailabilityImpl( + Class strategyRole, + Class strategyImplementation, + Iterable selectorNames) { + this.strategyRole = strategyRole; + this.strategyImplementation = strategyImplementation; + this.selectorNames = selectorNames; + } + + public SimpleAvailabilityImpl( + Class strategyRole, + Class strategyImplementation, + String... selectorNames) { + this( strategyRole, strategyImplementation, Arrays.asList( selectorNames ) ); + } + + @Override + public Class getStrategyRole() { + return strategyRole; + } + + @Override + public Iterable getSelectorNames() { + return selectorNames; + } + + @Override + public Class getStrategyImplementation() { + return strategyImplementation; + } +} 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 cf35ce47e8..6404478a06 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 @@ -29,6 +29,9 @@ import java.util.List; import org.jboss.logging.Logger; import org.hibernate.boot.registry.classloading.internal.ClassLoaderServiceImpl; +import org.hibernate.boot.registry.selector.Availability; +import org.hibernate.boot.registry.selector.AvailabilityAnnouncer; +import org.hibernate.boot.registry.selector.SimpleAvailabilityImpl; import org.hibernate.boot.registry.selector.spi.StrategySelectionException; import org.hibernate.boot.registry.selector.spi.StrategySelector; import org.hibernate.dialect.CUBRIDDialect; @@ -98,38 +101,27 @@ import org.hibernate.engine.transaction.spi.TransactionFactory; public class StrategySelectorBuilder { private static final Logger log = Logger.getLogger( StrategySelectorBuilder.class ); - private static class CustomRegistration { - private final Class strategy; - private final String name; - private final Class implementation; - - private CustomRegistration(Class strategy, String name, Class implementation) { - this.strategy = strategy; - this.name = name; - this.implementation = implementation; - } - - public void registerWith(StrategySelectorImpl strategySelector) { - strategySelector.registerStrategyImplementor( strategy, name, implementation ); - } - } - - private final List customRegistrations = new ArrayList(); + private final List explicitAvailabilities = new ArrayList(); @SuppressWarnings("unchecked") - public void addCustomRegistration(Class strategy, String name, Class implementation) { - if ( !strategy.isInterface() ) { + public void addExplicitAvailability(Class strategy, Class implementation, String name) { + addExplicitAvailability( new SimpleAvailabilityImpl( strategy, implementation, name ) ); + } + + public void addExplicitAvailability(Availability availability) { + if ( !availability.getStrategyRole().isInterface() ) { // not good form... - log.debug( "Registering non-interface strategy implementation : " + strategy.getName() ); + log.debug( "Registering non-interface strategy implementation : " + availability.getStrategyRole().getName() ); } - if ( ! strategy.isAssignableFrom( implementation ) ) { + if ( ! availability.getStrategyRole().isAssignableFrom( availability.getStrategyImplementation() ) ) { throw new StrategySelectionException( - "Implementation class [" + implementation.getName() + "] does not implement strategy interface [" - + strategy.getName() + "]" + "Implementation class [" + availability.getStrategyImplementation().getName() + + "] does not implement strategy interface [" + + availability.getStrategyRole().getName() + "]" ); } - customRegistrations.add( new CustomRegistration( strategy, name, implementation ) ); + explicitAvailabilities.add( availability ); } public StrategySelector buildSelector(ClassLoaderServiceImpl classLoaderService) { @@ -140,16 +132,32 @@ public class StrategySelectorBuilder { addJtaPlatforms( strategySelector ); addTransactionFactories( strategySelector ); - // todo : apply auto-discovered registrations + // apply auto-discovered registrations + for ( AvailabilityAnnouncer announcer : classLoaderService.loadJavaServices( AvailabilityAnnouncer.class ) ) { + for ( Availability discoveredAvailability : announcer.getAvailabilities() ) { + applyFromAvailability( strategySelector, discoveredAvailability ); + } + } // apply customizations - for ( CustomRegistration customRegistration : customRegistrations ) { - customRegistration.registerWith( strategySelector ); + for ( Availability explicitAvailability : explicitAvailabilities ) { + applyFromAvailability( strategySelector, explicitAvailability ); } return strategySelector; } + @SuppressWarnings("unchecked") + private void applyFromAvailability(StrategySelectorImpl strategySelector, Availability availability) { + for ( String name : availability.getSelectorNames() ) { + strategySelector.registerStrategyImplementor( + availability.getStrategyRole(), + name, + availability.getStrategyImplementation() + ); + } + } + private void addDialects(StrategySelectorImpl strategySelector) { addDialect( strategySelector, Cache71Dialect.class ); addDialect( strategySelector, CUBRIDDialect.class ); diff --git a/hibernate-core/src/main/java/org/hibernate/cache/internal/NoCachingRegionFactory.java b/hibernate-core/src/main/java/org/hibernate/cache/internal/NoCachingRegionFactory.java index 94a4a59201..7d16fb3e5a 100644 --- a/hibernate-core/src/main/java/org/hibernate/cache/internal/NoCachingRegionFactory.java +++ b/hibernate-core/src/main/java/org/hibernate/cache/internal/NoCachingRegionFactory.java @@ -43,6 +43,8 @@ import org.hibernate.cfg.Settings; * @author Steve Ebersole */ public class NoCachingRegionFactory implements RegionFactory { + public static final NoCachingRegionFactory INSTANCE = new NoCachingRegionFactory(); + public NoCachingRegionFactory() { } diff --git a/hibernate-core/src/main/java/org/hibernate/cache/internal/RegionFactoryInitiator.java b/hibernate-core/src/main/java/org/hibernate/cache/internal/RegionFactoryInitiator.java index 6a2002f591..65b13cb453 100644 --- a/hibernate-core/src/main/java/org/hibernate/cache/internal/RegionFactoryInitiator.java +++ b/hibernate-core/src/main/java/org/hibernate/cache/internal/RegionFactoryInitiator.java @@ -26,6 +26,7 @@ package org.hibernate.cache.internal; import java.util.Map; import org.hibernate.boot.registry.StandardServiceInitiator; +import org.hibernate.boot.registry.selector.spi.StrategySelector; import org.hibernate.cache.spi.RegionFactory; import org.hibernate.boot.registry.classloading.spi.ClassLoaderService; import org.hibernate.service.spi.ServiceException; @@ -52,32 +53,37 @@ public class RegionFactoryInitiator implements StandardServiceInitiator customImplClass = null; - if ( Class.class.isInstance( impl ) ) { - customImplClass = (Class) impl; - } - else { - customImplClass = registry.getService( ClassLoaderService.class ) - .classForName( mapLegacyNames( impl.toString() ) ); - } - - try { - return customImplClass.newInstance(); - } - catch ( Exception e ) { - throw new ServiceException( - "Could not initialize custom RegionFactory impl [" + customImplClass.getName() + "]", e - ); - } + final Object setting = configurationValues.get( IMPL_NAME ); + return registry.getService( StrategySelector.class ).resolveDefaultableStrategy( + RegionFactory.class, + setting, + NoCachingRegionFactory.INSTANCE + ); +// if ( setting == null ) { +// return new NoCachingRegionFactory(); +// } +// +// if ( getServiceInitiated().isInstance( setting ) ) { +// return (RegionFactory) setting; +// } +// +// Class customImplClass = null; +// if ( Class.class.isInstance( setting ) ) { +// customImplClass = (Class) setting; +// } +// else { +// customImplClass = registry.getService( ClassLoaderService.class ) +// .classForName( mapLegacyNames( setting.toString() ) ); +// } +// +// try { +// return customImplClass.newInstance(); +// } +// catch ( Exception e ) { +// throw new ServiceException( +// "Could not initialize custom RegionFactory impl [" + customImplClass.getName() + "]", e +// ); +// } } // todo this shouldn't be public (nor really static): diff --git a/hibernate-ehcache/src/main/java/org/hibernate/cache/ehcache/AvailabilityAnnouncerImpl.java b/hibernate-ehcache/src/main/java/org/hibernate/cache/ehcache/AvailabilityAnnouncerImpl.java new file mode 100644 index 0000000000..9efe6fa462 --- /dev/null +++ b/hibernate-ehcache/src/main/java/org/hibernate/cache/ehcache/AvailabilityAnnouncerImpl.java @@ -0,0 +1,68 @@ +/* + * 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 + */ +package org.hibernate.cache.ehcache; + +import java.util.ArrayList; +import java.util.List; + +import org.hibernate.boot.registry.selector.Availability; +import org.hibernate.boot.registry.selector.AvailabilityAnnouncer; +import org.hibernate.boot.registry.selector.SimpleAvailabilityImpl; +import org.hibernate.cache.spi.RegionFactory; + +/** + * Makes the 2 contained region factory implementations available to the Hibernate + * {@link org.hibernate.boot.registry.selector.spi.StrategySelector} service. + * + * @author Steve Ebersole + */ +public class AvailabilityAnnouncerImpl implements AvailabilityAnnouncer { + @Override + @SuppressWarnings("unchecked") + public Iterable getAvailabilities() { + final List availabilities = new ArrayList(); + + availabilities.add( + new SimpleAvailabilityImpl( + RegionFactory.class, + EhCacheRegionFactory.class, + "ehcache", + EhCacheRegionFactory.class.getSimpleName(), + "org.hibernate.cache.EhCacheRegionFactory" // legacy impl class name + ) + ); + + availabilities.add( + new SimpleAvailabilityImpl( + RegionFactory.class, + SingletonEhCacheRegionFactory.class, + "ehcache-singleton", + SingletonEhCacheRegionFactory.class.getSimpleName(), + "org.hibernate.cache.SingletonEhCacheRegionFactory" // legacy impl class name + ) + ); + + return availabilities; + } +} diff --git a/hibernate-ehcache/src/main/resources/META-INF/services/org.hibernate.boot.registry.selector.AvailabilityAnnouncer b/hibernate-ehcache/src/main/resources/META-INF/services/org.hibernate.boot.registry.selector.AvailabilityAnnouncer new file mode 100644 index 0000000000..4089ec9f31 --- /dev/null +++ b/hibernate-ehcache/src/main/resources/META-INF/services/org.hibernate.boot.registry.selector.AvailabilityAnnouncer @@ -0,0 +1 @@ +org.hibernate.cache.ehcache.AvailabilityAnnouncerImpl \ No newline at end of file diff --git a/hibernate-infinispan/src/main/java/org/hibernate/cache/infinispan/AvailabilityAnnouncerImpl.java b/hibernate-infinispan/src/main/java/org/hibernate/cache/infinispan/AvailabilityAnnouncerImpl.java new file mode 100644 index 0000000000..fc6ad8eccd --- /dev/null +++ b/hibernate-infinispan/src/main/java/org/hibernate/cache/infinispan/AvailabilityAnnouncerImpl.java @@ -0,0 +1,65 @@ +/* + * 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 + */ +package org.hibernate.cache.infinispan; + +import java.util.ArrayList; +import java.util.List; + +import org.hibernate.boot.registry.selector.Availability; +import org.hibernate.boot.registry.selector.AvailabilityAnnouncer; +import org.hibernate.boot.registry.selector.SimpleAvailabilityImpl; +import org.hibernate.cache.spi.RegionFactory; + +/** + * Makes the 2 contained region factory implementations available to the Hibernate + * {@link org.hibernate.boot.registry.selector.spi.StrategySelector} service. + * + * @author Steve Ebersole + */ +public class AvailabilityAnnouncerImpl implements AvailabilityAnnouncer { + @Override + public Iterable getAvailabilities() { + final List availabilities = new ArrayList(); + + availabilities.add( + new SimpleAvailabilityImpl( + RegionFactory.class, + InfinispanRegionFactory.class, + "infinispan", + InfinispanRegionFactory.class.getSimpleName() + ) + ); + + availabilities.add( + new SimpleAvailabilityImpl( + RegionFactory.class, + JndiInfinispanRegionFactory.class, + "infinispan-jndi", + JndiInfinispanRegionFactory.class.getSimpleName() + ) + ); + + return availabilities; + } +} diff --git a/hibernate-infinispan/src/main/resources/META-INF/services/org.hibernate.boot.registry.selector.AvailabilityAnnouncer b/hibernate-infinispan/src/main/resources/META-INF/services/org.hibernate.boot.registry.selector.AvailabilityAnnouncer new file mode 100644 index 0000000000..e69de29bb2