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
This commit is contained in:
Steve Ebersole 2010-01-22 07:22:50 +00:00
parent 70ddcd81f2
commit d24ed1a1d3
10 changed files with 391 additions and 5 deletions

View File

@ -24,6 +24,7 @@
*/ */
package org.hibernate.cfg; package org.hibernate.cfg;
import java.lang.annotation.Annotation;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collection; import java.util.Collection;
@ -36,6 +37,7 @@ import java.util.Map;
import java.util.Properties; import java.util.Properties;
import java.util.Set; import java.util.Set;
import javax.persistence.Basic; import javax.persistence.Basic;
import javax.persistence.Cacheable;
import javax.persistence.Column; import javax.persistence.Column;
import javax.persistence.DiscriminatorType; import javax.persistence.DiscriminatorType;
import javax.persistence.DiscriminatorValue; import javax.persistence.DiscriminatorValue;
@ -66,6 +68,7 @@ import javax.persistence.OneToOne;
import javax.persistence.PrimaryKeyJoinColumn; import javax.persistence.PrimaryKeyJoinColumn;
import javax.persistence.PrimaryKeyJoinColumns; import javax.persistence.PrimaryKeyJoinColumns;
import javax.persistence.SequenceGenerator; import javax.persistence.SequenceGenerator;
import javax.persistence.SharedCacheMode;
import javax.persistence.SqlResultSetMapping; import javax.persistence.SqlResultSetMapping;
import javax.persistence.SqlResultSetMappings; import javax.persistence.SqlResultSetMappings;
import javax.persistence.Table; import javax.persistence.Table;
@ -86,6 +89,7 @@ import org.hibernate.FetchMode;
import org.hibernate.MappingException; import org.hibernate.MappingException;
import org.hibernate.annotations.BatchSize; import org.hibernate.annotations.BatchSize;
import org.hibernate.annotations.Cache; import org.hibernate.annotations.Cache;
import org.hibernate.annotations.CacheConcurrencyStrategy;
import org.hibernate.annotations.Cascade; import org.hibernate.annotations.Cascade;
import org.hibernate.annotations.CascadeType; import org.hibernate.annotations.CascadeType;
import org.hibernate.annotations.Check; import org.hibernate.annotations.Check;
@ -128,6 +132,7 @@ import org.hibernate.annotations.common.reflection.XClass;
import org.hibernate.annotations.common.reflection.XMethod; import org.hibernate.annotations.common.reflection.XMethod;
import org.hibernate.annotations.common.reflection.XPackage; import org.hibernate.annotations.common.reflection.XPackage;
import org.hibernate.annotations.common.reflection.XProperty; import org.hibernate.annotations.common.reflection.XProperty;
import org.hibernate.cache.RegionFactory;
import org.hibernate.cfg.annotations.CollectionBinder; import org.hibernate.cfg.annotations.CollectionBinder;
import org.hibernate.cfg.annotations.EntityBinder; import org.hibernate.cfg.annotations.EntityBinder;
import org.hibernate.cfg.annotations.Nullability; import org.hibernate.cfg.annotations.Nullability;
@ -505,9 +510,9 @@ public final class AnnotationBinder {
org.hibernate.annotations.Entity hibEntityAnn = clazzToProcess.getAnnotation( org.hibernate.annotations.Entity hibEntityAnn = clazzToProcess.getAnnotation(
org.hibernate.annotations.Entity.class 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( EntityBinder entityBinder = new EntityBinder(
entityAnn, hibEntityAnn, clazzToProcess, persistentClass, mappings entityAnn, hibEntityAnn, clazzToProcess, persistentClass, mappings
); );
@ -765,6 +770,84 @@ public final class AnnotationBinder {
} }
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<? extends Annotation> annotationType() {
return Cache.class;
}
}
private static PersistentClass makePersistentClass(InheritanceState inheritanceState, PersistentClass superEntity) { private static PersistentClass makePersistentClass(InheritanceState inheritanceState, PersistentClass superEntity) {
//we now know what kind of persistent entity it is //we now know what kind of persistent entity it is
PersistentClass persistentClass; PersistentClass persistentClass;

View File

@ -68,6 +68,7 @@ import org.hibernate.MappingException;
import org.hibernate.Session; import org.hibernate.Session;
import org.hibernate.SessionFactory; import org.hibernate.SessionFactory;
import org.hibernate.annotations.AnyMetaDef; import org.hibernate.annotations.AnyMetaDef;
import org.hibernate.annotations.Cache;
import org.hibernate.annotations.common.reflection.MetadataProvider; import org.hibernate.annotations.common.reflection.MetadataProvider;
import org.hibernate.annotations.common.reflection.MetadataProviderInjector; import org.hibernate.annotations.common.reflection.MetadataProviderInjector;
import org.hibernate.annotations.common.reflection.ReflectionManager; import org.hibernate.annotations.common.reflection.ReflectionManager;

View File

@ -30,6 +30,7 @@ import java.util.Properties;
import org.hibernate.AnnotationException; import org.hibernate.AnnotationException;
import org.hibernate.MappingException; import org.hibernate.MappingException;
import org.hibernate.annotations.AnyMetaDef; import org.hibernate.annotations.AnyMetaDef;
import org.hibernate.annotations.Cache;
import org.hibernate.annotations.common.reflection.ReflectionManager; import org.hibernate.annotations.common.reflection.ReflectionManager;
import org.hibernate.annotations.common.reflection.XClass; import org.hibernate.annotations.common.reflection.XClass;
import org.hibernate.engine.NamedQueryDefinition; import org.hibernate.engine.NamedQueryDefinition;

View File

@ -474,7 +474,7 @@ public class Configuration implements Serializable {
/** /**
* <b>INTENDED FOR TESTSUITE USE ONLY!</b> * <b>INTENDED FOR TESTSUITE USE ONLY!</b>
* <p/> * <p/>
* 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 * the cache version cannot be found or used for whatever reason
* *
* @param xmlFile The xml file, not the bin! * @param xmlFile The xml file, not the bin!
@ -2797,6 +2797,10 @@ public class Configuration implements Serializable {
public ObjectNameNormalizer getObjectNameNormalizer() { public ObjectNameNormalizer getObjectNameNormalizer() {
return normalizer; return normalizer;
} }
public Properties getConfigurationProperties() {
return properties;
}
} }
final ObjectNameNormalizer normalizer = new ObjectNameNormalizerImpl(); final ObjectNameNormalizer normalizer = new ObjectNameNormalizerImpl();

View File

@ -550,4 +550,11 @@ public interface Mappings {
* @return The normalizer. * @return The normalizer.
*/ */
public ObjectNameNormalizer getObjectNameNormalizer(); public ObjectNameNormalizer getObjectNameNormalizer();
/**
* Retrieve the configuration properties currently in effect.
*
* @return The configuration properties
*/
public Properties getConfigurationProperties();
} }

View File

@ -380,7 +380,7 @@ public class SettingsFactory implements Serializable {
} }
} }
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 ); String regionFactoryClassName = PropertiesHelper.getString( Environment.CACHE_REGION_FACTORY, properties, null );
if ( regionFactoryClassName == null && cachingEnabled ) { if ( regionFactoryClassName == null && cachingEnabled ) {
String providerClassName = PropertiesHelper.getString( Environment.CACHE_PROVIDER, properties, null ); String providerClassName = PropertiesHelper.getString( Environment.CACHE_PROVIDER, properties, null );

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}