From 850cfda6c3fe497b5e7b52a13f35010665465234 Mon Sep 17 00:00:00 2001 From: Hardy Ferentschik Date: Wed, 11 May 2011 15:12:06 +0200 Subject: [PATCH] HHH-6207 Implementing binding of @Cacheable. Changing implementation of Caching to use AccessType enum instead of string --- .../hibernate/metamodel/MetadataBuilder.java | 7 ++ .../hibernate/metamodel/MetadataSources.java | 5 +- .../hibernate/metamodel/binding/Caching.java | 28 +++-- .../source/annotations/EntityBinder.java | 100 +++++++++++++----- .../source/hbm/RootEntityBinder.java | 6 +- .../source/internal/MetadataBuilderImpl.java | 13 +++ .../source/internal/MetadataImpl.java | 11 +- .../source/annotations/CacheBindingTests.java | 18 ++-- 8 files changed, 144 insertions(+), 44 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/MetadataBuilder.java b/hibernate-core/src/main/java/org/hibernate/metamodel/MetadataBuilder.java index fa96eebf9d..1499f53c6d 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/MetadataBuilder.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/MetadataBuilder.java @@ -23,13 +23,20 @@ */ package org.hibernate.metamodel; +import javax.persistence.SharedCacheMode; + import org.hibernate.cfg.NamingStrategy; /** * @author Steve Ebersole + * @author Hardy Ferentschik */ public interface MetadataBuilder { public MetadataBuilder with(NamingStrategy namingStrategy); + public MetadataBuilder with(SourceProcessingOrder sourceProcessingOrder); + + public MetadataBuilder with(SharedCacheMode cacheMode); + public Metadata buildMetadata(); } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/MetadataSources.java b/hibernate-core/src/main/java/org/hibernate/metamodel/MetadataSources.java index 190c074b63..21fdeb22ac 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/MetadataSources.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/MetadataSources.java @@ -69,6 +69,8 @@ public class MetadataSources { private final EntityResolver entityResolver; private final NamingStrategy namingStrategy; + private final MetadataBuilderImpl metadataBuilder; + public MetadataSources(BasicServiceRegistry serviceRegistry) { this( serviceRegistry, EJB3DTDEntityResolver.INSTANCE, EJB3NamingStrategy.INSTANCE ); } @@ -79,6 +81,7 @@ public class MetadataSources { this.namingStrategy = namingStrategy; this.jaxbHelper = new JaxbHelper( this ); + this.metadataBuilder = new MetadataBuilderImpl( this ); } public List getJaxbRootList() { @@ -102,7 +105,7 @@ public class MetadataSources { } public MetadataBuilder getMetadataBuilder() { - return new MetadataBuilderImpl( this ); + return metadataBuilder; } public Metadata buildMetadata() { diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/binding/Caching.java b/hibernate-core/src/main/java/org/hibernate/metamodel/binding/Caching.java index ef1838d6d4..e4a9e0ed12 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/binding/Caching.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/binding/Caching.java @@ -23,22 +23,25 @@ */ package org.hibernate.metamodel.binding; +import org.hibernate.cache.spi.access.AccessType; + /** * Defines the caching settings for an entity. * * @author Steve Ebersole + * @author Hardy Ferentschik */ public class Caching { private String region; - private String strategy; + private AccessType accessType; private boolean cacheLazyProperties; public Caching() { } - public Caching(String region, String strategy, boolean cacheLazyProperties) { + public Caching(String region, AccessType accessType, boolean cacheLazyProperties) { this.region = region; - this.strategy = strategy; + this.accessType = accessType; this.cacheLazyProperties = cacheLazyProperties; } @@ -50,12 +53,12 @@ public class Caching { this.region = region; } - public String getStrategy() { - return strategy; + public AccessType getAccessType() { + return accessType; } - public void setStrategy(String strategy) { - this.strategy = strategy; + public void setAccessType(AccessType accessType) { + this.accessType = accessType; } public boolean isCacheLazyProperties() { @@ -65,4 +68,15 @@ public class Caching { public void setCacheLazyProperties(boolean cacheLazyProperties) { this.cacheLazyProperties = cacheLazyProperties; } + + @Override + public String toString() { + final StringBuilder sb = new StringBuilder(); + sb.append( "Caching" ); + sb.append( "{region='" ).append( region ).append( '\'' ); + sb.append( ", accessType=" ).append( accessType ); + sb.append( ", cacheLazyProperties=" ).append( cacheLazyProperties ); + sb.append( '}' ); + return sb.toString(); + } } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/source/annotations/EntityBinder.java b/hibernate-core/src/main/java/org/hibernate/metamodel/source/annotations/EntityBinder.java index 40ffde4883..3be6aa21cc 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/source/annotations/EntityBinder.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/source/annotations/EntityBinder.java @@ -34,6 +34,8 @@ import org.hibernate.MappingException; import org.hibernate.annotations.CacheConcurrencyStrategy; import org.hibernate.annotations.OptimisticLockType; import org.hibernate.annotations.PolymorphismType; +import org.hibernate.cache.spi.RegionFactory; +import org.hibernate.cache.spi.access.AccessType; import org.hibernate.internal.util.StringHelper; import org.hibernate.metamodel.binding.Caching; import org.hibernate.metamodel.binding.EntityBinding; @@ -70,7 +72,8 @@ public class EntityBinder { bindJpaEntityAnnotation( entityBinding ); bindHibernateEntityAnnotation( entityBinding ); // optional hibernate specific @org.hibernate.annotations.Entity bindWhereFilter( entityBinding ); - bindCaching( entityBinding ); + bindJpaCaching( entityBinding ); + bindHibernateCaching( entityBinding ); schemaName = createSchemaName(); bindTable( entityBinding ); @@ -93,41 +96,90 @@ public class EntityBinder { } } - private void bindCaching(EntityBinding entityBinding) { + private void bindHibernateCaching(EntityBinding entityBinding) { AnnotationInstance cacheAnnotation = JandexHelper.getSingleAnnotation( configuredClass.getClassInfo(), HibernateDotNames.CACHE ); - if ( cacheAnnotation != null ) { - String region; - if ( cacheAnnotation.value( "region" ) != null ) { - region = cacheAnnotation.value( "region" ).asString(); + if ( cacheAnnotation == null ) { + return; + } + + String region; + if ( cacheAnnotation.value( "region" ) != null ) { + region = cacheAnnotation.value( "region" ).asString(); + } + else { + region = entityBinding.getEntity().getName(); + } + + boolean cacheLazyProperties = true; + if ( cacheAnnotation.value( "include" ) != null ) { + String tmp = cacheAnnotation.value( "include" ).asString(); + if ( "all".equalsIgnoreCase( tmp ) ) { + cacheLazyProperties = true; + } + else if ( "non-lazy".equalsIgnoreCase( tmp ) ) { + cacheLazyProperties = false; } else { - region = entityBinding.getEntity().getName(); + throw new AnnotationException( "Unknown lazy property annotations: " + tmp ); } + } - boolean cacheLazyProperties = true; - if ( cacheAnnotation.value( "include" ) != null ) { - String tmp = cacheAnnotation.value( "include" ).asString(); - if ( "all".equalsIgnoreCase( tmp ) ) { - cacheLazyProperties = true; - } - else if ( "non-lazy".equalsIgnoreCase( tmp ) ) { - cacheLazyProperties = false; - } - else { - throw new AnnotationException( "Unknown lazy property annotations: " + tmp ); - } + CacheConcurrencyStrategy strategy = CacheConcurrencyStrategy.valueOf( + cacheAnnotation.value( "usage" ).asEnum() + ); + Caching caching = new Caching( region, strategy.toAccessType(), cacheLazyProperties ); + entityBinding.setCaching( caching ); + } + + // This does not take care of any inheritance of @Cacheable within a class hierarchy as specified in JPA2. + // This is currently not supported (HF) + private void bindJpaCaching(EntityBinding entityBinding) { + AnnotationInstance cacheAnnotation = JandexHelper.getSingleAnnotation( + configuredClass.getClassInfo(), JPADotNames.CACHEABLE + ); + + boolean cacheable = true; // true is the default + if ( cacheAnnotation != null && cacheAnnotation.value() != null ) { + cacheable = cacheAnnotation.value().asBoolean(); + } + + Caching caching = null; + switch ( meta.getSharedCacheMode() ) { + case ALL: { + caching = createCachingForCacheableAnnotation( entityBinding ); + break; } - - CacheConcurrencyStrategy strategy = CacheConcurrencyStrategy.valueOf( - cacheAnnotation.value( "usage" ).asEnum() - ); - Caching caching = new Caching( region, strategy.toAccessType().getExternalName(), cacheLazyProperties ); + case ENABLE_SELECTIVE: { + if ( cacheable ) { + caching = createCachingForCacheableAnnotation( entityBinding ); + } + break; + } + case DISABLE_SELECTIVE: { + if ( cacheAnnotation == null || cacheable ) { + caching = createCachingForCacheableAnnotation( entityBinding ); + } + break; + } + default: { + // treat both NONE and UNSPECIFIED the same + break; + } + } + if ( caching != null ) { entityBinding.setCaching( caching ); } } + private Caching createCachingForCacheableAnnotation(EntityBinding entityBinding) { + String region = entityBinding.getEntity().getName(); + RegionFactory regionFactory = meta.getServiceRegistry().getService( RegionFactory.class ); + AccessType defaultAccessType = regionFactory.getDefaultAccessType(); + return new Caching( region, defaultAccessType, true ); + } + private Schema.Name createSchemaName() { String schema = null; String catalog = null; diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/source/hbm/RootEntityBinder.java b/hibernate-core/src/main/java/org/hibernate/metamodel/source/hbm/RootEntityBinder.java index a4b7f196f8..112fb24fd4 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/source/hbm/RootEntityBinder.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/source/hbm/RootEntityBinder.java @@ -25,6 +25,7 @@ package org.hibernate.metamodel.source.hbm; import org.hibernate.InvalidMappingException; import org.hibernate.MappingException; +import org.hibernate.cache.spi.access.AccessType; import org.hibernate.mapping.RootClass; import org.hibernate.metamodel.binding.Caching; import org.hibernate.metamodel.binding.EntityBinding; @@ -286,9 +287,8 @@ class RootEntityBinder extends AbstractEntityBinder { return; } final String region = cache.getRegion() != null ? cache.getRegion() : entityBinding.getEntity().getName(); - final String strategy = cache.getUsage(); + final AccessType accessType = Enum.valueOf( AccessType.class, cache.getUsage() ); final boolean cacheLazyProps = !"non-lazy".equals( cache.getInclude() ); - entityBinding.setCaching( new Caching( region, strategy, cacheLazyProps ) ); + entityBinding.setCaching( new Caching( region, accessType, cacheLazyProps ) ); } - } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/source/internal/MetadataBuilderImpl.java b/hibernate-core/src/main/java/org/hibernate/metamodel/source/internal/MetadataBuilderImpl.java index 516219f7e1..ff15136673 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/source/internal/MetadataBuilderImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/source/internal/MetadataBuilderImpl.java @@ -23,6 +23,8 @@ */ package org.hibernate.metamodel.source.internal; +import javax.persistence.SharedCacheMode; + import org.hibernate.cfg.EJB3NamingStrategy; import org.hibernate.cfg.NamingStrategy; import org.hibernate.metamodel.Metadata; @@ -38,6 +40,7 @@ public class MetadataBuilderImpl implements MetadataBuilder { private NamingStrategy namingStrategy = EJB3NamingStrategy.INSTANCE; private SourceProcessingOrder sourceProcessingOrder = SourceProcessingOrder.HBM_FIRST; + private SharedCacheMode sharedCacheMode = SharedCacheMode.ENABLE_SELECTIVE; public MetadataBuilderImpl(MetadataSources sources) { this.sources = sources; @@ -51,6 +54,10 @@ public class MetadataBuilderImpl implements MetadataBuilder { return namingStrategy; } + public SharedCacheMode getSharedCacheMode() { + return sharedCacheMode; + } + public SourceProcessingOrder getSourceProcessingOrder() { return sourceProcessingOrder; } @@ -67,6 +74,12 @@ public class MetadataBuilderImpl implements MetadataBuilder { return this; } + @Override + public MetadataBuilder with(SharedCacheMode sharedCacheMode) { + this.sharedCacheMode = sharedCacheMode; + return this; + } + @Override public Metadata buildMetadata() { return new MetadataImpl( this ); diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/source/internal/MetadataImpl.java b/hibernate-core/src/main/java/org/hibernate/metamodel/source/internal/MetadataImpl.java index 8a238435b4..05e9e50e8a 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/source/internal/MetadataImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/source/internal/MetadataImpl.java @@ -30,6 +30,7 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; +import javax.persistence.SharedCacheMode; import org.jboss.jandex.Index; import org.jboss.jandex.Indexer; @@ -40,13 +41,13 @@ import org.hibernate.HibernateException; import org.hibernate.cfg.NamingStrategy; import org.hibernate.internal.CoreMessageLogger; import org.hibernate.mapping.MetadataSource; +import org.hibernate.metamodel.Metadata; +import org.hibernate.metamodel.MetadataSources; import org.hibernate.metamodel.SourceProcessingOrder; import org.hibernate.metamodel.binding.EntityBinding; import org.hibernate.metamodel.binding.FetchProfile; import org.hibernate.metamodel.binding.PluralAttributeBinding; import org.hibernate.metamodel.relational.Database; -import org.hibernate.metamodel.Metadata; -import org.hibernate.metamodel.MetadataSources; import org.hibernate.metamodel.source.annotation.xml.XMLEntityMappings; import org.hibernate.metamodel.source.annotations.AnnotationBinder; import org.hibernate.metamodel.source.annotations.xml.OrmXmlParser; @@ -69,6 +70,7 @@ public class MetadataImpl implements Metadata, MetadataImplementor, Serializable private final BasicServiceRegistry serviceRegistry; private final NamingStrategy namingStrategy; + private final SharedCacheMode sharedCacheMode; private final Database database = new Database(); private Map entityBindingMap = new HashMap(); @@ -81,6 +83,7 @@ public class MetadataImpl implements Metadata, MetadataImplementor, Serializable this.serviceRegistry = metadataSources.getServiceRegistry(); this.namingStrategy = builder.getNamingStrategy(); + this.sharedCacheMode = builder.getSharedCacheMode(); final ArrayList processedEntityNames = new ArrayList(); if ( builder.getSourceProcessingOrder() == SourceProcessingOrder.HBM_FIRST ) { @@ -162,6 +165,10 @@ public class MetadataImpl implements Metadata, MetadataImplementor, Serializable return namingStrategy; } + public SharedCacheMode getSharedCacheMode() { + return sharedCacheMode; + } + public EntityBinding getEntityBinding(String entityName) { return entityBindingMap.get( entityName ); } diff --git a/hibernate-core/src/test/java/org/hibernate/metamodel/source/annotations/CacheBindingTests.java b/hibernate-core/src/test/java/org/hibernate/metamodel/source/annotations/CacheBindingTests.java index f24facb429..b35f23a53e 100644 --- a/hibernate-core/src/test/java/org/hibernate/metamodel/source/annotations/CacheBindingTests.java +++ b/hibernate-core/src/test/java/org/hibernate/metamodel/source/annotations/CacheBindingTests.java @@ -26,17 +26,18 @@ package org.hibernate.metamodel.source.annotations; import javax.persistence.Cacheable; import javax.persistence.Entity; import javax.persistence.Id; +import javax.persistence.SharedCacheMode; import org.junit.Test; import org.hibernate.annotations.Cache; import org.hibernate.annotations.CacheConcurrencyStrategy; +import org.hibernate.cache.spi.access.AccessType; import org.hibernate.metamodel.MetadataSources; import org.hibernate.metamodel.binding.Caching; import org.hibernate.metamodel.binding.EntityBinding; import org.hibernate.metamodel.source.internal.MetadataImpl; import org.hibernate.service.ServiceRegistryBuilder; -import org.hibernate.testing.FailureExpected; import org.hibernate.testing.junit4.BaseUnitTestCase; import static junit.framework.Assert.assertEquals; @@ -51,30 +52,33 @@ import static junit.framework.Assert.assertNull; public class CacheBindingTests extends BaseUnitTestCase { @Test public void testHibernateCaching() { - EntityBinding binding = getEntityBinding( HibernateCacheEntity.class ); + EntityBinding binding = getEntityBinding( HibernateCacheEntity.class, SharedCacheMode.ALL ); assertNotNull( "There should be a cache binding", binding.getCaching() ); Caching caching = binding.getCaching(); assertEquals( "Wrong region", "foo", caching.getRegion() ); - assertEquals( "Wrong strategy", "read-write", caching.getStrategy() ); + assertEquals( "Wrong strategy", AccessType.READ_WRITE, caching.getAccessType() ); assertEquals( "Wrong lazy properties configuration", false, caching.isCacheLazyProperties() ); } @Test - @FailureExpected( jiraKey = "HHH-6207", message = "under construction") public void testJpaCaching() { - EntityBinding binding = getEntityBinding( JpaCacheEntity.class ); + EntityBinding binding = getEntityBinding( JpaCacheEntity.class, SharedCacheMode.ALL ); assertNotNull( "There should be a cache binding", binding.getCaching() ); + Caching caching = binding.getCaching(); + assertEquals( "Wrong region", "CacheBindingTests$JpaCacheEntity", caching.getRegion() ); + assertEquals( "Wrong lazy properties configuration", true, caching.isCacheLazyProperties() ); } @Test public void testNoCaching() { - EntityBinding binding = getEntityBinding( NoCacheEntity.class ); + EntityBinding binding = getEntityBinding( NoCacheEntity.class, SharedCacheMode.NONE ); assertNull( "There should be no cache binding", binding.getCaching() ); } - private EntityBinding getEntityBinding(Class clazz) { + private EntityBinding getEntityBinding(Class clazz, SharedCacheMode cacheMode) { MetadataSources sources = new MetadataSources( new ServiceRegistryBuilder().buildServiceRegistry() ); sources.addAnnotatedClass( clazz ); + sources.getMetadataBuilder().with( cacheMode ); MetadataImpl metadata = (MetadataImpl) sources.buildMetadata(); return metadata.getEntityBinding( this.getClass().getSimpleName() + "$" + clazz.getSimpleName() );