From c47352058541e14e0b80d38f94c65d939d5394f5 Mon Sep 17 00:00:00 2001 From: Eric Dalquist Date: Fri, 27 Jan 2012 16:46:25 -0600 Subject: [PATCH] HHH-6974 Class level naturalId cache and stats Add class level @NaturalIdCache annotation to denote if second level natualId caching should be done Flush out stats model for naturalId cache related stats Add ehcache support classes for naturalId region --- .../org/hibernate/annotations/NaturalId.java | 14 +- .../hibernate/annotations/NaturalIdCache.java | 44 ++++ .../hibernate/cache/spi/NaturalIdRegion.java | 47 ++++ .../access/NaturalIdRegionAccessStrategy.java | 50 ++++ .../org/hibernate/cfg/AnnotationBinder.java | 6 +- .../cfg/annotations/EntityBinder.java | 29 ++- .../engine/spi/SessionFactoryImplementor.java | 8 + .../internal/SessionFactoryImpl.java | 21 +- .../org/hibernate/jmx/StatisticsService.java | 18 ++ .../hibernate/mapping/PersistentClass.java | 1 + .../java/org/hibernate/mapping/RootClass.java | 12 +- .../java/org/hibernate/mapping/Subclass.java | 5 + .../entity/AbstractEntityPersister.java | 8 +- .../persister/entity/EntityPersister.java | 7 - .../stat/NaturalIdCacheStatistics.java | 50 ++++ .../java/org/hibernate/stat/Statistics.java | 20 ++ ...oncurrentNaturalIdCacheStatisticsImpl.java | 112 +++++++++ .../internal/ConcurrentStatisticsImpl.java | 74 +++++- .../stat/spi/StatisticsImplementor.java | 22 ++ .../tuple/entity/EntityMetamodel.java | 4 +- .../annotations/naturalid/NaturalIdTest.java | 58 ++++- .../GoofyPersisterClassProvider.java | 5 - .../test/legacy/CustomPersister.java | 5 - ...topAwareNaturalIdRegionAccessStrategy.java | 227 ++++++++++++++++++ .../regions/EhcacheNaturalIdRegion.java | 66 +++++ ...eEhcacheNaturalIdRegionAccessStrategy.java | 99 ++++++++ ...yEhcacheNaturalIdRegionAccessStrategy.java | 93 +++++++ ...eEhcacheNaturalIdRegionAccessStrategy.java | 54 +++++ ...lEhcacheNaturalIdRegionAccessStrategy.java | 127 ++++++++++ .../PersisterClassProviderTest.java | 5 - .../BaseNaturalIdRegionAccessStrategy.java | 53 ++++ .../testing/cache/NaturalIdRegionImpl.java | 73 ++++++ ...eadWriteNaturalIdRegionAccessStrategy.java | 45 ++++ ...ReadOnlyNaturalIdRegionAccessStrategy.java | 57 +++++ ...eadWriteNaturalIdRegionAccessStrategy.java | 62 +++++ ...actionalNaturalIdRegionAccessStrategy.java | 25 ++ 36 files changed, 1539 insertions(+), 67 deletions(-) create mode 100644 hibernate-core/src/main/java/org/hibernate/annotations/NaturalIdCache.java create mode 100644 hibernate-core/src/main/java/org/hibernate/cache/spi/NaturalIdRegion.java create mode 100644 hibernate-core/src/main/java/org/hibernate/cache/spi/access/NaturalIdRegionAccessStrategy.java create mode 100644 hibernate-core/src/main/java/org/hibernate/stat/NaturalIdCacheStatistics.java create mode 100644 hibernate-core/src/main/java/org/hibernate/stat/internal/ConcurrentNaturalIdCacheStatisticsImpl.java create mode 100644 hibernate-ehcache/src/main/java/org/hibernate/cache/ehcache/internal/nonstop/NonstopAwareNaturalIdRegionAccessStrategy.java create mode 100644 hibernate-ehcache/src/main/java/org/hibernate/cache/ehcache/internal/regions/EhcacheNaturalIdRegion.java create mode 100644 hibernate-ehcache/src/main/java/org/hibernate/cache/ehcache/internal/strategy/NonStrictReadWriteEhcacheNaturalIdRegionAccessStrategy.java create mode 100644 hibernate-ehcache/src/main/java/org/hibernate/cache/ehcache/internal/strategy/ReadOnlyEhcacheNaturalIdRegionAccessStrategy.java create mode 100644 hibernate-ehcache/src/main/java/org/hibernate/cache/ehcache/internal/strategy/ReadWriteEhcacheNaturalIdRegionAccessStrategy.java create mode 100644 hibernate-ehcache/src/main/java/org/hibernate/cache/ehcache/internal/strategy/TransactionalEhcacheNaturalIdRegionAccessStrategy.java create mode 100644 hibernate-testing/src/main/java/org/hibernate/testing/cache/BaseNaturalIdRegionAccessStrategy.java create mode 100644 hibernate-testing/src/main/java/org/hibernate/testing/cache/NaturalIdRegionImpl.java create mode 100644 hibernate-testing/src/main/java/org/hibernate/testing/cache/NonstrictReadWriteNaturalIdRegionAccessStrategy.java create mode 100644 hibernate-testing/src/main/java/org/hibernate/testing/cache/ReadOnlyNaturalIdRegionAccessStrategy.java create mode 100644 hibernate-testing/src/main/java/org/hibernate/testing/cache/ReadWriteNaturalIdRegionAccessStrategy.java create mode 100644 hibernate-testing/src/main/java/org/hibernate/testing/cache/TransactionalNaturalIdRegionAccessStrategy.java diff --git a/hibernate-core/src/main/java/org/hibernate/annotations/NaturalId.java b/hibernate-core/src/main/java/org/hibernate/annotations/NaturalId.java index d589fd2e47..1d30f5df7f 100644 --- a/hibernate-core/src/main/java/org/hibernate/annotations/NaturalId.java +++ b/hibernate-core/src/main/java/org/hibernate/annotations/NaturalId.java @@ -23,17 +23,18 @@ */ package org.hibernate.annotations; -import java.lang.annotation.Retention; -import java.lang.annotation.Target; - import static java.lang.annotation.ElementType.FIELD; import static java.lang.annotation.ElementType.METHOD; import static java.lang.annotation.RetentionPolicy.RUNTIME; +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + /** * This specifies that a property is part of the natural id of the entity. * * @author Nicol�s Lichtmaier + * @see NaturalIdCache */ @Target( { METHOD, FIELD } ) @Retention( RUNTIME ) @@ -44,11 +45,4 @@ public @interface NaturalId { * @return {@code true} indicates the natural id is mutable; {@code false} (the default) that it is immutable. */ boolean mutable() default false; - - /** - * Should the mapping of this natural id to the primary id be cached - * - * @return {@code true} (the default) indicates the natural id mapping should be cached; {@code false} that the mapping should not be cached. - */ - boolean cache() default true; } diff --git a/hibernate-core/src/main/java/org/hibernate/annotations/NaturalIdCache.java b/hibernate-core/src/main/java/org/hibernate/annotations/NaturalIdCache.java new file mode 100644 index 0000000000..97e62d8966 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/annotations/NaturalIdCache.java @@ -0,0 +1,44 @@ +/* + * 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.annotations; +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +import static java.lang.annotation.ElementType.FIELD; +import static java.lang.annotation.ElementType.METHOD; +import static java.lang.annotation.ElementType.TYPE; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +/** + * Add caching strategy for the NaturalId to Id of a root entity that has a natural id + * + * @author Eric Dalquist + * @see NaturalId + */ +@Target({TYPE, METHOD, FIELD}) +@Retention(RUNTIME) +public @interface NaturalIdCache { + /** cache region name, defaults to full.entity.Name##NaturalId */ + String region() default ""; +} diff --git a/hibernate-core/src/main/java/org/hibernate/cache/spi/NaturalIdRegion.java b/hibernate-core/src/main/java/org/hibernate/cache/spi/NaturalIdRegion.java new file mode 100644 index 0000000000..de7c8d8c48 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/cache/spi/NaturalIdRegion.java @@ -0,0 +1,47 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2008-2011, 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.spi; + +import org.hibernate.cache.CacheException; +import org.hibernate.cache.spi.access.AccessType; +import org.hibernate.cache.spi.access.NaturalIdRegionAccessStrategy; + +/** + * Defines the contract for a cache region which will specifically be used to + * store naturalId data. + * + * @author Eric Dalquist + */ +public interface NaturalIdRegion extends TransactionalDataRegion { + + /** + * Build an access strategy for the requested access type. + * + * @param accessType The type of access strategy to build; never null. + * @return The appropriate strategy contract for accessing this region + * for the requested type of access. + * @throws org.hibernate.cache.CacheException Usually indicates mis-configuration. + */ + public NaturalIdRegionAccessStrategy buildAccessStrategy(AccessType accessType) throws CacheException; +} diff --git a/hibernate-core/src/main/java/org/hibernate/cache/spi/access/NaturalIdRegionAccessStrategy.java b/hibernate-core/src/main/java/org/hibernate/cache/spi/access/NaturalIdRegionAccessStrategy.java new file mode 100644 index 0000000000..be0b414224 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/cache/spi/access/NaturalIdRegionAccessStrategy.java @@ -0,0 +1,50 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2008-2011, 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.spi.access; + +import org.hibernate.cache.spi.NaturalIdRegion; + +/** + * Contract for managing transactional and concurrent access to cached naturalId + * data. For cached naturalId data, all modification actions actually just + * invalidate the entry(s). The call sequence here is: + * {@link #lockItem} -> {@link #remove} -> {@link #unlockItem} + *

+ * There is another usage pattern that is used to invalidate entries + * after performing "bulk" HQL/SQL operations: + * {@link #lockRegion} -> {@link #removeAll} -> {@link #unlockRegion} + * + * @author Gavin King + * @author Steve Ebersole + * @author Eric Dalquist + */ +public interface NaturalIdRegionAccessStrategy extends RegionAccessStrategy{ + + /** + * Get the wrapped naturalId cache region + * + * @return The underlying region + */ + public NaturalIdRegion getRegion(); +} diff --git a/hibernate-core/src/main/java/org/hibernate/cfg/AnnotationBinder.java b/hibernate-core/src/main/java/org/hibernate/cfg/AnnotationBinder.java index e4dc5098c0..6785739002 100644 --- a/hibernate-core/src/main/java/org/hibernate/cfg/AnnotationBinder.java +++ b/hibernate-core/src/main/java/org/hibernate/cfg/AnnotationBinder.java @@ -34,6 +34,7 @@ import java.util.List; import java.util.Map; import java.util.Properties; import java.util.Set; + import javax.persistence.Basic; import javax.persistence.Cacheable; import javax.persistence.CollectionTable; @@ -79,8 +80,6 @@ import javax.persistence.TableGenerator; import javax.persistence.UniqueConstraint; import javax.persistence.Version; -import org.jboss.logging.Logger; - import org.hibernate.AnnotationException; import org.hibernate.AssertionFailure; import org.hibernate.EntityMode; @@ -112,6 +111,7 @@ import org.hibernate.annotations.LazyToOneOption; import org.hibernate.annotations.ManyToAny; import org.hibernate.annotations.MapKeyType; import org.hibernate.annotations.NaturalId; +import org.hibernate.annotations.NaturalIdCache; import org.hibernate.annotations.NotFound; import org.hibernate.annotations.NotFoundAction; import org.hibernate.annotations.OnDelete; @@ -167,6 +167,7 @@ import org.hibernate.mapping.SingleTableSubclass; import org.hibernate.mapping.Subclass; import org.hibernate.mapping.ToOne; import org.hibernate.mapping.UnionSubclass; +import org.jboss.logging.Logger; /** * JSR 175 annotation binder which reads the annotations from classes, applies the @@ -574,6 +575,7 @@ public final class AnnotationBinder { entityBinder.setBatchSize( clazzToProcess.getAnnotation( BatchSize.class ) ); entityBinder.setWhere( clazzToProcess.getAnnotation( Where.class ) ); entityBinder.setCache( determineCacheSettings( clazzToProcess, mappings ) ); + entityBinder.setNaturalIdCache( clazzToProcess.getAnnotation( NaturalIdCache.class ) ); //Filters are not allowed on subclasses if ( !inheritanceState.hasParents() ) { diff --git a/hibernate-core/src/main/java/org/hibernate/cfg/annotations/EntityBinder.java b/hibernate-core/src/main/java/org/hibernate/cfg/annotations/EntityBinder.java index 8645e3d9ac..ae7d076356 100644 --- a/hibernate-core/src/main/java/org/hibernate/cfg/annotations/EntityBinder.java +++ b/hibernate-core/src/main/java/org/hibernate/cfg/annotations/EntityBinder.java @@ -27,6 +27,7 @@ import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; + import javax.persistence.Access; import javax.persistence.Entity; import javax.persistence.JoinColumn; @@ -35,8 +36,6 @@ import javax.persistence.PrimaryKeyJoinColumn; import javax.persistence.SecondaryTable; import javax.persistence.SecondaryTables; -import org.jboss.logging.Logger; - import org.hibernate.AnnotationException; import org.hibernate.AssertionFailure; import org.hibernate.EntityMode; @@ -47,6 +46,7 @@ import org.hibernate.annotations.CacheConcurrencyStrategy; import org.hibernate.annotations.FetchMode; import org.hibernate.annotations.Immutable; import org.hibernate.annotations.Loader; +import org.hibernate.annotations.NaturalIdCache; import org.hibernate.annotations.OptimisticLockType; import org.hibernate.annotations.Persister; import org.hibernate.annotations.PolymorphismType; @@ -89,6 +89,7 @@ import org.hibernate.mapping.SimpleValue; import org.hibernate.mapping.Table; import org.hibernate.mapping.TableOwner; import org.hibernate.mapping.Value; +import org.jboss.logging.Logger; /** * Stateful holder and processor for binding Entity information @@ -97,7 +98,8 @@ import org.hibernate.mapping.Value; */ public class EntityBinder { private static final CoreMessageLogger LOG = Logger.getMessageLogger(CoreMessageLogger.class, EntityBinder.class.getName()); - + private static final String NATURAL_ID_CACHE_SUFFIX = "##NaturalId"; + private String name; private XClass annotatedClass; private PersistentClass persistentClass; @@ -119,6 +121,7 @@ public class EntityBinder { private java.util.Map secondaryTableJoins = new HashMap(); private String cacheConcurrentStrategy; private String cacheRegion; + private String naturalIdCacheRegion; private java.util.Map filters = new HashMap(); private InheritanceState inheritanceState; private boolean ignoreIdAnnotations; @@ -230,6 +233,7 @@ public class EntityBinder { rootClass.setCacheRegionName( cacheRegion ); rootClass.setLazyPropertiesCacheable( cacheLazyProperty ); } + rootClass.setNaturalIdCacheRegionName( naturalIdCacheRegion ); boolean forceDiscriminatorInSelects = forceDiscriminator == null ? mappings.forceDiscriminatorInSelectsByDefault() : forceDiscriminator; @@ -826,6 +830,25 @@ public class EntityBinder { cacheLazyProperty = true; } } + + public void setNaturalIdCache(NaturalIdCache naturalIdCacheAnn) { + if ( naturalIdCacheAnn != null ) { + if ( BinderHelper.isEmptyAnnotationValue( naturalIdCacheAnn.region() ) ) { + if (cacheRegion != null) { + naturalIdCacheRegion = cacheRegion + NATURAL_ID_CACHE_SUFFIX; + } + else { + naturalIdCacheRegion = persistentClass.getEntityName() + NATURAL_ID_CACHE_SUFFIX; + } + } + else { + naturalIdCacheRegion = naturalIdCacheAnn.region(); + } + } + else { + naturalIdCacheRegion = null; + } + } public static String getCacheConcurrencyStrategy(CacheConcurrencyStrategy strategy) { org.hibernate.cache.spi.access.AccessType accessType = strategy.toAccessType(); diff --git a/hibernate-core/src/main/java/org/hibernate/engine/spi/SessionFactoryImplementor.java b/hibernate-core/src/main/java/org/hibernate/engine/spi/SessionFactoryImplementor.java index 2962a26448..cb912c23c4 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/spi/SessionFactoryImplementor.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/spi/SessionFactoryImplementor.java @@ -182,6 +182,14 @@ public interface SessionFactoryImplementor extends Mapping, SessionFactory { * @return The region */ public Region getSecondLevelCacheRegion(String regionName); + + /** + * Get a named naturalId cache region + * + * @param regionName The name of the region to retrieve. + * @return The region + */ + public Region getNaturalIdCacheRegion(String regionName); /** * Get a map of all the second level cache regions currently maintained in diff --git a/hibernate-core/src/main/java/org/hibernate/internal/SessionFactoryImpl.java b/hibernate-core/src/main/java/org/hibernate/internal/SessionFactoryImpl.java index fec89f611f..83ee962e3d 100644 --- a/hibernate-core/src/main/java/org/hibernate/internal/SessionFactoryImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/internal/SessionFactoryImpl.java @@ -39,11 +39,10 @@ import java.util.Properties; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; + import javax.naming.Reference; import javax.naming.StringRefAddr; -import org.jboss.logging.Logger; - import org.hibernate.AssertionFailure; import org.hibernate.Cache; import org.hibernate.ConnectionReleaseMode; @@ -145,6 +144,7 @@ import org.hibernate.tuple.entity.EntityTuplizer; import org.hibernate.type.AssociationType; import org.hibernate.type.Type; import org.hibernate.type.TypeResolver; +import org.jboss.logging.Logger; /** @@ -173,7 +173,6 @@ import org.hibernate.type.TypeResolver; public final class SessionFactoryImpl implements SessionFactoryImplementor { - private static final String NATURAL_ID_CACHE_SUFFIX = "##NaturalId"; private static final CoreMessageLogger LOG = Logger.getMessageLogger(CoreMessageLogger.class, SessionFactoryImpl.class.getName()); private static final IdentifierGenerator UUID_GENERATOR = UUIDGenerator.buildSessionFactoryUniqueIdentifierGenerator(); @@ -360,8 +359,8 @@ public final class SessionFactoryImpl entityPersisters.put( model.getEntityName(), cp ); classMeta.put( model.getEntityName(), cp.getClassMetadata() ); - if ( cp.hasNaturalIdentifier() && cp.isNatrualIdentifierCached() ) { - final String naturalIdCacheRegionName = cacheRegionPrefix + model.getRootClass().getCacheRegionName() + NATURAL_ID_CACHE_SUFFIX; + if ( cp.hasNaturalIdentifier() && model.getNaturalIdCacheRegionName() != null ) { + final String naturalIdCacheRegionName = cacheRegionPrefix + model.getNaturalIdCacheRegionName(); NaturalIdRegionAccessStrategy naturalIdAccessStrategy = ( NaturalIdRegionAccessStrategy ) entityAccessStrategies.get( naturalIdCacheRegionName ); if ( naturalIdAccessStrategy == null && settings.isSecondLevelCacheEnabled() ) { @@ -805,14 +804,6 @@ public final class SessionFactoryImpl ); entityPersisters.put( model.getEntity().getName(), cp ); classMeta.put( model.getEntity().getName(), cp.getClassMetadata() ); - - if ( settings.isSecondLevelCacheEnabled() && cp.hasNaturalIdentifier() && cp.isNatrualIdentifierCached() ) { - final String naturalIdCacheRegionName = cacheRegionPrefix + rootEntityBinding.getHierarchyDetails().getCaching().getRegion() + NATURAL_ID_CACHE_SUFFIX; - final NaturalIdRegion naturalIdRegion = settings.getRegionFactory().buildNaturalIdRegion( naturalIdCacheRegionName, properties, CacheDataDescriptionImpl.decode( cp ) ); - final NaturalIdRegionAccessStrategy naturalIdAccessStrategy = naturalIdRegion.buildAccessStrategy( settings.getRegionFactory().getDefaultAccessType() ); - entityAccessStrategies.put( naturalIdCacheRegionName, naturalIdAccessStrategy ); - allCacheRegions.put( naturalIdCacheRegionName, naturalIdRegion ); - } } this.classMetadata = Collections.unmodifiableMap(classMeta); @@ -1643,6 +1634,10 @@ public final class SessionFactoryImpl return allCacheRegions.get( regionName ); } + public Region getNaturalIdCacheRegion(String regionName) { + return allCacheRegions.get( regionName ); + } + @SuppressWarnings( {"unchecked"}) public Map getAllSecondLevelCacheRegions() { return new HashMap( allCacheRegions ); diff --git a/hibernate-core/src/main/java/org/hibernate/jmx/StatisticsService.java b/hibernate-core/src/main/java/org/hibernate/jmx/StatisticsService.java index 54f75b5069..cba1ef5466 100644 --- a/hibernate-core/src/main/java/org/hibernate/jmx/StatisticsService.java +++ b/hibernate-core/src/main/java/org/hibernate/jmx/StatisticsService.java @@ -12,6 +12,7 @@ import org.hibernate.internal.CoreMessageLogger; import org.hibernate.internal.SessionFactoryRegistry; import org.hibernate.stat.CollectionStatistics; import org.hibernate.stat.EntityStatistics; +import org.hibernate.stat.NaturalIdCacheStatistics; import org.hibernate.stat.QueryStatistics; import org.hibernate.stat.SecondLevelCacheStatistics; import org.hibernate.stat.Statistics; @@ -227,6 +228,23 @@ public class StatisticsService implements StatisticsServiceMBean { public long getSecondLevelCachePutCount() { return stats.getSecondLevelCachePutCount(); } + + public NaturalIdCacheStatistics getNaturalIdCacheStatistics(String regionName) { + return stats.getNaturalIdCacheStatistics( regionName ); + } + + public long getNaturalIdCacheHitCount() { + return stats.getNaturalIdCacheHitCount(); + } + + public long getNaturalIdCacheMissCount() { + return stats.getNaturalIdCacheMissCount(); + } + + public long getNaturalIdCachePutCount() { + return stats.getNaturalIdCachePutCount(); + } + /** * @see StatisticsServiceMBean#getSessionCloseCount() */ diff --git a/hibernate-core/src/main/java/org/hibernate/mapping/PersistentClass.java b/hibernate-core/src/main/java/org/hibernate/mapping/PersistentClass.java index b8caca7d44..836fe837de 100644 --- a/hibernate-core/src/main/java/org/hibernate/mapping/PersistentClass.java +++ b/hibernate-core/src/main/java/org/hibernate/mapping/PersistentClass.java @@ -248,6 +248,7 @@ public abstract class PersistentClass implements Serializable, Filterable, MetaA public abstract boolean isInherited(); public abstract boolean isPolymorphic(); public abstract boolean isVersioned(); + public abstract String getNaturalIdCacheRegionName(); public abstract String getCacheConcurrencyStrategy(); public abstract PersistentClass getSuperclass(); public abstract boolean isExplicitPolymorphism(); diff --git a/hibernate-core/src/main/java/org/hibernate/mapping/RootClass.java b/hibernate-core/src/main/java/org/hibernate/mapping/RootClass.java index 46f2cc4537..e5ebf617ef 100644 --- a/hibernate-core/src/main/java/org/hibernate/mapping/RootClass.java +++ b/hibernate-core/src/main/java/org/hibernate/mapping/RootClass.java @@ -32,6 +32,7 @@ import org.jboss.logging.Logger; import org.hibernate.MappingException; import org.hibernate.engine.spi.Mapping; import org.hibernate.internal.CoreMessageLogger; +import org.hibernate.internal.SessionFactoryImpl; import org.hibernate.internal.util.ReflectHelper; import org.hibernate.internal.util.collections.SingletonIterator; @@ -52,6 +53,7 @@ public class RootClass extends PersistentClass implements TableOwner { private boolean polymorphic; private String cacheConcurrencyStrategy; private String cacheRegionName; + private String naturalIdCacheRegionName; private boolean lazyPropertiesCacheable = true; private Value discriminator; //may be final private boolean mutable = true; @@ -307,7 +309,15 @@ public class RootClass extends PersistentClass implements TableOwner { public void setCacheRegionName(String cacheRegionName) { this.cacheRegionName = cacheRegionName; } - + + @Override + public String getNaturalIdCacheRegionName() { + return naturalIdCacheRegionName; + } + public void setNaturalIdCacheRegionName(String naturalIdCacheRegionName) { + this.naturalIdCacheRegionName = naturalIdCacheRegionName; + } + @Override public boolean isLazyPropertiesCacheable() { return lazyPropertiesCacheable; diff --git a/hibernate-core/src/main/java/org/hibernate/mapping/Subclass.java b/hibernate-core/src/main/java/org/hibernate/mapping/Subclass.java index aacd1e9fab..2536fcd639 100644 --- a/hibernate-core/src/main/java/org/hibernate/mapping/Subclass.java +++ b/hibernate-core/src/main/java/org/hibernate/mapping/Subclass.java @@ -55,6 +55,11 @@ public class Subclass extends PersistentClass { return subclassId; } + @Override + public String getNaturalIdCacheRegionName() { + return getSuperclass().getNaturalIdCacheRegionName(); + } + public String getCacheConcurrencyStrategy() { return getSuperclass().getCacheConcurrencyStrategy(); } diff --git a/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java b/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java index f4bf6d7bd5..f5365248a7 100644 --- a/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java +++ b/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java @@ -37,8 +37,6 @@ import java.util.List; import java.util.Map; import java.util.Set; -import org.jboss.logging.Logger; - import org.hibernate.AssertionFailure; import org.hibernate.EntityMode; import org.hibernate.FetchMode; @@ -122,6 +120,7 @@ import org.hibernate.type.EntityType; import org.hibernate.type.Type; import org.hibernate.type.TypeHelper; import org.hibernate.type.VersionType; +import org.jboss.logging.Logger; /** * Basic functionality for persisting an entity via JDBC @@ -4601,11 +4600,6 @@ public abstract class AbstractEntityPersister public boolean hasNaturalIdentifier() { return entityMetamodel.hasNaturalIdentifier(); } - - @Override - public boolean isNatrualIdentifierCached() { - return entityMetamodel.isNatrualIdentifierCached(); - } public void setPropertyValue(Object object, String propertyName, Object value) { getEntityTuplizer().setPropertyValue( object, propertyName, value ); diff --git a/hibernate-core/src/main/java/org/hibernate/persister/entity/EntityPersister.java b/hibernate-core/src/main/java/org/hibernate/persister/entity/EntityPersister.java index b2e1ce1234..afa8b592aa 100644 --- a/hibernate-core/src/main/java/org/hibernate/persister/entity/EntityPersister.java +++ b/hibernate-core/src/main/java/org/hibernate/persister/entity/EntityPersister.java @@ -289,13 +289,6 @@ public interface EntityPersister extends OptimisticCacheSource { * @return True if the entity defines a natural id; false otherwise. */ public boolean hasNaturalIdentifier(); - - /** - * Determine whether this entity's natural identifier is cacheable. {@link NaturalId#cache()} - * - * @return True if the natural id is cacheable, false if it is not cacheable or no natural id is defined - */ - public boolean isNatrualIdentifierCached(); /** * If the entity defines a natural id ({@link #hasNaturalIdentifier()}), which diff --git a/hibernate-core/src/main/java/org/hibernate/stat/NaturalIdCacheStatistics.java b/hibernate-core/src/main/java/org/hibernate/stat/NaturalIdCacheStatistics.java new file mode 100644 index 0000000000..f0eb35dbc9 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/stat/NaturalIdCacheStatistics.java @@ -0,0 +1,50 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2008-2011, 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.stat; + +import java.io.Serializable; +import java.util.Map; + +/** + * NaturalId query statistics + *

+ * Note that for a cached natural id, the cache miss is equals to the db count + * + * @author Eric Dalquist + */ +public interface NaturalIdCacheStatistics extends Serializable { + long getHitCount(); + + long getMissCount(); + + long getPutCount(); + + long getElementCountInMemory(); + + long getElementCountOnDisk(); + + long getSizeInMemory(); + + Map getEntries(); +} diff --git a/hibernate-core/src/main/java/org/hibernate/stat/Statistics.java b/hibernate-core/src/main/java/org/hibernate/stat/Statistics.java index e8b935b0a9..33cd475080 100755 --- a/hibernate-core/src/main/java/org/hibernate/stat/Statistics.java +++ b/hibernate-core/src/main/java/org/hibernate/stat/Statistics.java @@ -59,6 +59,14 @@ public interface Statistics { */ public SecondLevelCacheStatistics getSecondLevelCacheStatistics(String regionName); + /** + * Natural id cache statistics per region + * + * @param regionName region name + * @return NaturalIdCacheStatistics + */ + public NaturalIdCacheStatistics getNaturalIdCacheStatistics(String regionName); + /** * Query statistics from query string (HQL or SQL) * @@ -123,6 +131,18 @@ public interface Statistics { * Get the global number of cacheable queries put in cache */ public long getQueryCachePutCount(); + /** + * Get the global number of cached naturalId lookups successfully retrieved from cache + */ + public long getNaturalIdCacheHitCount(); + /** + * Get the global number of cached naturalId lookups *not* found in cache + */ + public long getNaturalIdCacheMissCount(); + /** + * Get the global number of cacheable naturalId lookups put in cache + */ + public long getNaturalIdCachePutCount(); /** * Get the global number of timestamps successfully retrieved from cache */ diff --git a/hibernate-core/src/main/java/org/hibernate/stat/internal/ConcurrentNaturalIdCacheStatisticsImpl.java b/hibernate-core/src/main/java/org/hibernate/stat/internal/ConcurrentNaturalIdCacheStatisticsImpl.java new file mode 100644 index 0000000000..e60d456bb0 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/stat/internal/ConcurrentNaturalIdCacheStatisticsImpl.java @@ -0,0 +1,112 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2011, 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.stat.internal; + +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import java.util.concurrent.atomic.AtomicLong; + +import org.hibernate.cache.spi.CacheKey; +import org.hibernate.cache.spi.Region; +import org.hibernate.stat.NaturalIdCacheStatistics; + +/** + * Second level cache statistics of a specific region + * + * @author Alex Snaps + */ +public class ConcurrentNaturalIdCacheStatisticsImpl extends CategorizedStatistics implements NaturalIdCacheStatistics { + private final transient Region region; + private AtomicLong hitCount = new AtomicLong(); + private AtomicLong missCount = new AtomicLong(); + private AtomicLong putCount = new AtomicLong(); + + ConcurrentNaturalIdCacheStatisticsImpl(Region region) { + super( region.getName() ); + this.region = region; + } + + public long getHitCount() { + return hitCount.get(); + } + + public long getMissCount() { + return missCount.get(); + } + + public long getPutCount() { + return putCount.get(); + } + + public long getElementCountInMemory() { + return region.getElementCountInMemory(); + } + + public long getElementCountOnDisk() { + return region.getElementCountOnDisk(); + } + + public long getSizeInMemory() { + return region.getSizeInMemory(); + } + + public Map getEntries() { + Map map = new HashMap(); + Iterator iter = region.toMap().entrySet().iterator(); + while (iter.hasNext()) { + Map.Entry me = (Map.Entry) iter.next(); + map.put(((CacheKey) me.getKey()).getKey(), me.getValue()); + } + return map; + } + + public String toString() { + StringBuilder buf = new StringBuilder() + .append("NaturalIdCacheStatistics") + .append("[hitCount=").append(this.hitCount) + .append(",missCount=").append(this.missCount) + .append(",putCount=").append(this.putCount); + //not sure if this would ever be null but wanted to be careful + if (region != null) { + buf.append(",elementCountInMemory=").append(this.getElementCountInMemory()) + .append(",elementCountOnDisk=").append(this.getElementCountOnDisk()) + .append(",sizeInMemory=").append(this.getSizeInMemory()); + } + buf.append(']'); + return buf.toString(); + } + + void incrementHitCount() { + hitCount.getAndIncrement(); + } + + void incrementMissCount() { + missCount.getAndIncrement(); + } + + void incrementPutCount() { + putCount.getAndIncrement(); + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/stat/internal/ConcurrentStatisticsImpl.java b/hibernate-core/src/main/java/org/hibernate/stat/internal/ConcurrentStatisticsImpl.java index 4871a7608c..acf6a9377b 100644 --- a/hibernate-core/src/main/java/org/hibernate/stat/internal/ConcurrentStatisticsImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/stat/internal/ConcurrentStatisticsImpl.java @@ -27,8 +27,6 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.atomic.AtomicLong; -import org.jboss.logging.Logger; - import org.hibernate.cache.spi.Region; import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.internal.CoreMessageLogger; @@ -36,9 +34,11 @@ import org.hibernate.internal.util.collections.ArrayHelper; import org.hibernate.service.Service; import org.hibernate.stat.CollectionStatistics; import org.hibernate.stat.EntityStatistics; +import org.hibernate.stat.NaturalIdCacheStatistics; import org.hibernate.stat.QueryStatistics; import org.hibernate.stat.SecondLevelCacheStatistics; import org.hibernate.stat.spi.StatisticsImplementor; +import org.jboss.logging.Logger; /** * Implementation of {@link org.hibernate.stat.Statistics} based on the {@link java.util.concurrent} package. @@ -76,6 +76,10 @@ public class ConcurrentStatisticsImpl implements StatisticsImplementor, Service private AtomicLong secondLevelCacheHitCount = new AtomicLong(); private AtomicLong secondLevelCacheMissCount = new AtomicLong(); private AtomicLong secondLevelCachePutCount = new AtomicLong(); + + private AtomicLong naturalIdCacheHitCount = new AtomicLong(); + private AtomicLong naturalIdCacheMissCount = new AtomicLong(); + private AtomicLong naturalIdCachePutCount = new AtomicLong(); private AtomicLong queryExecutionCount = new AtomicLong(); private AtomicLong queryExecutionMaxTime = new AtomicLong(); @@ -93,6 +97,10 @@ public class ConcurrentStatisticsImpl implements StatisticsImplementor, Service private AtomicLong optimisticFailureCount = new AtomicLong(); + /** + * natural id cache statistics per region + */ + private final ConcurrentMap naturalIdCacheStatistics = new ConcurrentHashMap(); /** * second level cache statistics per region */ @@ -127,6 +135,10 @@ public class ConcurrentStatisticsImpl implements StatisticsImplementor, Service secondLevelCacheHitCount.set( 0 ); secondLevelCacheMissCount.set( 0 ); secondLevelCachePutCount.set( 0 ); + + naturalIdCacheHitCount.set( 0 ); + naturalIdCacheMissCount.set( 0 ); + naturalIdCachePutCount.set( 0 ); sessionCloseCount.set( 0 ); sessionOpenCount.set( 0 ); @@ -282,6 +294,31 @@ public class ConcurrentStatisticsImpl implements StatisticsImplementor, Service collectionRemoveCount.getAndIncrement(); ( (ConcurrentCollectionStatisticsImpl) getCollectionStatistics( role ) ).incrementRemoveCount(); } + + + @Override + public NaturalIdCacheStatistics getNaturalIdCacheStatistics(String regionName) { + ConcurrentNaturalIdCacheStatisticsImpl nics = + (ConcurrentNaturalIdCacheStatisticsImpl) naturalIdCacheStatistics.get( regionName ); + + if ( nics == null ) { + if ( sessionFactory == null ) { + return null; + } + Region region = sessionFactory.getNaturalIdCacheRegion( regionName ); + if ( region == null ) { + return null; + } + nics = new ConcurrentNaturalIdCacheStatisticsImpl( region ); + ConcurrentNaturalIdCacheStatisticsImpl previous; + if ( ( previous = (ConcurrentNaturalIdCacheStatisticsImpl) naturalIdCacheStatistics.putIfAbsent( + regionName, nics + ) ) != null ) { + nics = previous; + } + } + return nics; + } /** * Second level cache statistics per region @@ -326,6 +363,24 @@ public class ConcurrentStatisticsImpl implements StatisticsImplementor, Service secondLevelCacheMissCount.getAndIncrement(); ( (ConcurrentSecondLevelCacheStatisticsImpl) getSecondLevelCacheStatistics( regionName ) ).incrementMissCount(); } + + @Override + public void naturalIdCachePut(String regionName) { + naturalIdCachePutCount.getAndIncrement(); + ( (ConcurrentNaturalIdCacheStatisticsImpl) getNaturalIdCacheStatistics( regionName ) ).incrementPutCount(); + } + + @Override + public void naturalIdCacheHit(String regionName) { + naturalIdCacheHitCount.getAndIncrement(); + ( (ConcurrentNaturalIdCacheStatisticsImpl) getNaturalIdCacheStatistics( regionName ) ).incrementHitCount(); + } + + @Override + public void naturalIdCacheMiss(String regionName) { + naturalIdCacheMissCount.getAndIncrement(); + ( (ConcurrentNaturalIdCacheStatisticsImpl) getNaturalIdCacheStatistics( regionName ) ).incrementMissCount(); + } @SuppressWarnings({ "UnnecessaryBoxing" }) public void queryExecuted(String hql, int rows, long time) { @@ -515,6 +570,21 @@ public class ConcurrentStatisticsImpl implements StatisticsImplementor, Service public long getSecondLevelCachePutCount() { return secondLevelCachePutCount.get(); } + + @Override + public long getNaturalIdCacheHitCount() { + return naturalIdCacheHitCount.get(); + } + + @Override + public long getNaturalIdCacheMissCount() { + return naturalIdCacheMissCount.get(); + } + + @Override + public long getNaturalIdCachePutCount() { + return naturalIdCachePutCount.get(); + } /** * @return session closing diff --git a/hibernate-core/src/main/java/org/hibernate/stat/spi/StatisticsImplementor.java b/hibernate-core/src/main/java/org/hibernate/stat/spi/StatisticsImplementor.java index a9c1c6cb07..cff7ad444e 100644 --- a/hibernate-core/src/main/java/org/hibernate/stat/spi/StatisticsImplementor.java +++ b/hibernate-core/src/main/java/org/hibernate/stat/spi/StatisticsImplementor.java @@ -25,6 +25,7 @@ package org.hibernate.stat.spi; import org.hibernate.service.Service; import org.hibernate.stat.Statistics; +import org.hibernate.stat.internal.ConcurrentSecondLevelCacheStatisticsImpl; /** * Statistics SPI for the Hibernate core. This is essentially the "statistic collector" API, its the contract @@ -171,6 +172,27 @@ public interface StatisticsImplementor extends Statistics, Service { * @param regionName The name of the cache region */ public void secondLevelCacheMiss(String regionName); + + /** + * Callback indicating a put into natural id cache. + * + * @param regionName The name of the cache region + */ + public void naturalIdCachePut(String regionName); + + /** + * Callback indicating a get from natural id cache resulted in a hit. + * + * @param regionName The name of the cache region + */ + public void naturalIdCacheHit(String regionName); + + /** + * Callback indicating a get from natural id cache resulted in a miss. + * + * @param regionName The name of the cache region + */ + public void naturalIdCacheMiss(String regionName); /** * Callback indicating a put into the query cache. diff --git a/hibernate-core/src/main/java/org/hibernate/tuple/entity/EntityMetamodel.java b/hibernate-core/src/main/java/org/hibernate/tuple/entity/EntityMetamodel.java index 55c7d4d78b..d8a4d3f77b 100644 --- a/hibernate-core/src/main/java/org/hibernate/tuple/entity/EntityMetamodel.java +++ b/hibernate-core/src/main/java/org/hibernate/tuple/entity/EntityMetamodel.java @@ -263,7 +263,7 @@ public class EntityMetamodel implements Serializable { else { naturalIdPropertyNumbers = ArrayHelper.toIntArray(naturalIdNumbers); hasImmutableNaturalId = !foundUpdateableNaturalIdProperty; - hasCacheableNaturalId = true; //TODO how to read the annotation here? + hasCacheableNaturalId = persistentClass.getNaturalIdCacheRegionName() != null; } hasInsertGeneratedValues = foundInsertGeneratedValue; @@ -510,7 +510,7 @@ public class EntityMetamodel implements Serializable { else { naturalIdPropertyNumbers = ArrayHelper.toIntArray(naturalIdNumbers); hasImmutableNaturalId = !foundUpdateableNaturalIdProperty; - hasCacheableNaturalId = true; //TODO how to read the annotation here? + hasCacheableNaturalId = false; //See previous TODO and HHH-6354 } hasInsertGeneratedValues = foundInsertGeneratedValue; diff --git a/hibernate-core/src/matrix/java/org/hibernate/test/annotations/naturalid/NaturalIdTest.java b/hibernate-core/src/matrix/java/org/hibernate/test/annotations/naturalid/NaturalIdTest.java index bfcf3d20da..49f6e0a417 100644 --- a/hibernate-core/src/matrix/java/org/hibernate/test/annotations/naturalid/NaturalIdTest.java +++ b/hibernate-core/src/matrix/java/org/hibernate/test/annotations/naturalid/NaturalIdTest.java @@ -23,11 +23,14 @@ */ package org.hibernate.test.annotations.naturalid; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + import java.util.List; -import org.junit.Test; - import org.hibernate.Criteria; +import org.hibernate.NaturalIdLoadAccess; import org.hibernate.Session; import org.hibernate.Transaction; import org.hibernate.cfg.Configuration; @@ -35,9 +38,7 @@ import org.hibernate.criterion.Restrictions; import org.hibernate.metadata.ClassMetadata; import org.hibernate.stat.Statistics; import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; +import org.junit.Test; /** * Test case for NaturalId annotation @@ -112,6 +113,53 @@ public class NaturalIdTest extends BaseCoreFunctionalTestCase { s.close(); } + @Test + public void testNaturalIdLoaderCached() { + saveSomeCitizens(); + + Session s = openSession(); + Transaction tx = s.beginTransaction(); + State france = ( State ) s.load( State.class, 2 ); + final NaturalIdLoadAccess naturalIdLoader = s.byNaturalId( Citizen.class ); + naturalIdLoader.using( "ssn", "1234" ).using( "state", france ); + + Statistics stats = sessionFactory().getStatistics(); + stats.setStatisticsEnabled( true ); + stats.clear(); + assertEquals( + "Cache hits should be empty", 0, stats + .getQueryCacheHitCount() + ); + + // first query + Citizen citizen = (Citizen)naturalIdLoader.load(); + assertNotNull( citizen ); + assertEquals( + "Cache hits should be empty", 0, stats + .getNaturalIdCacheHitCount() + ); + assertEquals( + "First load should be a miss", 1, stats + .getNaturalIdCacheMissCount() + ); + assertEquals( + "Query result should be added to cache", 1, stats + .getNaturalIdCachePutCount() + ); + + // query a second time - result should be cached + citizen = (Citizen)naturalIdLoader.load(); + assertNotNull( citizen ); + assertEquals( + "Cache hits should be empty", 1, stats + .getNaturalIdCacheHitCount() + ); + + // cleanup + tx.rollback(); + s.close(); + } + @Test public void testNaturalIdUncached() { saveSomeCitizens(); diff --git a/hibernate-core/src/test/java/org/hibernate/test/cfg/persister/GoofyPersisterClassProvider.java b/hibernate-core/src/test/java/org/hibernate/test/cfg/persister/GoofyPersisterClassProvider.java index 52c6113b24..4623291e7e 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/cfg/persister/GoofyPersisterClassProvider.java +++ b/hibernate-core/src/test/java/org/hibernate/test/cfg/persister/GoofyPersisterClassProvider.java @@ -235,11 +235,6 @@ public class GoofyPersisterClassProvider implements PersisterClassResolver { public boolean hasNaturalIdentifier() { return false; } - - @Override - public boolean isNatrualIdentifierCached() { - return false; - } @Override public int[] getNaturalIdentifierProperties() { diff --git a/hibernate-core/src/test/java/org/hibernate/test/legacy/CustomPersister.java b/hibernate-core/src/test/java/org/hibernate/test/legacy/CustomPersister.java index 899884b061..9ea279f52f 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/legacy/CustomPersister.java +++ b/hibernate-core/src/test/java/org/hibernate/test/legacy/CustomPersister.java @@ -563,11 +563,6 @@ public class CustomPersister implements EntityPersister { public boolean hasNaturalIdentifier() { return false; } - - @Override - public boolean isNatrualIdentifierCached() { - return false; - } @Override public boolean hasMutableProperties() { diff --git a/hibernate-ehcache/src/main/java/org/hibernate/cache/ehcache/internal/nonstop/NonstopAwareNaturalIdRegionAccessStrategy.java b/hibernate-ehcache/src/main/java/org/hibernate/cache/ehcache/internal/nonstop/NonstopAwareNaturalIdRegionAccessStrategy.java new file mode 100644 index 0000000000..f1708801f1 --- /dev/null +++ b/hibernate-ehcache/src/main/java/org/hibernate/cache/ehcache/internal/nonstop/NonstopAwareNaturalIdRegionAccessStrategy.java @@ -0,0 +1,227 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2011, 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.internal.nonstop; + +import net.sf.ehcache.constructs.nonstop.NonStopCacheException; + +import org.hibernate.cache.CacheException; +import org.hibernate.cache.spi.NaturalIdRegion; +import org.hibernate.cache.spi.access.NaturalIdRegionAccessStrategy; +import org.hibernate.cache.spi.access.SoftLock; + +/** + * Implementation of {@link NaturalIdRegionAccessStrategy} that handles {@link NonStopCacheException} using + * {@link HibernateNonstopCacheExceptionHandler} + * + * @author Abhishek Sanoujam + * @author Alex Snaps + */ +public class NonstopAwareNaturalIdRegionAccessStrategy implements NaturalIdRegionAccessStrategy { + + private final NaturalIdRegionAccessStrategy actualStrategy; + private final HibernateNonstopCacheExceptionHandler hibernateNonstopExceptionHandler; + + /** + * Constructor accepting the actual {@link NaturalIdRegionAccessStrategy} and the {@link HibernateNonstopCacheExceptionHandler} + * + * @param actualStrategy + * @param hibernateNonstopExceptionHandler + */ + public NonstopAwareNaturalIdRegionAccessStrategy(NaturalIdRegionAccessStrategy actualStrategy, + HibernateNonstopCacheExceptionHandler hibernateNonstopExceptionHandler) { + this.actualStrategy = actualStrategy; + this.hibernateNonstopExceptionHandler = hibernateNonstopExceptionHandler; + } + + /** + * {@inheritDoc} + * + * @see org.hibernate.cache.spi.access.EntityRegionAccessStrategy#getRegion() + */ + public NaturalIdRegion getRegion() { + return actualStrategy.getRegion(); + } + + /** + * {@inheritDoc} + * + * @see org.hibernate.cache.spi.access.EntityRegionAccessStrategy#evict(java.lang.Object) + */ + public void evict(Object key) throws CacheException { + try { + actualStrategy.evict( key ); + } + catch ( NonStopCacheException nonStopCacheException ) { + hibernateNonstopExceptionHandler.handleNonstopCacheException( nonStopCacheException ); + } + } + + /** + * {@inheritDoc} + * + * @see org.hibernate.cache.spi.access.EntityRegionAccessStrategy#evictAll() + */ + public void evictAll() throws CacheException { + try { + actualStrategy.evictAll(); + } + catch ( NonStopCacheException nonStopCacheException ) { + hibernateNonstopExceptionHandler.handleNonstopCacheException( nonStopCacheException ); + } + } + + /** + * {@inheritDoc} + * + * @see org.hibernate.cache.spi.access.EntityRegionAccessStrategy#get(java.lang.Object, long) + */ + public Object get(Object key, long txTimestamp) throws CacheException { + try { + return actualStrategy.get( key, txTimestamp ); + } + catch ( NonStopCacheException nonStopCacheException ) { + hibernateNonstopExceptionHandler.handleNonstopCacheException( nonStopCacheException ); + return null; + } + } + + /** + * {@inheritDoc} + * + * @see org.hibernate.cache.spi.access.EntityRegionAccessStrategy#lockItem(java.lang.Object, java.lang.Object) + */ + public SoftLock lockItem(Object key, Object version) throws CacheException { + try { + return actualStrategy.lockItem( key, version ); + } + catch ( NonStopCacheException nonStopCacheException ) { + hibernateNonstopExceptionHandler.handleNonstopCacheException( nonStopCacheException ); + return null; + } + } + + /** + * {@inheritDoc} + * + * @see org.hibernate.cache.spi.access.EntityRegionAccessStrategy#lockRegion() + */ + public SoftLock lockRegion() throws CacheException { + try { + return actualStrategy.lockRegion(); + } + catch ( NonStopCacheException nonStopCacheException ) { + hibernateNonstopExceptionHandler.handleNonstopCacheException( nonStopCacheException ); + return null; + } + } + + /** + * {@inheritDoc} + * + * @see org.hibernate.cache.spi.access.EntityRegionAccessStrategy#putFromLoad(java.lang.Object, java.lang.Object, long, java.lang.Object, + * boolean) + */ + public boolean putFromLoad(Object key, Object value, long txTimestamp, Object version, boolean minimalPutOverride) + throws CacheException { + try { + return actualStrategy.putFromLoad( key, value, txTimestamp, version, minimalPutOverride ); + } + catch ( NonStopCacheException nonStopCacheException ) { + hibernateNonstopExceptionHandler.handleNonstopCacheException( nonStopCacheException ); + return false; + } + } + + /** + * {@inheritDoc} + * + * @see org.hibernate.cache.spi.access.EntityRegionAccessStrategy#putFromLoad(java.lang.Object, java.lang.Object, long, java.lang.Object) + */ + public boolean putFromLoad(Object key, Object value, long txTimestamp, Object version) throws CacheException { + try { + return actualStrategy.putFromLoad( key, value, txTimestamp, version ); + } + catch ( NonStopCacheException nonStopCacheException ) { + hibernateNonstopExceptionHandler.handleNonstopCacheException( nonStopCacheException ); + return false; + } + } + + /** + * {@inheritDoc} + * + * @see org.hibernate.cache.spi.access.EntityRegionAccessStrategy#remove(java.lang.Object) + */ + public void remove(Object key) throws CacheException { + try { + actualStrategy.remove( key ); + } + catch ( NonStopCacheException nonStopCacheException ) { + hibernateNonstopExceptionHandler.handleNonstopCacheException( nonStopCacheException ); + } + } + + /** + * {@inheritDoc} + * + * @see org.hibernate.cache.spi.access.EntityRegionAccessStrategy#removeAll() + */ + public void removeAll() throws CacheException { + try { + actualStrategy.removeAll(); + } + catch ( NonStopCacheException nonStopCacheException ) { + hibernateNonstopExceptionHandler.handleNonstopCacheException( nonStopCacheException ); + } + } + + /** + * {@inheritDoc} + * + * @see org.hibernate.cache.spi.access.EntityRegionAccessStrategy#unlockItem(java.lang.Object, org.hibernate.cache.spi.access.SoftLock) + */ + public void unlockItem(Object key, SoftLock lock) throws CacheException { + try { + actualStrategy.unlockItem( key, lock ); + } + catch ( NonStopCacheException nonStopCacheException ) { + hibernateNonstopExceptionHandler.handleNonstopCacheException( nonStopCacheException ); + } + } + + /** + * {@inheritDoc} + * + * @see org.hibernate.cache.spi.access.EntityRegionAccessStrategy#unlockRegion(org.hibernate.cache.spi.access.SoftLock) + */ + public void unlockRegion(SoftLock lock) throws CacheException { + try { + actualStrategy.unlockRegion( lock ); + } + catch ( NonStopCacheException nonStopCacheException ) { + hibernateNonstopExceptionHandler.handleNonstopCacheException( nonStopCacheException ); + } + } + +} diff --git a/hibernate-ehcache/src/main/java/org/hibernate/cache/ehcache/internal/regions/EhcacheNaturalIdRegion.java b/hibernate-ehcache/src/main/java/org/hibernate/cache/ehcache/internal/regions/EhcacheNaturalIdRegion.java new file mode 100644 index 0000000000..92d7c9d227 --- /dev/null +++ b/hibernate-ehcache/src/main/java/org/hibernate/cache/ehcache/internal/regions/EhcacheNaturalIdRegion.java @@ -0,0 +1,66 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2011, 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.internal.regions; + +import java.util.Properties; + +import net.sf.ehcache.Ehcache; + +import org.hibernate.cache.CacheException; +import org.hibernate.cache.ehcache.internal.strategy.EhcacheAccessStrategyFactory; +import org.hibernate.cache.spi.CacheDataDescription; +import org.hibernate.cache.spi.NaturalIdRegion; +import org.hibernate.cache.spi.access.AccessType; +import org.hibernate.cache.spi.access.NaturalIdRegionAccessStrategy; +import org.hibernate.cfg.Settings; + +/** + * A collection region specific wrapper around an Ehcache instance. + *

+ * This implementation returns Ehcache specific access strategy instances for all the non-transactional access types. Transactional access + * is not supported. + * + * @author Chris Dennis + * @author Abhishek Sanoujam + * @author Alex Snaps + */ +public class EhcacheNaturalIdRegion extends EhcacheTransactionalDataRegion implements NaturalIdRegion { + + + /** + * Constructs an EhcacheNaturalIdRegion around the given underlying cache. + * + * @param accessStrategyFactory + */ + public EhcacheNaturalIdRegion(EhcacheAccessStrategyFactory accessStrategyFactory, Ehcache underlyingCache, Settings settings, + CacheDataDescription metadata, Properties properties) { + super( accessStrategyFactory, underlyingCache, settings, metadata, properties ); + } + + @Override + public NaturalIdRegionAccessStrategy buildAccessStrategy(AccessType accessType) throws CacheException { + return accessStrategyFactory.createNaturalIdRegionAccessStrategy( this, accessType ); + } +} \ No newline at end of file diff --git a/hibernate-ehcache/src/main/java/org/hibernate/cache/ehcache/internal/strategy/NonStrictReadWriteEhcacheNaturalIdRegionAccessStrategy.java b/hibernate-ehcache/src/main/java/org/hibernate/cache/ehcache/internal/strategy/NonStrictReadWriteEhcacheNaturalIdRegionAccessStrategy.java new file mode 100644 index 0000000000..cbcf454aa0 --- /dev/null +++ b/hibernate-ehcache/src/main/java/org/hibernate/cache/ehcache/internal/strategy/NonStrictReadWriteEhcacheNaturalIdRegionAccessStrategy.java @@ -0,0 +1,99 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2011, 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.internal.strategy; + +import org.hibernate.cache.CacheException; +import org.hibernate.cache.ehcache.internal.regions.EhcacheNaturalIdRegion; +import org.hibernate.cache.spi.NaturalIdRegion; +import org.hibernate.cache.spi.access.NaturalIdRegionAccessStrategy; +import org.hibernate.cache.spi.access.SoftLock; +import org.hibernate.cfg.Settings; + +/** + * Ehcache specific non-strict read/write NaturalId region access strategy + * + * @author Chris Dennis + * @author Alex Snaps + */ +public class NonStrictReadWriteEhcacheNaturalIdRegionAccessStrategy + extends AbstractEhcacheAccessStrategy + implements NaturalIdRegionAccessStrategy { + + /** + * Create a non-strict read/write access strategy accessing the given NaturalId region. + */ + public NonStrictReadWriteEhcacheNaturalIdRegionAccessStrategy(EhcacheNaturalIdRegion region, Settings settings) { + super( region, settings ); + } + + /** + * {@inheritDoc} + */ + public NaturalIdRegion getRegion() { + return region; + } + + /** + * {@inheritDoc} + */ + public Object get(Object key, long txTimestamp) throws CacheException { + return region.get( key ); + } + + /** + * {@inheritDoc} + */ + public boolean putFromLoad(Object key, Object value, long txTimestamp, Object version, boolean minimalPutOverride) + throws CacheException { + if ( minimalPutOverride && region.contains( key ) ) { + return false; + } + else { + region.put( key, value ); + return true; + } + } + + /** + * Since this is a non-strict read/write strategy item locking is not used. + */ + public SoftLock lockItem(Object key, Object version) throws CacheException { + return null; + } + + /** + * Since this is a non-strict read/write strategy item locking is not used. + */ + public void unlockItem(Object key, SoftLock lock) throws CacheException { + region.remove( key ); + } + + /** + * {@inheritDoc} + */ + @Override + public void remove(Object key) throws CacheException { + region.remove( key ); + } +} diff --git a/hibernate-ehcache/src/main/java/org/hibernate/cache/ehcache/internal/strategy/ReadOnlyEhcacheNaturalIdRegionAccessStrategy.java b/hibernate-ehcache/src/main/java/org/hibernate/cache/ehcache/internal/strategy/ReadOnlyEhcacheNaturalIdRegionAccessStrategy.java new file mode 100644 index 0000000000..fe497383e3 --- /dev/null +++ b/hibernate-ehcache/src/main/java/org/hibernate/cache/ehcache/internal/strategy/ReadOnlyEhcacheNaturalIdRegionAccessStrategy.java @@ -0,0 +1,93 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2011, 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.internal.strategy; + +import org.hibernate.cache.CacheException; +import org.hibernate.cache.ehcache.internal.regions.EhcacheNaturalIdRegion; +import org.hibernate.cache.spi.NaturalIdRegion; +import org.hibernate.cache.spi.access.NaturalIdRegionAccessStrategy; +import org.hibernate.cache.spi.access.SoftLock; +import org.hibernate.cfg.Settings; + +/** + * Ehcache specific read-only NaturalId region access strategy + * + * @author Chris Dennis + * @author Alex Snaps + */ +public class ReadOnlyEhcacheNaturalIdRegionAccessStrategy + extends AbstractEhcacheAccessStrategy + implements NaturalIdRegionAccessStrategy { + + /** + * Create a read-only access strategy accessing the given NaturalId region. + */ + public ReadOnlyEhcacheNaturalIdRegionAccessStrategy(EhcacheNaturalIdRegion region, Settings settings) { + super( region, settings ); + } + + /** + * {@inheritDoc} + */ + public NaturalIdRegion getRegion() { + return region; + } + + /** + * {@inheritDoc} + */ + public Object get(Object key, long txTimestamp) throws CacheException { + return region.get( key ); + } + + /** + * {@inheritDoc} + */ + public boolean putFromLoad(Object key, Object value, long txTimestamp, Object version, boolean minimalPutOverride) + throws CacheException { + if ( minimalPutOverride && region.contains( key ) ) { + return false; + } + else { + region.put( key, value ); + return true; + } + } + + /** + * Throws UnsupportedOperationException since this cache is read-only + * + * @throws UnsupportedOperationException always + */ + public SoftLock lockItem(Object key, Object version) throws UnsupportedOperationException { + throw new UnsupportedOperationException( "Can't write to a readonly object" ); + } + + /** + * A no-op since this cache is read-only + */ + public void unlockItem(Object key, SoftLock lock) throws CacheException { + //throw new UnsupportedOperationException("Can't write to a readonly object"); + } +} diff --git a/hibernate-ehcache/src/main/java/org/hibernate/cache/ehcache/internal/strategy/ReadWriteEhcacheNaturalIdRegionAccessStrategy.java b/hibernate-ehcache/src/main/java/org/hibernate/cache/ehcache/internal/strategy/ReadWriteEhcacheNaturalIdRegionAccessStrategy.java new file mode 100644 index 0000000000..0384da7789 --- /dev/null +++ b/hibernate-ehcache/src/main/java/org/hibernate/cache/ehcache/internal/strategy/ReadWriteEhcacheNaturalIdRegionAccessStrategy.java @@ -0,0 +1,54 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2011, 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.internal.strategy; + +import org.hibernate.cache.ehcache.internal.regions.EhcacheNaturalIdRegion; +import org.hibernate.cache.spi.NaturalIdRegion; +import org.hibernate.cache.spi.access.NaturalIdRegionAccessStrategy; +import org.hibernate.cfg.Settings; + +/** + * Ehcache specific read/write NaturalId region access strategy + * + * @author Chris Dennis + * @author Alex Snaps + */ +public class ReadWriteEhcacheNaturalIdRegionAccessStrategy + extends AbstractReadWriteEhcacheAccessStrategy + implements NaturalIdRegionAccessStrategy { + + /** + * Create a read/write access strategy accessing the given NaturalId region. + */ + public ReadWriteEhcacheNaturalIdRegionAccessStrategy(EhcacheNaturalIdRegion region, Settings settings) { + super( region, settings ); + } + + /** + * {@inheritDoc} + */ + public NaturalIdRegion getRegion() { + return region; + } +} \ No newline at end of file diff --git a/hibernate-ehcache/src/main/java/org/hibernate/cache/ehcache/internal/strategy/TransactionalEhcacheNaturalIdRegionAccessStrategy.java b/hibernate-ehcache/src/main/java/org/hibernate/cache/ehcache/internal/strategy/TransactionalEhcacheNaturalIdRegionAccessStrategy.java new file mode 100644 index 0000000000..42e30c9046 --- /dev/null +++ b/hibernate-ehcache/src/main/java/org/hibernate/cache/ehcache/internal/strategy/TransactionalEhcacheNaturalIdRegionAccessStrategy.java @@ -0,0 +1,127 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2011, 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.internal.strategy; + +import net.sf.ehcache.Ehcache; +import net.sf.ehcache.Element; + +import org.hibernate.cache.CacheException; +import org.hibernate.cache.ehcache.internal.regions.EhcacheNaturalIdRegion; +import org.hibernate.cache.spi.NaturalIdRegion; +import org.hibernate.cache.spi.access.NaturalIdRegionAccessStrategy; +import org.hibernate.cache.spi.access.SoftLock; +import org.hibernate.cfg.Settings; + +/** + * JTA NaturalIdRegionAccessStrategy. + * + * @author Chris Dennis + * @author Ludovic Orban + * @author Alex Snaps + */ +public class TransactionalEhcacheNaturalIdRegionAccessStrategy + extends AbstractEhcacheAccessStrategy + implements NaturalIdRegionAccessStrategy { + + private final Ehcache ehcache; + + /** + * Construct a new collection region access strategy. + * + * @param region the Hibernate region. + * @param ehcache the cache. + * @param settings the Hibernate settings. + */ + public TransactionalEhcacheNaturalIdRegionAccessStrategy(EhcacheNaturalIdRegion region, Ehcache ehcache, Settings settings) { + super( region, settings ); + this.ehcache = ehcache; + } + + + /** + * {@inheritDoc} + */ + public Object get(Object key, long txTimestamp) throws CacheException { + try { + Element element = ehcache.get( key ); + return element == null ? null : element.getObjectValue(); + } + catch ( net.sf.ehcache.CacheException e ) { + throw new CacheException( e ); + } + } + + /** + * {@inheritDoc} + */ + public NaturalIdRegion getRegion() { + return region; + } + + /** + * {@inheritDoc} + */ + public SoftLock lockItem(Object key, Object version) throws CacheException { + return null; + } + + /** + * {@inheritDoc} + */ + public boolean putFromLoad(Object key, Object value, long txTimestamp, + Object version, boolean minimalPutOverride) throws CacheException { + try { + if ( minimalPutOverride && ehcache.get( key ) != null ) { + return false; + } + //OptimisticCache? versioning? + ehcache.put( new Element( key, value ) ); + return true; + } + catch ( net.sf.ehcache.CacheException e ) { + throw new CacheException( e ); + } + } + + /** + * {@inheritDoc} + */ + @Override + public void remove(Object key) throws CacheException { + try { + ehcache.remove( key ); + } + catch ( net.sf.ehcache.CacheException e ) { + throw new CacheException( e ); + } + } + + /** + * {@inheritDoc} + */ + public void unlockItem(Object key, SoftLock lock) throws CacheException { + // no-op + } + +} diff --git a/hibernate-entitymanager/src/test/java/org/hibernate/ejb/test/ejb3configuration/PersisterClassProviderTest.java b/hibernate-entitymanager/src/test/java/org/hibernate/ejb/test/ejb3configuration/PersisterClassProviderTest.java index bf08183fbc..548c28bc7b 100644 --- a/hibernate-entitymanager/src/test/java/org/hibernate/ejb/test/ejb3configuration/PersisterClassProviderTest.java +++ b/hibernate-entitymanager/src/test/java/org/hibernate/ejb/test/ejb3configuration/PersisterClassProviderTest.java @@ -258,11 +258,6 @@ public class PersisterClassProviderTest { return false; } - @Override - public boolean isNatrualIdentifierCached() { - return false; - } - @Override public int[] getNaturalIdentifierProperties() { return new int[0]; diff --git a/hibernate-testing/src/main/java/org/hibernate/testing/cache/BaseNaturalIdRegionAccessStrategy.java b/hibernate-testing/src/main/java/org/hibernate/testing/cache/BaseNaturalIdRegionAccessStrategy.java new file mode 100644 index 0000000000..ca0fd82902 --- /dev/null +++ b/hibernate-testing/src/main/java/org/hibernate/testing/cache/BaseNaturalIdRegionAccessStrategy.java @@ -0,0 +1,53 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2010-2011, 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.testing.cache; + +import org.hibernate.cache.spi.NaturalIdRegion; +import org.hibernate.cache.spi.access.NaturalIdRegionAccessStrategy; + +/** + * @author Eric Dalquist + */ +class BaseNaturalIdRegionAccessStrategy extends BaseRegionAccessStrategy implements NaturalIdRegionAccessStrategy { + private final NaturalIdRegionImpl region; + + @Override + protected BaseGeneralDataRegion getInternalRegion() { + return region; + } + + @Override + protected boolean isDefaultMinimalPutOverride() { + return region.getSettings().isMinimalPutsEnabled(); + } + + @Override + public NaturalIdRegion getRegion() { + return region; + } + + BaseNaturalIdRegionAccessStrategy(NaturalIdRegionImpl region) { + this.region = region; + } +} diff --git a/hibernate-testing/src/main/java/org/hibernate/testing/cache/NaturalIdRegionImpl.java b/hibernate-testing/src/main/java/org/hibernate/testing/cache/NaturalIdRegionImpl.java new file mode 100644 index 0000000000..570f83a0c4 --- /dev/null +++ b/hibernate-testing/src/main/java/org/hibernate/testing/cache/NaturalIdRegionImpl.java @@ -0,0 +1,73 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2010-2011, 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.testing.cache; + +import org.hibernate.cache.CacheException; +import org.hibernate.cache.spi.CacheDataDescription; +import org.hibernate.cache.spi.NaturalIdRegion; +import org.hibernate.cache.spi.access.AccessType; +import org.hibernate.cache.spi.access.NaturalIdRegionAccessStrategy; +import org.hibernate.cfg.Settings; +import org.hibernate.internal.CoreMessageLogger; +import org.jboss.logging.Logger; + +/** + * @author Eric Dalquist + */ +class NaturalIdRegionImpl extends BaseTransactionalDataRegion implements NaturalIdRegion { + private static final CoreMessageLogger LOG = Logger.getMessageLogger( + CoreMessageLogger.class, NaturalIdRegionImpl.class.getName() + ); + private final Settings settings; + NaturalIdRegionImpl(String name, CacheDataDescription metadata, Settings settings) { + super( name, metadata ); + this.settings=settings; + } + + public Settings getSettings() { + return settings; + } + + @Override + public NaturalIdRegionAccessStrategy buildAccessStrategy(AccessType accessType) throws CacheException { + switch ( accessType ) { + case READ_ONLY: + if ( getCacheDataDescription().isMutable() ) { + LOG.warnf( "read-only cache configured for mutable collection [ %s ]", getName() ); + } + return new ReadOnlyNaturalIdRegionAccessStrategy( this ); + case READ_WRITE: + return new ReadWriteNaturalIdRegionAccessStrategy( this ); + case NONSTRICT_READ_WRITE: + return new NonstrictReadWriteNaturalIdRegionAccessStrategy( this ); + case TRANSACTIONAL: + return new TransactionalNaturalIdRegionAccessStrategy( this ); +// throw new UnsupportedOperationException( "doesn't support this access strategy" ); + default: + throw new IllegalArgumentException( "unrecognized access strategy type [" + accessType + "]" ); + } + } + + +} diff --git a/hibernate-testing/src/main/java/org/hibernate/testing/cache/NonstrictReadWriteNaturalIdRegionAccessStrategy.java b/hibernate-testing/src/main/java/org/hibernate/testing/cache/NonstrictReadWriteNaturalIdRegionAccessStrategy.java new file mode 100644 index 0000000000..381971908c --- /dev/null +++ b/hibernate-testing/src/main/java/org/hibernate/testing/cache/NonstrictReadWriteNaturalIdRegionAccessStrategy.java @@ -0,0 +1,45 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2011, 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.testing.cache; + +import org.hibernate.cache.CacheException; +import org.hibernate.cache.spi.access.SoftLock; + +/** + * @author Eric Dalquist + */ +class NonstrictReadWriteNaturalIdRegionAccessStrategy extends BaseNaturalIdRegionAccessStrategy { + NonstrictReadWriteNaturalIdRegionAccessStrategy(NaturalIdRegionImpl region) { + super( region ); + } + @Override + public void unlockItem(Object key, SoftLock lock) throws CacheException { + evict( key ); + } + + @Override + public void remove(Object key) throws CacheException { + evict( key ); + } +} diff --git a/hibernate-testing/src/main/java/org/hibernate/testing/cache/ReadOnlyNaturalIdRegionAccessStrategy.java b/hibernate-testing/src/main/java/org/hibernate/testing/cache/ReadOnlyNaturalIdRegionAccessStrategy.java new file mode 100644 index 0000000000..d8268e5260 --- /dev/null +++ b/hibernate-testing/src/main/java/org/hibernate/testing/cache/ReadOnlyNaturalIdRegionAccessStrategy.java @@ -0,0 +1,57 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2010-2011, 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.testing.cache; + +import org.jboss.logging.Logger; + +import org.hibernate.cache.CacheException; +import org.hibernate.cache.spi.access.SoftLock; +import org.hibernate.internal.CoreMessageLogger; + +/** + * @author Eric Dalquist + */ +class ReadOnlyNaturalIdRegionAccessStrategy extends BaseNaturalIdRegionAccessStrategy { + private static final CoreMessageLogger LOG = Logger.getMessageLogger( + CoreMessageLogger.class, ReadOnlyNaturalIdRegionAccessStrategy.class.getName() + ); + + ReadOnlyNaturalIdRegionAccessStrategy(NaturalIdRegionImpl region) { + super( region ); + } + + @Override + public void unlockItem(Object key, SoftLock lock) throws CacheException { + LOG.invalidEditOfReadOnlyItem( key ); + } + + @Override + public SoftLock lockItem(Object key, Object version) throws CacheException { + LOG.invalidEditOfReadOnlyItem( key ); + throw new UnsupportedOperationException( "Can't write to a readonly object" ); + } + + + +} diff --git a/hibernate-testing/src/main/java/org/hibernate/testing/cache/ReadWriteNaturalIdRegionAccessStrategy.java b/hibernate-testing/src/main/java/org/hibernate/testing/cache/ReadWriteNaturalIdRegionAccessStrategy.java new file mode 100644 index 0000000000..d2092e1c5b --- /dev/null +++ b/hibernate-testing/src/main/java/org/hibernate/testing/cache/ReadWriteNaturalIdRegionAccessStrategy.java @@ -0,0 +1,62 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2010-2011, 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.testing.cache; + +import java.util.Comparator; + +import org.hibernate.cache.spi.NaturalIdRegion; +import org.hibernate.cache.spi.access.NaturalIdRegionAccessStrategy; + +/** + * @author Eric Dalquist + */ +class ReadWriteNaturalIdRegionAccessStrategy extends AbstractReadWriteAccessStrategy + implements NaturalIdRegionAccessStrategy { + + private final NaturalIdRegionImpl region; + + ReadWriteNaturalIdRegionAccessStrategy(NaturalIdRegionImpl region) { + this.region = region; + } + + @Override + Comparator getVersionComparator() { + return region.getCacheDataDescription().getVersionComparator(); + } + + @Override + protected BaseGeneralDataRegion getInternalRegion() { + return region; + } + + @Override + protected boolean isDefaultMinimalPutOverride() { + return region.getSettings().isMinimalPutsEnabled(); + } + + @Override + public NaturalIdRegion getRegion() { + return region; + } +} diff --git a/hibernate-testing/src/main/java/org/hibernate/testing/cache/TransactionalNaturalIdRegionAccessStrategy.java b/hibernate-testing/src/main/java/org/hibernate/testing/cache/TransactionalNaturalIdRegionAccessStrategy.java new file mode 100644 index 0000000000..625941399d --- /dev/null +++ b/hibernate-testing/src/main/java/org/hibernate/testing/cache/TransactionalNaturalIdRegionAccessStrategy.java @@ -0,0 +1,25 @@ +package org.hibernate.testing.cache; + +import org.hibernate.cache.CacheException; + +/** + * @author Eric Dalquist + */ +class TransactionalNaturalIdRegionAccessStrategy extends BaseNaturalIdRegionAccessStrategy { + TransactionalNaturalIdRegionAccessStrategy(NaturalIdRegionImpl region) { + super( region ); + } + + + + + /** + * {@inheritDoc} + */ + @Override + public void remove(Object key) throws CacheException { + evict( key ); + } + + +}