From d24ed1a1d39c1458d020a27a504a46e76dfe2e26 Mon Sep 17 00:00:00 2001 From: Steve Ebersole Date: Fri, 22 Jan 2010 07:22:50 +0000 Subject: [PATCH] HHH-4659 - Add support for standard declarative cache (@Cacheable) git-svn-id: https://svn.jboss.org/repos/hibernate/core/trunk@18605 1b8cb986-b30d-0410-93ca-fae66ebed9b2 --- .../org/hibernate/cfg/AnnotationBinder.java | 89 ++++++++++++- .../cfg/AnnotationConfiguration.java | 1 + .../org/hibernate/cfg/ExtendedMappings.java | 1 + .../java/org/hibernate/cfg/Configuration.java | 6 +- .../main/java/org/hibernate/cfg/Mappings.java | 7 + .../org/hibernate/cfg/SettingsFactory.java | 2 +- .../annotation/ConfigurationTest.java | 120 ++++++++++++++++++ .../annotation/ExplicitlyCacheableEntity.java | 57 +++++++++ .../ExplicitlyNonCacheableEntity.java | 57 +++++++++ .../NoCacheableAnnotationEntity.java | 56 ++++++++ 10 files changed, 391 insertions(+), 5 deletions(-) create mode 100644 entitymanager/src/test/java/org/hibernate/ejb/test/cacheable/annotation/ConfigurationTest.java create mode 100644 entitymanager/src/test/java/org/hibernate/ejb/test/cacheable/annotation/ExplicitlyCacheableEntity.java create mode 100644 entitymanager/src/test/java/org/hibernate/ejb/test/cacheable/annotation/ExplicitlyNonCacheableEntity.java create mode 100644 entitymanager/src/test/java/org/hibernate/ejb/test/cacheable/annotation/NoCacheableAnnotationEntity.java diff --git a/annotations/src/main/java/org/hibernate/cfg/AnnotationBinder.java b/annotations/src/main/java/org/hibernate/cfg/AnnotationBinder.java index f0ca5b4720..9fd616c160 100644 --- a/annotations/src/main/java/org/hibernate/cfg/AnnotationBinder.java +++ b/annotations/src/main/java/org/hibernate/cfg/AnnotationBinder.java @@ -24,6 +24,7 @@ */ package org.hibernate.cfg; +import java.lang.annotation.Annotation; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; @@ -36,6 +37,7 @@ import java.util.Properties; import java.util.Set; import javax.persistence.Basic; +import javax.persistence.Cacheable; import javax.persistence.Column; import javax.persistence.DiscriminatorType; import javax.persistence.DiscriminatorValue; @@ -66,6 +68,7 @@ import javax.persistence.PrimaryKeyJoinColumn; import javax.persistence.PrimaryKeyJoinColumns; import javax.persistence.SequenceGenerator; +import javax.persistence.SharedCacheMode; import javax.persistence.SqlResultSetMapping; import javax.persistence.SqlResultSetMappings; import javax.persistence.Table; @@ -86,6 +89,7 @@ import org.hibernate.MappingException; import org.hibernate.annotations.BatchSize; import org.hibernate.annotations.Cache; +import org.hibernate.annotations.CacheConcurrencyStrategy; import org.hibernate.annotations.Cascade; import org.hibernate.annotations.CascadeType; import org.hibernate.annotations.Check; @@ -128,6 +132,7 @@ import org.hibernate.annotations.common.reflection.XMethod; import org.hibernate.annotations.common.reflection.XPackage; import org.hibernate.annotations.common.reflection.XProperty; +import org.hibernate.cache.RegionFactory; import org.hibernate.cfg.annotations.CollectionBinder; import org.hibernate.cfg.annotations.EntityBinder; import org.hibernate.cfg.annotations.Nullability; @@ -505,9 +510,9 @@ public static void bindClass( org.hibernate.annotations.Entity hibEntityAnn = clazzToProcess.getAnnotation( org.hibernate.annotations.Entity.class ); - org.hibernate.annotations.Cache cacheAnn = clazzToProcess.getAnnotation( - org.hibernate.annotations.Cache.class - ); + + Cache cacheAnn = determineCacheSettings( clazzToProcess, mappings ); + EntityBinder entityBinder = new EntityBinder( entityAnn, hibEntityAnn, clazzToProcess, persistentClass, mappings ); @@ -765,6 +770,84 @@ else if ( InheritanceType.TABLE_PER_CLASS.equals( inheritanceState.getType() ) ) } + private static Cache determineCacheSettings(XClass clazzToProcess, ExtendedMappings mappings) { + Cache cacheAnn = clazzToProcess.getAnnotation( Cache.class ); + if ( cacheAnn != null ) { + return cacheAnn; + } + + Cacheable cacheableAnn = clazzToProcess.getAnnotation( Cacheable.class ); + SharedCacheMode mode = (SharedCacheMode) mappings.getConfigurationProperties().get( + "javax.persistence.sharedCache.mode" + ); + switch ( mode ) { + case ALL: { + cacheAnn = buildCacheMock( clazzToProcess.getName(), mappings ); + break; + } + case ENABLE_SELECTIVE: { + if ( cacheableAnn != null && cacheableAnn.value() ) { + cacheAnn = buildCacheMock( clazzToProcess.getName(), mappings ); + } + break; + } + case DISABLE_SELECTIVE: { + if ( cacheableAnn == null || cacheableAnn.value() ) { + cacheAnn = buildCacheMock( clazzToProcess.getName(), mappings ); + } + break; + } + default: { + // treat both NONE and UNSPECIFIED the same + break; + } + } + return cacheAnn; + } + + private static Cache buildCacheMock(String region, ExtendedMappings mappings) { + return new LocalCacheAnnotationImpl( region, determineCacheConcurrencyStrategy( mappings ) ); + } + + private static CacheConcurrencyStrategy DEFAULT_CACHE_CONCURRENCY_STRATEGY; + + private static CacheConcurrencyStrategy determineCacheConcurrencyStrategy(ExtendedMappings mappings) { + if ( DEFAULT_CACHE_CONCURRENCY_STRATEGY == null ) { +// todo need to figure out how we will determine the default cache access-type/concurrency-strategy +// RegionFactory cacheRegionFactory = SettingsFactory.createRegionFactory( mappings.getConfigurationProperties(), true ); +// DEFAULT_CACHE_CONCURRENCY_STRATEGY = cacheRegionFactory.[getDefault...] + DEFAULT_CACHE_CONCURRENCY_STRATEGY = CacheConcurrencyStrategy.TRANSACTIONAL; + } + return DEFAULT_CACHE_CONCURRENCY_STRATEGY; + } + + @SuppressWarnings({ "ClassExplicitlyAnnotation" }) + private static class LocalCacheAnnotationImpl implements Cache { + private final String region; + private final CacheConcurrencyStrategy usage; + + private LocalCacheAnnotationImpl(String region, CacheConcurrencyStrategy usage) { + this.region = region; + this.usage = usage; + } + + public CacheConcurrencyStrategy usage() { + return usage; + } + + public String region() { + return region; + } + + public String include() { + return "all"; + } + + public Class annotationType() { + return Cache.class; + } + } + private static PersistentClass makePersistentClass(InheritanceState inheritanceState, PersistentClass superEntity) { //we now know what kind of persistent entity it is PersistentClass persistentClass; diff --git a/annotations/src/main/java/org/hibernate/cfg/AnnotationConfiguration.java b/annotations/src/main/java/org/hibernate/cfg/AnnotationConfiguration.java index 8dc7b51f9f..be162e4a80 100644 --- a/annotations/src/main/java/org/hibernate/cfg/AnnotationConfiguration.java +++ b/annotations/src/main/java/org/hibernate/cfg/AnnotationConfiguration.java @@ -68,6 +68,7 @@ import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.annotations.AnyMetaDef; +import org.hibernate.annotations.Cache; import org.hibernate.annotations.common.reflection.MetadataProvider; import org.hibernate.annotations.common.reflection.MetadataProviderInjector; import org.hibernate.annotations.common.reflection.ReflectionManager; diff --git a/annotations/src/main/java/org/hibernate/cfg/ExtendedMappings.java b/annotations/src/main/java/org/hibernate/cfg/ExtendedMappings.java index 37326e3d4d..2bbf9180bd 100644 --- a/annotations/src/main/java/org/hibernate/cfg/ExtendedMappings.java +++ b/annotations/src/main/java/org/hibernate/cfg/ExtendedMappings.java @@ -30,6 +30,7 @@ import org.hibernate.AnnotationException; import org.hibernate.MappingException; import org.hibernate.annotations.AnyMetaDef; +import org.hibernate.annotations.Cache; import org.hibernate.annotations.common.reflection.ReflectionManager; import org.hibernate.annotations.common.reflection.XClass; import org.hibernate.engine.NamedQueryDefinition; diff --git a/core/src/main/java/org/hibernate/cfg/Configuration.java b/core/src/main/java/org/hibernate/cfg/Configuration.java index 570f2543ad..a022cbc019 100644 --- a/core/src/main/java/org/hibernate/cfg/Configuration.java +++ b/core/src/main/java/org/hibernate/cfg/Configuration.java @@ -474,7 +474,7 @@ private File determineCachedDomFile(File xmlFile) { /** * INTENDED FOR TESTSUITE USE ONLY! *

- * Much like {@link addCacheableFile(File)} except that here we will fail immediately if + * Much like {@link #addCacheableFile(File)} except that here we will fail immediately if * the cache version cannot be found or used for whatever reason * * @param xmlFile The xml file, not the bin! @@ -2797,6 +2797,10 @@ public MappedSuperclass getMappedSuperclass(Class type) { public ObjectNameNormalizer getObjectNameNormalizer() { return normalizer; } + + public Properties getConfigurationProperties() { + return properties; + } } final ObjectNameNormalizer normalizer = new ObjectNameNormalizerImpl(); diff --git a/core/src/main/java/org/hibernate/cfg/Mappings.java b/core/src/main/java/org/hibernate/cfg/Mappings.java index c2aef4eca2..7e721b7300 100644 --- a/core/src/main/java/org/hibernate/cfg/Mappings.java +++ b/core/src/main/java/org/hibernate/cfg/Mappings.java @@ -550,4 +550,11 @@ public PropertyReference(String referencedClass, String propertyName, boolean un * @return The normalizer. */ public ObjectNameNormalizer getObjectNameNormalizer(); + + /** + * Retrieve the configuration properties currently in effect. + * + * @return The configuration properties + */ + public Properties getConfigurationProperties(); } \ No newline at end of file diff --git a/core/src/main/java/org/hibernate/cfg/SettingsFactory.java b/core/src/main/java/org/hibernate/cfg/SettingsFactory.java index 3b2fc8197b..543b2283cc 100644 --- a/core/src/main/java/org/hibernate/cfg/SettingsFactory.java +++ b/core/src/main/java/org/hibernate/cfg/SettingsFactory.java @@ -380,7 +380,7 @@ protected QueryCacheFactory createQueryCacheFactory(Properties properties) { } } - protected RegionFactory createRegionFactory(Properties properties, boolean cachingEnabled) { + public static RegionFactory createRegionFactory(Properties properties, boolean cachingEnabled) { String regionFactoryClassName = PropertiesHelper.getString( Environment.CACHE_REGION_FACTORY, properties, null ); if ( regionFactoryClassName == null && cachingEnabled ) { String providerClassName = PropertiesHelper.getString( Environment.CACHE_PROVIDER, properties, null ); diff --git a/entitymanager/src/test/java/org/hibernate/ejb/test/cacheable/annotation/ConfigurationTest.java b/entitymanager/src/test/java/org/hibernate/ejb/test/cacheable/annotation/ConfigurationTest.java new file mode 100644 index 0000000000..c518919303 --- /dev/null +++ b/entitymanager/src/test/java/org/hibernate/ejb/test/cacheable/annotation/ConfigurationTest.java @@ -0,0 +1,120 @@ +/* + * 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.ejb.test.cacheable.annotation; + +import java.util.Properties; +import javax.persistence.SharedCacheMode; + +import org.hibernate.ejb.AvailableSettings; +import org.hibernate.ejb.Ejb3Configuration; +import org.hibernate.junit.UnitTestCase; +import org.hibernate.mapping.PersistentClass; + +/** + * TODO : javadoc + * + * @author Steve Ebersole + */ +public class ConfigurationTest extends UnitTestCase { + public ConfigurationTest(String string) { + super( string ); + } + + public void testSharedCacheModeNone() { + Ejb3Configuration config = buildConfiguration( SharedCacheMode.NONE ); + + PersistentClass pc = config.getClassMapping( ExplicitlyCacheableEntity.class.getName() ); + assertNull( pc.getCacheConcurrencyStrategy() ); + + pc = config.getClassMapping( ExplicitlyNonCacheableEntity.class.getName() ); + assertNull( pc.getCacheConcurrencyStrategy() ); + + pc = config.getClassMapping( NoCacheableAnnotationEntity.class.getName() ); + assertNull( pc.getCacheConcurrencyStrategy() ); + } + + public void testSharedCacheModeUnspecified() { + Ejb3Configuration config = buildConfiguration( SharedCacheMode.UNSPECIFIED ); + + PersistentClass pc = config.getClassMapping( ExplicitlyCacheableEntity.class.getName() ); + assertNull( pc.getCacheConcurrencyStrategy() ); + + pc = config.getClassMapping( ExplicitlyNonCacheableEntity.class.getName() ); + assertNull( pc.getCacheConcurrencyStrategy() ); + + pc = config.getClassMapping( NoCacheableAnnotationEntity.class.getName() ); + assertNull( pc.getCacheConcurrencyStrategy() ); + } + + public void testSharedCacheModeAll() { + Ejb3Configuration config = buildConfiguration( SharedCacheMode.ALL ); + + PersistentClass pc = config.getClassMapping( ExplicitlyCacheableEntity.class.getName() ); + assertNotNull( pc.getCacheConcurrencyStrategy() ); + + pc = config.getClassMapping( ExplicitlyNonCacheableEntity.class.getName() ); + assertNotNull( pc.getCacheConcurrencyStrategy() ); + + pc = config.getClassMapping( NoCacheableAnnotationEntity.class.getName() ); + assertNotNull( pc.getCacheConcurrencyStrategy() ); + } + + public void testSharedCacheModeEnable() { + Ejb3Configuration config = buildConfiguration( SharedCacheMode.ENABLE_SELECTIVE ); + + PersistentClass pc = config.getClassMapping( ExplicitlyCacheableEntity.class.getName() ); + assertNotNull( pc.getCacheConcurrencyStrategy() ); + + pc = config.getClassMapping( ExplicitlyNonCacheableEntity.class.getName() ); + assertNull( pc.getCacheConcurrencyStrategy() ); + + pc = config.getClassMapping( NoCacheableAnnotationEntity.class.getName() ); + assertNull( pc.getCacheConcurrencyStrategy() ); + } + + public void testSharedCacheModeDisable() { + Ejb3Configuration config = buildConfiguration( SharedCacheMode.DISABLE_SELECTIVE ); + + PersistentClass pc = config.getClassMapping( ExplicitlyCacheableEntity.class.getName() ); + assertNotNull( pc.getCacheConcurrencyStrategy() ); + + pc = config.getClassMapping( ExplicitlyNonCacheableEntity.class.getName() ); + assertNull( pc.getCacheConcurrencyStrategy() ); + + pc = config.getClassMapping( NoCacheableAnnotationEntity.class.getName() ); + assertNotNull( pc.getCacheConcurrencyStrategy() ); + } + + private Ejb3Configuration buildConfiguration(SharedCacheMode mode) { + Properties properties = new Properties(); + properties.put( AvailableSettings.SHARED_CACHE_MODE, mode ); + Ejb3Configuration config = new Ejb3Configuration(); + config.setProperties( properties ); + config.addAnnotatedClass( ExplicitlyCacheableEntity.class ); + config.addAnnotatedClass( ExplicitlyNonCacheableEntity.class ); + config.addAnnotatedClass( NoCacheableAnnotationEntity.class ); + config.buildMappings(); + return config; + } +} diff --git a/entitymanager/src/test/java/org/hibernate/ejb/test/cacheable/annotation/ExplicitlyCacheableEntity.java b/entitymanager/src/test/java/org/hibernate/ejb/test/cacheable/annotation/ExplicitlyCacheableEntity.java new file mode 100644 index 0000000000..2a91625917 --- /dev/null +++ b/entitymanager/src/test/java/org/hibernate/ejb/test/cacheable/annotation/ExplicitlyCacheableEntity.java @@ -0,0 +1,57 @@ +/* + * 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.ejb.test.cacheable.annotation; + +import javax.persistence.Cacheable; +import javax.persistence.Entity; +import javax.persistence.Id; + +/** + * TODO : javadoc + * + * @author Steve Ebersole + */ +@Entity +@Cacheable +public class ExplicitlyCacheableEntity { + private Long id; + private String name; + + @Id + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } +} \ No newline at end of file diff --git a/entitymanager/src/test/java/org/hibernate/ejb/test/cacheable/annotation/ExplicitlyNonCacheableEntity.java b/entitymanager/src/test/java/org/hibernate/ejb/test/cacheable/annotation/ExplicitlyNonCacheableEntity.java new file mode 100644 index 0000000000..35eee194ed --- /dev/null +++ b/entitymanager/src/test/java/org/hibernate/ejb/test/cacheable/annotation/ExplicitlyNonCacheableEntity.java @@ -0,0 +1,57 @@ +/* + * 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.ejb.test.cacheable.annotation; + +import javax.persistence.Cacheable; +import javax.persistence.Entity; +import javax.persistence.Id; + +/** + * TODO : javadoc + * + * @author Steve Ebersole + */ +@Entity +@Cacheable(false) +public class ExplicitlyNonCacheableEntity { + private Long id; + private String name; + + @Id + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } +} diff --git a/entitymanager/src/test/java/org/hibernate/ejb/test/cacheable/annotation/NoCacheableAnnotationEntity.java b/entitymanager/src/test/java/org/hibernate/ejb/test/cacheable/annotation/NoCacheableAnnotationEntity.java new file mode 100644 index 0000000000..ea836a7428 --- /dev/null +++ b/entitymanager/src/test/java/org/hibernate/ejb/test/cacheable/annotation/NoCacheableAnnotationEntity.java @@ -0,0 +1,56 @@ +/* + * 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.ejb.test.cacheable.annotation; + +import javax.persistence.Cacheable; +import javax.persistence.Entity; +import javax.persistence.Id; + +/** + * TODO : javadoc + * + * @author Steve Ebersole + */ +@Entity +public class NoCacheableAnnotationEntity { + private Long id; + private String name; + + @Id + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } +} \ No newline at end of file