diff --git a/hibernate-core/src/main/java/org/hibernate/SessionFactory.java b/hibernate-core/src/main/java/org/hibernate/SessionFactory.java index af932e6393..68e109e913 100644 --- a/hibernate-core/src/main/java/org/hibernate/SessionFactory.java +++ b/hibernate-core/src/main/java/org/hibernate/SessionFactory.java @@ -32,6 +32,7 @@ import java.util.Set; import org.hibernate.engine.spi.FilterDefinition; import org.hibernate.metadata.ClassMetadata; import org.hibernate.metadata.CollectionMetadata; +import org.hibernate.proxy.EntityNotFoundDelegate; import org.hibernate.stat.Statistics; /** @@ -51,6 +52,14 @@ import org.hibernate.stat.Statistics; * @author Steve Ebersole */ public interface SessionFactory extends Referenceable, Serializable { + + public interface SessionFactoryOptions { + Interceptor getInterceptor(); + EntityNotFoundDelegate getEntityNotFoundDelegate(); + } + + public SessionFactoryOptions getSessionFactoryOptions(); + /** * Obtain a {@link Session} builder. * diff --git a/hibernate-core/src/main/java/org/hibernate/cache/internal/CacheDataDescriptionImpl.java b/hibernate-core/src/main/java/org/hibernate/cache/internal/CacheDataDescriptionImpl.java index 425dfac570..4e2bdd9f6a 100644 --- a/hibernate-core/src/main/java/org/hibernate/cache/internal/CacheDataDescriptionImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/cache/internal/CacheDataDescriptionImpl.java @@ -28,6 +28,8 @@ import java.util.Comparator; import org.hibernate.cache.spi.CacheDataDescription; import org.hibernate.mapping.Collection; import org.hibernate.mapping.PersistentClass; +import org.hibernate.metamodel.binding.EntityBinding; +import org.hibernate.metamodel.binding.PluralAttributeBinding; import org.hibernate.type.VersionType; /** @@ -66,6 +68,14 @@ public class CacheDataDescriptionImpl implements CacheDataDescription { ); } + public static CacheDataDescriptionImpl decode(EntityBinding model) { + return new CacheDataDescriptionImpl( + model.isMutable(), + model.isVersioned(), + getVersionComparator( model ) + ); + } + public static CacheDataDescriptionImpl decode(Collection model) { return new CacheDataDescriptionImpl( model.isMutable(), @@ -73,4 +83,25 @@ public class CacheDataDescriptionImpl implements CacheDataDescription { model.getOwner().isVersioned() ? ( ( VersionType ) model.getOwner().getVersion().getType() ).getComparator() : null ); } + + public static CacheDataDescriptionImpl decode(PluralAttributeBinding model) { + return new CacheDataDescriptionImpl( + model.isMutable(), + model.getEntityBinding().isVersioned(), + getVersionComparator( model.getEntityBinding() ) + ); + } + + private static Comparator getVersionComparator(EntityBinding model ) { + Comparator versionComparator = null; + if ( model.isVersioned() ) { + versionComparator = ( + ( VersionType ) model + .getVersioningValueBinding() + .getHibernateTypeDescriptor() + .getExplicitType() + ).getComparator(); + } + return versionComparator; + } } diff --git a/hibernate-core/src/main/java/org/hibernate/cache/spi/access/CollectionRegionAccessStrategy.java b/hibernate-core/src/main/java/org/hibernate/cache/spi/access/CollectionRegionAccessStrategy.java index 6f88fd1c6a..7187fec426 100644 --- a/hibernate-core/src/main/java/org/hibernate/cache/spi/access/CollectionRegionAccessStrategy.java +++ b/hibernate-core/src/main/java/org/hibernate/cache/spi/access/CollectionRegionAccessStrategy.java @@ -23,7 +23,6 @@ */ package org.hibernate.cache.spi.access; -import org.hibernate.cache.CacheException; import org.hibernate.cache.spi.CollectionRegion; /** @@ -39,7 +38,7 @@ import org.hibernate.cache.spi.CollectionRegion; * @author Gavin King * @author Steve Ebersole */ -public interface CollectionRegionAccessStrategy { +public interface CollectionRegionAccessStrategy extends RegionAccessStrategy { /** * Get the wrapped collection cache region @@ -48,125 +47,4 @@ public interface CollectionRegionAccessStrategy { */ public CollectionRegion getRegion(); - /** - * Attempt to retrieve an object from the cache. Mainly used in attempting - * to resolve entities/collections from the second level cache. - * - * @param key The key of the item to be retrieved. - * @param txTimestamp a timestamp prior to the transaction start time - * @return the cached object or null - * @throws org.hibernate.cache.CacheException Propogated from underlying {@link org.hibernate.cache.spi.Region} - */ - public Object get(Object key, long txTimestamp) throws CacheException; - - /** - * Attempt to cache an object, after loading from the database. - * - * @param key The item key - * @param value The item - * @param txTimestamp a timestamp prior to the transaction start time - * @param version the item version number - * @return true if the object was successfully cached - * @throws CacheException Propogated from underlying {@link org.hibernate.cache.spi.Region} - */ - public boolean putFromLoad( - Object key, - Object value, - long txTimestamp, - Object version) throws CacheException; - - /** - * Attempt to cache an object, after loading from the database, explicitly - * specifying the minimalPut behavior. - * - * @param key The item key - * @param value The item - * @param txTimestamp a timestamp prior to the transaction start time - * @param version the item version number - * @param minimalPutOverride Explicit minimalPut flag - * @return true if the object was successfully cached - * @throws CacheException Propogated from underlying {@link org.hibernate.cache.spi.Region} - */ - public boolean putFromLoad( - Object key, - Object value, - long txTimestamp, - Object version, - boolean minimalPutOverride) throws CacheException; - - /** - * We are going to attempt to update/delete the keyed object. This - * method is used by "asynchronous" concurrency strategies. - *

- * The returned object must be passed back to release(), to release the - * lock. Concurrency strategies which do not support client-visible - * locks may silently return null. - * - * @param key The key of the item to lock - * @param version The item's current version value - * @return A representation of our lock on the item; or null. - * @throws CacheException Propogated from underlying {@link org.hibernate.cache.spi.Region} - */ - public SoftLock lockItem(Object key, Object version) throws CacheException; - - /** - * Lock the entire region - * - * @return A representation of our lock on the item; or null. - * @throws CacheException Propogated from underlying {@link org.hibernate.cache.spi.Region} - */ - public SoftLock lockRegion() throws CacheException; - - /** - * Called when we have finished the attempted update/delete (which may or - * may not have been successful), after transaction completion. This method - * is used by "asynchronous" concurrency strategies. - * - * @param key The item key - * @param lock The lock previously obtained from {@link #lockItem} - * @throws CacheException Propogated from underlying {@link org.hibernate.cache.spi.Region} - */ - public void unlockItem(Object key, SoftLock lock) throws CacheException; - - /** - * Called after we have finished the attempted invalidation of the entire - * region - * - * @param lock The lock previously obtained from {@link #lockRegion} - * @throws CacheException Propogated from underlying {@link org.hibernate.cache.spi.Region} - */ - public void unlockRegion(SoftLock lock) throws CacheException; - - /** - * Called after an item has become stale (before the transaction completes). - * This method is used by "synchronous" concurrency strategies. - * - * @param key The key of the item to remove - * @throws CacheException Propogated from underlying {@link org.hibernate.cache.spi.Region} - */ - public void remove(Object key) throws CacheException; - - /** - * Called to evict data from the entire region - * - * @throws CacheException Propogated from underlying {@link org.hibernate.cache.spi.Region} - */ - public void removeAll() throws CacheException; - - /** - * Forcibly evict an item from the cache immediately without regard for transaction - * isolation. - * - * @param key The key of the item to remove - * @throws CacheException Propogated from underlying {@link org.hibernate.cache.spi.Region} - */ - public void evict(Object key) throws CacheException; - - /** - * Forcibly evict all items from the cache immediately without regard for transaction - * isolation. - * - * @throws CacheException Propogated from underlying {@link org.hibernate.cache.spi.Region} - */ - public void evictAll() throws CacheException; } diff --git a/hibernate-core/src/main/java/org/hibernate/cache/spi/access/EntityRegionAccessStrategy.java b/hibernate-core/src/main/java/org/hibernate/cache/spi/access/EntityRegionAccessStrategy.java index 7b110fe46c..faf27cc846 100644 --- a/hibernate-core/src/main/java/org/hibernate/cache/spi/access/EntityRegionAccessStrategy.java +++ b/hibernate-core/src/main/java/org/hibernate/cache/spi/access/EntityRegionAccessStrategy.java @@ -41,7 +41,7 @@ import org.hibernate.cache.spi.EntityRegion; * @author Gavin King * @author Steve Ebersole */ -public interface EntityRegionAccessStrategy { +public interface EntityRegionAccessStrategy extends RegionAccessStrategy{ /** * Get the wrapped entity cache region @@ -50,95 +50,6 @@ public interface EntityRegionAccessStrategy { */ public EntityRegion getRegion(); - /** - * Attempt to retrieve an object from the cache. Mainly used in attempting - * to resolve entities/collections from the second level cache. - * - * @param key The key of the item to be retrieved. - * @param txTimestamp a timestamp prior to the transaction start time - * @return the cached object or null - * @throws CacheException Propogated from underlying {@link org.hibernate.cache.spi.Region} - */ - public Object get(Object key, long txTimestamp) throws CacheException; - - /** - * Attempt to cache an object, after loading from the database. - * - * @param key The item key - * @param value The item - * @param txTimestamp a timestamp prior to the transaction start time - * @param version the item version number - * @return true if the object was successfully cached - * @throws CacheException Propogated from underlying {@link org.hibernate.cache.spi.Region} - */ - public boolean putFromLoad( - Object key, - Object value, - long txTimestamp, - Object version) throws CacheException; - - /** - * Attempt to cache an object, after loading from the database, explicitly - * specifying the minimalPut behavior. - * - * @param key The item key - * @param value The item - * @param txTimestamp a timestamp prior to the transaction start time - * @param version the item version number - * @param minimalPutOverride Explicit minimalPut flag - * @return true if the object was successfully cached - * @throws CacheException Propogated from underlying {@link org.hibernate.cache.spi.Region} - */ - public boolean putFromLoad( - Object key, - Object value, - long txTimestamp, - Object version, - boolean minimalPutOverride) throws CacheException; - - /** - * We are going to attempt to update/delete the keyed object. This - * method is used by "asynchronous" concurrency strategies. - *

- * The returned object must be passed back to release(), to release the - * lock. Concurrency strategies which do not support client-visible - * locks may silently return null. - * - * @param key The key of the item to lock - * @param version The item's current version value - * @return A representation of our lock on the item; or null. - * @throws CacheException Propogated from underlying {@link org.hibernate.cache.spi.Region} - */ - public SoftLock lockItem(Object key, Object version) throws CacheException; - - /** - * Lock the entire region - * - * @return A representation of our lock on the item; or null. - * @throws CacheException Propogated from underlying {@link org.hibernate.cache.spi.Region} - */ - public SoftLock lockRegion() throws CacheException; - - /** - * Called when we have finished the attempted update/delete (which may or - * may not have been successful), after transaction completion. This method - * is used by "asynchronous" concurrency strategies. - * - * @param key The item key - * @param lock The lock previously obtained from {@link #lockItem} - * @throws CacheException Propogated from underlying {@link org.hibernate.cache.spi.Region} - */ - public void unlockItem(Object key, SoftLock lock) throws CacheException; - - /** - * Called after we have finished the attempted invalidation of the entire - * region - * - * @param lock The lock previously obtained from {@link #lockRegion} - * @throws CacheException Propogated from underlying {@link org.hibernate.cache.spi.Region} - */ - public void unlockRegion(SoftLock lock) throws CacheException; - /** * Called after an item has been inserted (before the transaction completes), * instead of calling evict(). diff --git a/hibernate-core/src/main/java/org/hibernate/cache/spi/access/RegionAccessStrategy.java b/hibernate-core/src/main/java/org/hibernate/cache/spi/access/RegionAccessStrategy.java new file mode 100644 index 0000000000..c60c4f25e0 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/cache/spi/access/RegionAccessStrategy.java @@ -0,0 +1,153 @@ +/* + * 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.spi.access; + +import org.hibernate.cache.CacheException; + +/** + * @author Gail Badner + */ +public interface RegionAccessStrategy { + /** + * Attempt to retrieve an object from the cache. Mainly used in attempting + * to resolve entities/collections from the second level cache. + * + * @param key The key of the item to be retrieved. + * @param txTimestamp a timestamp prior to the transaction start time + * @return the cached object or null + * @throws org.hibernate.cache.CacheException Propogated from underlying {@link org.hibernate.cache.spi.Region} + */ + Object get(Object key, long txTimestamp) throws CacheException; + + /** + * Attempt to cache an object, after loading from the database. + * + * @param key The item key + * @param value The item + * @param txTimestamp a timestamp prior to the transaction start time + * @param version the item version number + * @return true if the object was successfully cached + * @throws org.hibernate.cache.CacheException Propogated from underlying {@link org.hibernate.cache.spi.Region} + */ + boolean putFromLoad( + Object key, + Object value, + long txTimestamp, + Object version) throws CacheException; + + /** + * Attempt to cache an object, after loading from the database, explicitly + * specifying the minimalPut behavior. + * + * @param key The item key + * @param value The item + * @param txTimestamp a timestamp prior to the transaction start time + * @param version the item version number + * @param minimalPutOverride Explicit minimalPut flag + * @return true if the object was successfully cached + * @throws org.hibernate.cache.CacheException Propogated from underlying {@link org.hibernate.cache.spi.Region} + */ + boolean putFromLoad( + Object key, + Object value, + long txTimestamp, + Object version, + boolean minimalPutOverride) throws CacheException; + + /** + * We are going to attempt to update/delete the keyed object. This + * method is used by "asynchronous" concurrency strategies. + *

+ * The returned object must be passed back to release(), to release the + * lock. Concurrency strategies which do not support client-visible + * locks may silently return null. + * + * @param key The key of the item to lock + * @param version The item's current version value + * @return A representation of our lock on the item; or null. + * @throws org.hibernate.cache.CacheException Propogated from underlying {@link org.hibernate.cache.spi.Region} + */ + SoftLock lockItem(Object key, Object version) throws CacheException; + + /** + * Lock the entire region + * + * @return A representation of our lock on the item; or null. + * @throws org.hibernate.cache.CacheException Propogated from underlying {@link org.hibernate.cache.spi.Region} + */ + SoftLock lockRegion() throws CacheException; + + /** + * Called when we have finished the attempted update/delete (which may or + * may not have been successful), after transaction completion. This method + * is used by "asynchronous" concurrency strategies. + * + * @param key The item key + * @param lock The lock previously obtained from {@link #lockItem} + * @throws org.hibernate.cache.CacheException Propogated from underlying {@link org.hibernate.cache.spi.Region} + */ + void unlockItem(Object key, SoftLock lock) throws CacheException; + + /** + * Called after we have finished the attempted invalidation of the entire + * region + * + * @param lock The lock previously obtained from {@link #lockRegion} + * @throws org.hibernate.cache.CacheException Propogated from underlying {@link org.hibernate.cache.spi.Region} + */ + void unlockRegion(SoftLock lock) throws CacheException; + + /** + * Called after an item has become stale (before the transaction completes). + * This method is used by "synchronous" concurrency strategies. + * + * @param key The key of the item to remove + * @throws org.hibernate.cache.CacheException Propogated from underlying {@link org.hibernate.cache.spi.Region} + */ + void remove(Object key) throws CacheException; + + /** + * Called to evict data from the entire region + * + * @throws org.hibernate.cache.CacheException Propogated from underlying {@link org.hibernate.cache.spi.Region} + */ + void removeAll() throws CacheException; + + /** + * Forcibly evict an item from the cache immediately without regard for transaction + * isolation. + * + * @param key The key of the item to remove + * @throws org.hibernate.cache.CacheException Propogated from underlying {@link org.hibernate.cache.spi.Region} + */ + void evict(Object key) throws CacheException; + + /** + * Forcibly evict all items from the cache immediately without regard for transaction + * isolation. + * + * @throws org.hibernate.cache.CacheException Propogated from underlying {@link org.hibernate.cache.spi.Region} + */ + void evictAll() throws CacheException; +} diff --git a/hibernate-core/src/main/java/org/hibernate/cfg/HbmBinder.java b/hibernate-core/src/main/java/org/hibernate/cfg/HbmBinder.java index 5a925154b8..b45043307a 100644 --- a/hibernate-core/src/main/java/org/hibernate/cfg/HbmBinder.java +++ b/hibernate-core/src/main/java/org/hibernate/cfg/HbmBinder.java @@ -2661,6 +2661,7 @@ public final class HbmBinder { String comment = cmAtt == null ? null : cmAtt.getValue(); NamedQueryDefinition namedQuery = new NamedQueryDefinition( + queryName, query, cacheable, region, @@ -2673,7 +2674,7 @@ public final class HbmBinder { getParameterTypes(queryElem) ); - mappings.addQuery( queryName, namedQuery ); + mappings.addQuery( namedQuery.getName(), namedQuery ); } public static CacheMode getCacheMode(String cacheMode) { diff --git a/hibernate-core/src/main/java/org/hibernate/cfg/NamedSQLQuerySecondPass.java b/hibernate-core/src/main/java/org/hibernate/cfg/NamedSQLQuerySecondPass.java index 636b94df4a..478912e0f5 100644 --- a/hibernate-core/src/main/java/org/hibernate/cfg/NamedSQLQuerySecondPass.java +++ b/hibernate-core/src/main/java/org/hibernate/cfg/NamedSQLQuerySecondPass.java @@ -84,6 +84,7 @@ public class NamedSQLQuerySecondPass extends ResultSetMappingBinder implements Q String resultSetRef = ref == null ? null : ref.getValue(); if ( StringHelper.isNotEmpty( resultSetRef ) ) { namedQuery = new NamedSQLQueryDefinition( + queryName, queryElem.getText(), resultSetRef, synchronizedTables, @@ -103,6 +104,7 @@ public class NamedSQLQuerySecondPass extends ResultSetMappingBinder implements Q else { ResultSetMappingDefinition definition = buildResultSetMappingDefinition( queryElem, path, mappings ); namedQuery = new NamedSQLQueryDefinition( + queryName, queryElem.getText(), definition.getQueryReturns(), synchronizedTables, @@ -119,7 +121,7 @@ public class NamedSQLQuerySecondPass extends ResultSetMappingBinder implements Q ); } - LOG.debugf("Named SQL query: %s -> %s", queryName, namedQuery.getQueryString()); + LOG.debugf("Named SQL query: %s -> %s", namedQuery.getName(), namedQuery.getQueryString()); mappings.addSQLQuery( queryName, namedQuery ); } } diff --git a/hibernate-core/src/main/java/org/hibernate/cfg/SettingsFactory.java b/hibernate-core/src/main/java/org/hibernate/cfg/SettingsFactory.java index 7b88455ecb..1286675c25 100644 --- a/hibernate-core/src/main/java/org/hibernate/cfg/SettingsFactory.java +++ b/hibernate-core/src/main/java/org/hibernate/cfg/SettingsFactory.java @@ -61,7 +61,7 @@ public class SettingsFactory implements Serializable { public static final String DEF_CACHE_REG_FACTORY = NoCachingRegionFactory.class.getName(); - protected SettingsFactory() { + public SettingsFactory() { } public Settings buildSettings(Properties props, ServiceRegistry serviceRegistry) { diff --git a/hibernate-core/src/main/java/org/hibernate/cfg/annotations/QueryBinder.java b/hibernate-core/src/main/java/org/hibernate/cfg/annotations/QueryBinder.java index 03648535a0..cb1ad0e7d8 100644 --- a/hibernate-core/src/main/java/org/hibernate/cfg/annotations/QueryBinder.java +++ b/hibernate-core/src/main/java/org/hibernate/cfg/annotations/QueryBinder.java @@ -64,6 +64,7 @@ public abstract class QueryBinder { QueryHint[] hints = queryAnn.hints(); String queryName = queryAnn.query(); NamedQueryDefinition query = new NamedQueryDefinition( + queryAnn.name(), queryName, getBoolean( queryName, "org.hibernate.cacheable", hints ), getString( queryName, "org.hibernate.cacheRegion", hints ), @@ -76,12 +77,12 @@ public abstract class QueryBinder { null ); if ( isDefault ) { - mappings.addDefaultQuery( queryAnn.name(), query ); + mappings.addDefaultQuery( query.getName(), query ); } else { - mappings.addQuery( queryAnn.name(), query ); + mappings.addQuery( query.getName(), query ); } - LOG.debugf( "Binding named query: %s => %s", queryAnn.name(), queryAnn.query() ); + LOG.debugf( "Binding named query: %s => %s", query.getName(), query.getQueryString() ); } @@ -97,6 +98,7 @@ public abstract class QueryBinder { if ( !BinderHelper.isEmptyAnnotationValue( resultSetMapping ) ) { //sql result set usage query = new NamedSQLQueryDefinition( + queryAnn.name(), queryName, resultSetMapping, null, @@ -118,6 +120,7 @@ public abstract class QueryBinder { final NativeSQLQueryRootReturn entityQueryReturn = new NativeSQLQueryRootReturn( "alias1", queryAnn.resultClass().getName(), new HashMap(), LockMode.READ ); query = new NamedSQLQueryDefinition( + queryAnn.name(), queryName, new NativeSQLQueryReturn[] { entityQueryReturn }, null, @@ -137,10 +140,10 @@ public abstract class QueryBinder { throw new NotYetImplementedException( "Pure native scalar queries are not yet supported" ); } if ( isDefault ) { - mappings.addDefaultSQLQuery( queryAnn.name(), query ); + mappings.addDefaultSQLQuery( query.getName(), query ); } else { - mappings.addSQLQuery( queryAnn.name(), query ); + mappings.addSQLQuery( query.getName(), query ); } LOG.debugf( "Binding named native query: %s => %s", queryAnn.name(), queryAnn.query() ); } @@ -155,6 +158,7 @@ public abstract class QueryBinder { if ( !BinderHelper.isEmptyAnnotationValue( resultSetMapping ) ) { //sql result set usage query = new NamedSQLQueryDefinition( + queryAnn.name(), queryAnn.query(), resultSetMapping, null, @@ -176,6 +180,7 @@ public abstract class QueryBinder { final NativeSQLQueryRootReturn entityQueryReturn = new NativeSQLQueryRootReturn( "alias1", queryAnn.resultClass().getName(), new HashMap(), LockMode.READ ); query = new NamedSQLQueryDefinition( + queryAnn.name(), queryAnn.query(), new NativeSQLQueryReturn[] { entityQueryReturn }, null, @@ -194,8 +199,8 @@ public abstract class QueryBinder { else { throw new NotYetImplementedException( "Pure native scalar queries are not yet supported" ); } - mappings.addSQLQuery( queryAnn.name(), query ); - LOG.debugf( "Binding named native query: %s => %s", queryAnn.name(), queryAnn.query() ); + mappings.addSQLQuery( query.getName(), query ); + LOG.debugf( "Binding named native query: %s => %s", query.getName(), queryAnn.query() ); } public static void bindQueries(NamedQueries queriesAnn, Mappings mappings, boolean isDefault) { @@ -229,6 +234,7 @@ public abstract class QueryBinder { flushMode = getFlushMode( queryAnn.flushMode() ); NamedQueryDefinition query = new NamedQueryDefinition( + queryAnn.name(), queryAnn.query(), queryAnn.cacheable(), BinderHelper.isEmptyAnnotationValue( queryAnn.cacheRegion() ) ? null : queryAnn.cacheRegion(), @@ -241,8 +247,8 @@ public abstract class QueryBinder { null ); - mappings.addQuery( queryAnn.name(), query ); - LOG.debugf( "Binding named query: %s => %s", queryAnn.name(), queryAnn.query() ); + mappings.addQuery( query.getName(), query ); + LOG.debugf( "Binding named query: %s => %s", query.getName(), query.getQueryString() ); } private static FlushMode getFlushMode(FlushModeType flushModeType) { diff --git a/hibernate-core/src/main/java/org/hibernate/engine/spi/NamedQueryDefinition.java b/hibernate-core/src/main/java/org/hibernate/engine/spi/NamedQueryDefinition.java index 47b97dfbfd..d021ef32a4 100755 --- a/hibernate-core/src/main/java/org/hibernate/engine/spi/NamedQueryDefinition.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/spi/NamedQueryDefinition.java @@ -35,6 +35,7 @@ import org.hibernate.FlushMode; * @author Gavin King */ public class NamedQueryDefinition implements Serializable { + private final String name; private final String query; private final boolean cacheable; private final String cacheRegion; @@ -47,6 +48,7 @@ public class NamedQueryDefinition implements Serializable { private String comment; // kept for backward compatibility until after the 3.1beta5 release of HA + // TODO: is this still needed? public NamedQueryDefinition( String query, boolean cacheable, @@ -56,6 +58,7 @@ public class NamedQueryDefinition implements Serializable { FlushMode flushMode, Map parameterTypes) { this( + null, query, cacheable, cacheRegion, @@ -70,6 +73,7 @@ public class NamedQueryDefinition implements Serializable { } public NamedQueryDefinition( + String name, String query, boolean cacheable, String cacheRegion, @@ -80,6 +84,7 @@ public class NamedQueryDefinition implements Serializable { boolean readOnly, String comment, Map parameterTypes) { + this.name = name; this.query = query; this.cacheable = cacheable; this.cacheRegion = cacheRegion; @@ -92,6 +97,10 @@ public class NamedQueryDefinition implements Serializable { this.comment = comment; } + public String getName() { + return name; + } + public String getQueryString() { return query; } diff --git a/hibernate-core/src/main/java/org/hibernate/engine/spi/NamedSQLQueryDefinition.java b/hibernate-core/src/main/java/org/hibernate/engine/spi/NamedSQLQueryDefinition.java index 106140e47d..b3f675be17 100755 --- a/hibernate-core/src/main/java/org/hibernate/engine/spi/NamedSQLQueryDefinition.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/spi/NamedSQLQueryDefinition.java @@ -62,6 +62,7 @@ public class NamedSQLQueryDefinition extends NamedQueryDefinition { * @param callable Does the query string represent a callable object (i.e., proc) */ public NamedSQLQueryDefinition( + String name, String query, NativeSQLQueryReturn[] queryReturns, List querySpaces, @@ -76,6 +77,7 @@ public class NamedSQLQueryDefinition extends NamedQueryDefinition { Map parameterTypes, boolean callable) { super( + name, query.trim(), /* trim done to workaround stupid oracle bug that cant handle whitespaces before a { in a sp */ cacheable, cacheRegion, @@ -111,6 +113,7 @@ public class NamedSQLQueryDefinition extends NamedQueryDefinition { * @param callable Does the query string represent a callable object (i.e., proc) */ public NamedSQLQueryDefinition( + String name, String query, String resultSetRef, List querySpaces, @@ -125,6 +128,7 @@ public class NamedSQLQueryDefinition extends NamedQueryDefinition { Map parameterTypes, boolean callable) { super( + name, query.trim(), /* trim done to workaround stupid oracle bug that cant handle whitespaces before a { in a sp */ cacheable, cacheRegion, @@ -172,6 +176,7 @@ public class NamedSQLQueryDefinition extends NamedQueryDefinition { Map parameterTypes, boolean callable) { this( + null, query, resultSetRef, querySpaces, 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 788a916eb0..57f16a315a 100644 --- a/hibernate-core/src/main/java/org/hibernate/internal/SessionFactoryImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/internal/SessionFactoryImpl.java @@ -75,10 +75,11 @@ import org.hibernate.cache.spi.UpdateTimestampsCache; import org.hibernate.cache.spi.access.AccessType; import org.hibernate.cache.spi.access.CollectionRegionAccessStrategy; import org.hibernate.cache.spi.access.EntityRegionAccessStrategy; -import org.hibernate.cfg.AvailableSettings; +import org.hibernate.cache.spi.access.RegionAccessStrategy; import org.hibernate.cfg.Configuration; import org.hibernate.cfg.Environment; import org.hibernate.cfg.Settings; +import org.hibernate.cfg.SettingsFactory; import org.hibernate.context.internal.ThreadLocalSessionContext; import org.hibernate.context.spi.CurrentSessionContext; import org.hibernate.context.internal.JTASessionContext; @@ -114,6 +115,7 @@ import org.hibernate.mapping.RootClass; import org.hibernate.metadata.ClassMetadata; import org.hibernate.metadata.CollectionMetadata; import org.hibernate.metamodel.binding.EntityBinding; +import org.hibernate.metamodel.binding.PluralAttributeBinding; import org.hibernate.metamodel.source.spi.MetadataImplementor; import org.hibernate.persister.collection.CollectionPersister; import org.hibernate.persister.entity.EntityPersister; @@ -180,13 +182,12 @@ public final class SessionFactoryImpl private final transient Map collectionMetadata; private final transient Map> collectionRolesByEntityParticipant; private final transient Map identifierGenerators; - private final transient Map namedQueries; - private final transient Map namedSqlQueries; - private final transient Map sqlResultSetMappings; + private final transient Map namedQueries; + private final transient Map namedSqlQueries; + private final transient Map sqlResultSetMappings; private final transient Map filters; private final transient Map fetchProfiles; - private final transient Map imports; - private final transient Interceptor interceptor; + private final transient Map imports; private final transient SessionFactoryServiceRegistry serviceRegistry; private final transient Settings settings; private final transient Properties properties; @@ -196,7 +197,6 @@ public final class SessionFactoryImpl private final transient Map queryCaches; private final transient ConcurrentMap allCacheRegions = new ConcurrentHashMap(); private final transient CurrentSessionContext currentSessionContext; - private final transient EntityNotFoundDelegate entityNotFoundDelegate; private final transient SQLFunctionRegistry sqlFunctionRegistry; private final transient SessionFactoryObserverChain observer = new SessionFactoryObserverChain(); private final transient HashMap entityNameResolvers = new HashMap(); @@ -206,18 +206,44 @@ public final class SessionFactoryImpl private final transient TypeResolver typeResolver; private final transient TypeHelper typeHelper; private final transient TransactionEnvironment transactionEnvironment; + private final transient SessionFactoryOptions sessionFactoryOptions; @SuppressWarnings( {"unchecked"} ) public SessionFactoryImpl( - Configuration cfg, + final Configuration cfg, Mapping mapping, ServiceRegistry serviceRegistry, Settings settings, SessionFactoryObserver observer) throws HibernateException { LOG.debug( "Building session factory" ); + sessionFactoryOptions = new SessionFactoryOptions() { + private EntityNotFoundDelegate entityNotFoundDelegate; + + @Override + public Interceptor getInterceptor() { + return cfg.getInterceptor(); + } + + @Override + public EntityNotFoundDelegate getEntityNotFoundDelegate() { + if ( entityNotFoundDelegate == null ) { + if ( cfg.getEntityNotFoundDelegate() != null ) { + entityNotFoundDelegate = cfg.getEntityNotFoundDelegate(); + } + else { + entityNotFoundDelegate = new EntityNotFoundDelegate() { + public void handleEntityNotFound(String entityName, Serializable id) { + throw new ObjectNotFoundException( id, entityName ); + } + }; + } + } + return entityNotFoundDelegate; + } + }; + this.settings = settings; - this.interceptor = cfg.getInterceptor(); this.properties = new Properties(); this.properties.putAll( cfg.getProperties() ); @@ -377,10 +403,10 @@ public final class SessionFactoryImpl collectionRolesByEntityParticipant = Collections.unmodifiableMap( tmpEntityToCollectionRoleMap ); //Named Queries: - namedQueries = new HashMap( cfg.getNamedQueries() ); - namedSqlQueries = new HashMap( cfg.getNamedSQLQueries() ); - sqlResultSetMappings = new HashMap( cfg.getSqlResultSetMappings() ); - imports = new HashMap( cfg.getImports() ); + namedQueries = new HashMap( cfg.getNamedQueries() ); + namedSqlQueries = new HashMap( cfg.getNamedSQLQueries() ); + sqlResultSetMappings = new HashMap( cfg.getSqlResultSetMappings() ); + imports = new HashMap( cfg.getImports() ); // after *all* persisters and named queries are registered Iterator iter = entityPersisters.values().iterator(); @@ -455,17 +481,6 @@ public final class SessionFactoryImpl } } - // EntityNotFoundDelegate - EntityNotFoundDelegate entityNotFoundDelegate = cfg.getEntityNotFoundDelegate(); - if ( entityNotFoundDelegate == null ) { - entityNotFoundDelegate = new EntityNotFoundDelegate() { - public void handleEntityNotFound(String entityName, Serializable id) { - throw new ObjectNotFoundException( id, entityName ); - } - }; - } - this.entityNotFoundDelegate = entityNotFoundDelegate; - // this needs to happen after persisters are all ready to go... this.fetchProfiles = new HashMap(); itr = cfg.iterateFetchProfiles(); @@ -509,52 +524,41 @@ public final class SessionFactoryImpl public SessionFactoryImpl( MetadataImplementor metadata, - Mapping mapping, - ServiceRegistry serviceRegistry, + SessionFactoryOptions sessionFactoryOptions, SessionFactoryObserver observer) throws HibernateException { LOG.debug( "Building session factory" ); // TODO: remove initialization of final variables; just setting to null to make compiler happy this.name = null; this.uuid = null; - this.entityPersisters = null; - this.classMetadata = null; - this.collectionPersisters = null; - this.collectionMetadata = null; - this.collectionRolesByEntityParticipant = null; - this.identifierGenerators = null; - this.namedQueries = null; - this.namedSqlQueries = null; - this.sqlResultSetMappings = null; this.fetchProfiles = null; - this.imports = null; - this.interceptor = null; this.queryCache = null; this.updateTimestampsCache = null; this.queryCaches = null; this.currentSessionContext = null; - this.entityNotFoundDelegate = null; this.sqlFunctionRegistry = null; - this.queryPlanCache = null; this.transactionEnvironment = null; - ConfigurationService configurationService = serviceRegistry.getService( ConfigurationService.class ); - this.settings = null; + this.sessionFactoryOptions = sessionFactoryOptions; - this.serviceRegistry = serviceRegistry.getService( SessionFactoryServiceRegistryFactory.class ).buildServiceRegistry( - this, - metadata + this.properties = createPropertiesFromMap( + metadata.getServiceRegistry().getService( ConfigurationService.class ).getSettings() ); - // TODO: get Interceptor from ConfurationService - //this.interceptor = cfg.getInterceptor(); + // TODO: these should be moved into SessionFactoryOptions + this.settings = new SettingsFactory().buildSettings( + properties, + metadata.getServiceRegistry() + ); - // TODO: find references to properties and make sure everything needed is available to services via - // ConfigurationService - this.properties = null; + this.serviceRegistry = + metadata.getServiceRegistry() + .getService( SessionFactoryServiceRegistryFactory.class ) + .buildServiceRegistry( this, metadata ); + + // TODO: get SQL functions from a new service + // this.sqlFunctionRegistry = new SQLFunctionRegistry( getDialect(), cfg.getSqlFunctions() ); - // TODO: should this be build along w/ metadata? seems like it should so app has more control over it... - //this.sqlFunctionRegistry = new SQLFunctionRegistry( getDialect(), metadata.getSqlFunctions() ); if ( observer != null ) { this.observer.addObserver( observer ); } @@ -568,10 +572,203 @@ public final class SessionFactoryImpl } LOG.debugf("Session factory constructed with filter configurations : %s", filters); - LOG.debugf("Instantiating session factory with properties: %s", configurationService.getSettings() ); + LOG.debugf("Instantiating session factory with properties: %s", properties ); + + // TODO: get RegionFactory from service registry + settings.getRegionFactory().start( settings, properties ); + this.queryPlanCache = new QueryPlanCache( this ); + + class IntegratorObserver implements SessionFactoryObserver { + private ArrayList integrators = new ArrayList(); + + @Override + public void sessionFactoryCreated(SessionFactory factory) { + } + + @Override + public void sessionFactoryClosed(SessionFactory factory) { + for ( Integrator integrator : integrators ) { + integrator.disintegrate( SessionFactoryImpl.this, SessionFactoryImpl.this.serviceRegistry ); + } + } + } + + final IntegratorObserver integratorObserver = new IntegratorObserver(); + this.observer.addObserver( integratorObserver ); + for ( Integrator integrator : serviceRegistry.getService( IntegratorService.class ).getIntegrators() ) { + // TODO: add Integrator.integrate(MetadataImplementor, ...) + // integrator.integrate( cfg, this, this.serviceRegistry ); + integratorObserver.integrators.add( integrator ); + } + + + //Generators: + + identifierGenerators = new HashMap(); + for ( EntityBinding entityBinding : metadata.getEntityBindings() ) { + if ( entityBinding.isRoot() ) { + // TODO: create the IdentifierGenerator while the metadata is being build, then simply + // use EntityBinding.getIdentifierGenerator() (also remove getIdentifierGeneratorFactory from Mappings) + // TODO: this is broken; throws NullPointerException + //IdentifierGenerator generator = entityBinding.getEntityIdentifier().createIdentifierGenerator( + // metadata.getIdentifierGeneratorFactory() + //); + //identifierGenerators.put( entityBinding.getEntity().getName(), generator ); + } + } + + /////////////////////////////////////////////////////////////////////// + // Prepare persisters and link them up with their cache + // region/access-strategy + + StringBuilder stringBuilder = new StringBuilder(); + if ( settings.getCacheRegionPrefix() != null) { + stringBuilder + .append( settings.getCacheRegionPrefix() ) + .append( '.' ); + } + final String cacheRegionPrefix = stringBuilder.toString(); + + entityPersisters = new HashMap(); + Map entityAccessStrategies = new HashMap(); + Map classMeta = new HashMap(); + for ( EntityBinding model : metadata.getEntityBindings() ) { + // TODO: should temp table prep happen when metadata is being built? + //model.prepareTemporaryTables( metadata, getDialect() ); + // cache region is defined by the root-class in the hierarchy... + EntityBinding rootEntityBinding = metadata.getRootEntityBinding( model.getEntity().getName() ); + EntityRegionAccessStrategy accessStrategy = null; + if ( settings.isSecondLevelCacheEnabled() && + rootEntityBinding.getCaching() != null && + model.getCaching() != null && + model.getCaching().getAccessType() != null ) { + final String cacheRegionName = cacheRegionPrefix + rootEntityBinding.getCaching().getRegion(); + accessStrategy = EntityRegionAccessStrategy.class.cast( entityAccessStrategies.get( cacheRegionName ) ); + if ( accessStrategy == null ) { + final AccessType accessType = model.getCaching().getAccessType(); + LOG.trace("Building cache for entity data [" + model.getEntity().getName() + "]"); + EntityRegion entityRegion = + settings.getRegionFactory().buildEntityRegion( + cacheRegionName, + properties, + CacheDataDescriptionImpl.decode( model ) + ); + accessStrategy = entityRegion.buildAccessStrategy( accessType ); + entityAccessStrategies.put( cacheRegionName, accessStrategy ); + allCacheRegions.put( cacheRegionName, entityRegion ); + } + } + EntityPersister cp = serviceRegistry.getService( PersisterFactory.class ).createEntityPersister( + model, accessStrategy, this, metadata + ); + entityPersisters.put( model.getEntity().getName(), cp ); + classMeta.put( model.getEntity().getName(), cp.getClassMetadata() ); + } + this.classMetadata = Collections.unmodifiableMap(classMeta); + + Map> tmpEntityToCollectionRoleMap = new HashMap>(); + collectionPersisters = new HashMap(); + for ( PluralAttributeBinding model : metadata.getCollectionBindings() ) { + if ( model.getAttribute() == null ) { + throw new IllegalStateException( "No attribute defined for a PluralAttributeBinding: " + model ); + } + if ( model.getAttribute().isSingular() ) { + throw new IllegalStateException( + "PluralAttributeBinding has a Singular attribute defined: " + model.getAttribute().getName() + ); + } + // TODO: Add PluralAttributeBinding.getCaching() + final String cacheRegionName = cacheRegionPrefix + model.getCacheRegionName(); + final AccessType accessType = AccessType.fromExternalName( model.getCacheConcurrencyStrategy() ); + CollectionRegionAccessStrategy accessStrategy = null; + if ( accessType != null && settings.isSecondLevelCacheEnabled() ) { + // TODO: is model.getAttribute().getName() the collection's role??? For now, assuming it is + LOG.trace("Building cache for collection data [" + model.getAttribute().getName() + "]"); + CollectionRegion collectionRegion = + settings.getRegionFactory() + .buildCollectionRegion( + cacheRegionName, properties, CacheDataDescriptionImpl.decode( model ) + ); + accessStrategy = collectionRegion.buildAccessStrategy( accessType ); + entityAccessStrategies.put( cacheRegionName, accessStrategy ); + allCacheRegions.put( cacheRegionName, collectionRegion ); + } + CollectionPersister persister = + serviceRegistry + .getService( PersisterFactory.class ) + .createCollectionPersister( metadata, model, accessStrategy, this ); + // TODO: is model.getAttribute().getName() the collection's role??? For now, assuming it is + collectionPersisters.put( model.getAttribute().getName(), persister.getCollectionMetadata() ); + Type indexType = persister.getIndexType(); + if ( indexType != null && indexType.isAssociationType() && !indexType.isAnyType() ) { + String entityName = ( ( AssociationType ) indexType ).getAssociatedEntityName( this ); + Set roles = tmpEntityToCollectionRoleMap.get( entityName ); + if ( roles == null ) { + roles = new HashSet(); + tmpEntityToCollectionRoleMap.put( entityName, roles ); + } + roles.add( persister.getRole() ); + } + Type elementType = persister.getElementType(); + if ( elementType.isAssociationType() && !elementType.isAnyType() ) { + String entityName = ( ( AssociationType ) elementType ).getAssociatedEntityName( this ); + Set roles = tmpEntityToCollectionRoleMap.get( entityName ); + if ( roles == null ) { + roles = new HashSet(); + tmpEntityToCollectionRoleMap.put( entityName, roles ); + } + roles.add( persister.getRole() ); + } + } + collectionMetadata = Collections.unmodifiableMap(collectionPersisters); + Iterator itr = tmpEntityToCollectionRoleMap.entrySet().iterator(); + while ( itr.hasNext() ) { + final Map.Entry entry = ( Map.Entry ) itr.next(); + entry.setValue( Collections.unmodifiableSet( ( Set ) entry.getValue() ) ); + } + collectionRolesByEntityParticipant = Collections.unmodifiableMap( tmpEntityToCollectionRoleMap ); + + //Named Queries: + namedQueries = new HashMap(); + for ( NamedQueryDefinition namedQueryDefinition : metadata.getNamedQueryDefinitions() ) { + namedQueries.put( namedQueryDefinition.getName(), namedQueryDefinition ); + } + namedSqlQueries = new HashMap(); + for ( NamedSQLQueryDefinition namedNativeQueryDefinition: metadata.getNamedNativeQueryDefinitions() ) { + namedSqlQueries.put( namedNativeQueryDefinition.getName(), namedNativeQueryDefinition ); + } + sqlResultSetMappings = new HashMap(); + for( ResultSetMappingDefinition resultSetMappingDefinition : metadata.getResultSetMappingDefinitions() ) { + sqlResultSetMappings.put( resultSetMappingDefinition.getName(), resultSetMappingDefinition ); + } + imports = new HashMap(); + for ( Map.Entry importEntry : metadata.getImports() ) { + imports.put( importEntry.getKey(), importEntry.getValue() ); + } + + // after *all* persisters and named queries are registered + Iterator iter = entityPersisters.values().iterator(); + while ( iter.hasNext() ) { + final EntityPersister persister = ( ( EntityPersister ) iter.next() ); + // TODO: broken + //persister.postInstantiate(); + registerEntityNameResolvers( persister ); + + } + iter = collectionPersisters.values().iterator(); + while ( iter.hasNext() ) { + final CollectionPersister persister = ( ( CollectionPersister ) iter.next() ); + persister.postInstantiate(); + } // TODO: implement + } + @SuppressWarnings( {"unchecked"} ) + private static Properties createPropertiesFromMap(Map map) { + Properties properties = new Properties(); + properties.putAll( map ); + return properties; } public Session openSession() throws HibernateException { @@ -762,6 +959,11 @@ public final class SessionFactoryImpl return settings; } + @Override + public SessionFactoryOptions getSessionFactoryOptions() { + return sessionFactoryOptions; + } + public JdbcServices getJdbcServices() { return serviceRegistry.getService( JdbcServices.class ); } @@ -775,7 +977,7 @@ public final class SessionFactoryImpl public Interceptor getInterceptor() { - return interceptor; + return sessionFactoryOptions.getInterceptor(); } public SQLExceptionConverter getSQLExceptionConverter() { @@ -1315,7 +1517,7 @@ public final class SessionFactoryImpl @Override public EntityNotFoundDelegate getEntityNotFoundDelegate() { - return entityNotFoundDelegate; + return sessionFactoryOptions.getEntityNotFoundDelegate(); } public SQLFunctionRegistry getSqlFunctionRegistry() { diff --git a/hibernate-core/src/main/java/org/hibernate/jmx/SessionFactoryStub.java b/hibernate-core/src/main/java/org/hibernate/jmx/SessionFactoryStub.java index 777592156e..26bfb32f9d 100644 --- a/hibernate-core/src/main/java/org/hibernate/jmx/SessionFactoryStub.java +++ b/hibernate-core/src/main/java/org/hibernate/jmx/SessionFactoryStub.java @@ -38,6 +38,8 @@ import org.jboss.logging.Logger; import org.hibernate.AssertionFailure; import org.hibernate.Cache; import org.hibernate.HibernateException; +import org.hibernate.Interceptor; +import org.hibernate.ObjectNotFoundException; import org.hibernate.StatelessSessionBuilder; import org.hibernate.internal.CoreMessageLogger; import org.hibernate.Session; @@ -51,6 +53,7 @@ import org.hibernate.id.UUIDGenerator; import org.hibernate.internal.SessionFactoryRegistry; import org.hibernate.metadata.ClassMetadata; import org.hibernate.metadata.CollectionMetadata; +import org.hibernate.proxy.EntityNotFoundDelegate; import org.hibernate.service.jndi.internal.JndiServiceImpl; import org.hibernate.stat.Statistics; @@ -88,6 +91,11 @@ public class SessionFactoryStub implements SessionFactory { SessionFactoryRegistry.INSTANCE.addSessionFactory( uuid, name, this, new JndiServiceImpl( service.getProperties() ) ); } + @Override + public SessionFactoryOptions getSessionFactoryOptions() { + return impl.getSessionFactoryOptions(); + } + @Override public SessionBuilder withOptions() { return getImpl().withOptions(); diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/Metadata.java b/hibernate-core/src/main/java/org/hibernate/metamodel/Metadata.java index a3cd180f49..8f3f861b4f 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/Metadata.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/Metadata.java @@ -24,14 +24,19 @@ package org.hibernate.metamodel; +import java.util.Map; import javax.persistence.SharedCacheMode; import org.hibernate.SessionFactory; import org.hibernate.cache.spi.access.AccessType; import org.hibernate.cfg.NamingStrategy; +import org.hibernate.engine.ResultSetMappingDefinition; import org.hibernate.engine.spi.FilterDefinition; +import org.hibernate.engine.spi.NamedQueryDefinition; +import org.hibernate.engine.spi.NamedSQLQueryDefinition; import org.hibernate.metamodel.binding.EntityBinding; import org.hibernate.metamodel.binding.IdGenerator; +import org.hibernate.metamodel.binding.PluralAttributeBinding; import org.hibernate.metamodel.binding.TypeDef; /** @@ -53,15 +58,34 @@ public interface Metadata { public Options getOptions(); + public SessionFactoryBuilder getSessionFactoryBuilder(); + public SessionFactory buildSessionFactory(); public Iterable getEntityBindings(); public EntityBinding getEntityBinding(String entityName); + /** + * Get the "root" entity binding + * @param entityName + * @return the "root entity binding; simply returns entityBinding if it is the root entity binding + */ + public EntityBinding getRootEntityBinding(String entityName); + + public Iterable getCollectionBindings(); + public Iterable getTypeDefinitions(); public Iterable getFilterDefinitions(); + public Iterable getNamedQueryDefinitions(); + + public Iterable getNamedNativeQueryDefinitions(); + + public Iterable getResultSetMappingDefinitions(); + + public Iterable> getImports(); + public IdGenerator getIdGenerator(String name); } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/SessionFactoryBuilder.java b/hibernate-core/src/main/java/org/hibernate/metamodel/SessionFactoryBuilder.java new file mode 100644 index 0000000000..c97ede7191 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/SessionFactoryBuilder.java @@ -0,0 +1,39 @@ +/* + * 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.metamodel; + +import org.hibernate.Interceptor; +import org.hibernate.SessionFactory; +import org.hibernate.proxy.EntityNotFoundDelegate; + +/** + * @author Gail Badner + */ +public interface SessionFactoryBuilder { + public SessionFactoryBuilder with(Interceptor interceptor); + + public SessionFactoryBuilder with(EntityNotFoundDelegate entityNotFoundDelegate); + + public SessionFactory buildSessionFactory(); +} diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/binding/EntityBinding.java b/hibernate-core/src/main/java/org/hibernate/metamodel/binding/EntityBinding.java index b9adc3bd1e..9cf6599423 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/binding/EntityBinding.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/binding/EntityBinding.java @@ -229,6 +229,10 @@ public class EntityBinding { return entityInheritanceType; } + public boolean isVersioned() { + return versionBinding != null; + } + public SimpleAttributeBinding getVersioningValueBinding() { return versionBinding; } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/source/annotations/global/QueryBinder.java b/hibernate-core/src/main/java/org/hibernate/metamodel/source/annotations/global/QueryBinder.java index 2a86402719..660843ff7a 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/source/annotations/global/QueryBinder.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/source/annotations/global/QueryBinder.java @@ -124,8 +124,8 @@ public class QueryBinder { comment = null; } metadata.addNamedQuery( - name, new NamedQueryDefinition( + name, query, getBoolean( hints, QueryHints.CACHEABLE, name ), cacheRegion, timeout, fetchSize, getFlushMode( hints, QueryHints.FLUSH_MODE, name ), getCacheMode( hints, QueryHints.CACHE_MODE, name ), @@ -167,6 +167,7 @@ public class QueryBinder { NamedSQLQueryDefinition def; if ( StringHelper.isNotEmpty( resultSetMapping ) ) { def = new NamedSQLQueryDefinition( + name, query, resultSetMapping, null, cacheable, cacheRegion, timeout, fetchSize, flushMode, cacheMode, readOnly, comment, @@ -179,6 +180,7 @@ public class QueryBinder { throw new NotYetImplementedException( "Pure native scalar queries are not yet supported" ); } def = new NamedSQLQueryDefinition( + name, query, new NativeSQLQueryRootReturn[] { new NativeSQLQueryRootReturn( "alias1", @@ -192,7 +194,7 @@ public class QueryBinder { ); } - metadata.addNamedNativeQuery( name, def ); + metadata.addNamedNativeQuery( def ); LOG.debugf( "Binding named native query: %s => %s", name, query ); } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/source/internal/MetadataImpl.java b/hibernate-core/src/main/java/org/hibernate/metamodel/source/internal/MetadataImpl.java index b3c35ff6f2..29cf6993bf 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/source/internal/MetadataImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/source/internal/MetadataImpl.java @@ -33,15 +33,20 @@ import java.util.Map; import org.jboss.logging.Logger; import org.hibernate.DuplicateMappingException; +import org.hibernate.MappingException; import org.hibernate.SessionFactory; import org.hibernate.cfg.NamingStrategy; +import org.hibernate.engine.ResultSetMappingDefinition; import org.hibernate.engine.spi.FilterDefinition; import org.hibernate.engine.spi.NamedQueryDefinition; import org.hibernate.engine.spi.NamedSQLQueryDefinition; import org.hibernate.id.factory.DefaultIdentifierGeneratorFactory; +import org.hibernate.id.factory.IdentifierGeneratorFactory; import org.hibernate.internal.CoreMessageLogger; import org.hibernate.metamodel.MetadataSources; +import org.hibernate.metamodel.SessionFactoryBuilder; import org.hibernate.metamodel.SourceProcessingOrder; +import org.hibernate.metamodel.binding.AttributeBinding; import org.hibernate.metamodel.binding.EntityBinding; import org.hibernate.metamodel.binding.FetchProfile; import org.hibernate.metamodel.binding.IdGenerator; @@ -58,6 +63,7 @@ import org.hibernate.metamodel.source.spi.MetaAttributeContext; import org.hibernate.metamodel.source.spi.MetadataImplementor; import org.hibernate.service.BasicServiceRegistry; import org.hibernate.service.classloading.spi.ClassLoaderService; +import org.hibernate.type.Type; import org.hibernate.type.TypeResolver; /** @@ -65,6 +71,7 @@ import org.hibernate.type.TypeResolver; * * @author Steve Ebersole * @author Hardy Ferentschik + * @author Gail Badner */ public class MetadataImpl implements MetadataImplementor, Serializable { @@ -78,6 +85,9 @@ public class MetadataImpl implements MetadataImplementor, Serializable { private ClassLoaderService classLoaderService; private TypeResolver typeResolver = new TypeResolver(); + + private SessionFactoryBuilder sessionFactoryBuilder = new SessionFactoryBuilderImpl( this ); + private DefaultIdentifierGeneratorFactory identifierGeneratorFactory = new DefaultIdentifierGeneratorFactory(); private final Database database = new Database(); @@ -88,13 +98,15 @@ public class MetadataImpl implements MetadataImplementor, Serializable { * Maps the fully qualified class name of an entity to its entity binding */ private Map entityBindingMap = new HashMap(); + private Map rootEntityBindingMap = new HashMap(); private Map collectionBindingMap = new HashMap(); private Map fetchProfiles = new HashMap(); - private Map imports; + private Map imports = new HashMap(); private Map typeDefs = new HashMap(); private Map idGenerators = new HashMap(); private Map namedQueryDefs = new HashMap(); private Map namedNativeQueryDefs = new HashMap(); + private Map resultSetMappings = new HashMap(); private Map filterDefs = new HashMap(); // todo : keep as part of Database? @@ -164,11 +176,17 @@ public class MetadataImpl implements MetadataImplementor, Serializable { @Override public void addFetchProfile(FetchProfile profile) { + if ( profile == null || profile.getName() == null ) { + throw new IllegalArgumentException( "Fetch profile object or name is null: " + profile ); + } fetchProfiles.put( profile.getName(), profile ); } @Override public void addFilterDefinition(FilterDefinition def) { + if ( def == null || def.getFilterName() == null ) { + throw new IllegalArgumentException( "Filter definition object or name is null: " + def ); + } filterDefs.put( def.getFilterName(), def ); } @@ -178,6 +196,9 @@ public class MetadataImpl implements MetadataImplementor, Serializable { @Override public void addIdGenerator(IdGenerator generator) { + if ( generator == null || generator.getName() == null ) { + throw new IllegalArgumentException( "ID generator object or name is null." ); + } idGenerators.put( generator.getName(), generator ); } @@ -195,12 +216,18 @@ public class MetadataImpl implements MetadataImplementor, Serializable { @Override public void addAuxiliaryDatabaseObject(AuxiliaryDatabaseObject auxiliaryDatabaseObject) { + if ( auxiliaryDatabaseObject == null ) { + throw new IllegalArgumentException( "Auxiliary database object is null." ); + } auxiliaryDatabaseObjects.add( auxiliaryDatabaseObject ); } @Override - public void addNamedNativeQuery(String name, NamedSQLQueryDefinition def) { - namedNativeQueryDefs.put( name, def ); + public void addNamedNativeQuery(NamedSQLQueryDefinition def) { + if ( def == null || def.getName() == null ) { + throw new IllegalArgumentException( "Named native query definition object or name is null: " + def.getQueryString() ); + } + namedNativeQueryDefs.put( def.getName(), def ); } public NamedSQLQueryDefinition getNamedNativeQuery(String name) { @@ -211,8 +238,16 @@ public class MetadataImpl implements MetadataImplementor, Serializable { } @Override - public void addNamedQuery(String name, NamedQueryDefinition def) { - namedQueryDefs.put( name, def ); + public Iterable getNamedNativeQueryDefinitions() { + return namedNativeQueryDefs.values(); + } + + @Override + public void addNamedQuery(NamedQueryDefinition def) { + if ( def == null || def.getName() == null ) { + throw new IllegalArgumentException( "Named query definition object or name is null: " + def.getQueryString() ); + } + namedQueryDefs.put( def.getName(), def ); } public NamedQueryDefinition getNamedQuery(String name) { @@ -222,8 +257,29 @@ public class MetadataImpl implements MetadataImplementor, Serializable { return namedQueryDefs.get( name ); } + @Override + public Iterable getNamedQueryDefinitions() { + return namedQueryDefs.values(); + } + + @Override + public void addResultSetMapping(ResultSetMappingDefinition resultSetMappingDefinition) { + if ( resultSetMappingDefinition == null || resultSetMappingDefinition.getName() == null ) { + throw new IllegalArgumentException( "Resultset mappping object or name is null: " + resultSetMappingDefinition ); + } + resultSetMappings.put( resultSetMappingDefinition.getName(), resultSetMappingDefinition ); + } + + @Override + public Iterable getResultSetMappingDefinitions() { + return resultSetMappings.values(); + } + @Override public void addTypeDefinition(TypeDef typeDef) { + if ( typeDef == null || typeDef.getName() == null ) { + throw new IllegalArgumentException( "Type definition object or name is null: " + typeDef.getTypeClass() ); + } final TypeDef previous = typeDefs.put( typeDef.getName(), typeDef ); if ( previous != null ) { LOG.debugf( "Duplicate typedef name [%s] now -> %s", typeDef.getName(), typeDef.getTypeClass() ); @@ -253,8 +309,7 @@ public class MetadataImpl implements MetadataImplementor, Serializable { @Override public SessionFactory buildSessionFactory() { - // todo : implement!!!! - return null; + return sessionFactoryBuilder.buildSessionFactory(); } @Override @@ -271,6 +326,28 @@ public class MetadataImpl implements MetadataImplementor, Serializable { return entityBindingMap.get( entityName ); } + @Override + public EntityBinding getRootEntityBinding(String entityName) { + EntityBinding rootEntityBinding = rootEntityBindingMap.get( entityName ); + if ( rootEntityBinding == null ) { + EntityBinding entityBinding = entityBindingMap.get( entityName ); + if ( entityBinding == null ) { + throw new IllegalStateException( "Unknown entity binding: " + entityName ); + } + if ( entityBinding.isRoot() ) { + rootEntityBinding = entityBinding; + } + else { + if ( entityBinding.getEntity().getSuperType() == null ) { + throw new IllegalStateException( "Entity binding has no root: " + entityName ); + } + rootEntityBinding = getRootEntityBinding( entityBinding.getEntity().getSuperType().getName() ); + } + rootEntityBindingMap.put( entityName, rootEntityBinding ); + } + return rootEntityBinding; + } + public Iterable getEntityBindings() { return entityBindingMap.values(); } @@ -287,7 +364,8 @@ public class MetadataImpl implements MetadataImplementor, Serializable { return collectionBindingMap.get( collectionRole ); } - public Iterable getCollections() { + @Override + public Iterable getCollectionBindings() { return collectionBindingMap.values(); } @@ -302,8 +380,8 @@ public class MetadataImpl implements MetadataImplementor, Serializable { } public void addImport(String importName, String entityName) { - if ( imports == null ) { - imports = new HashMap(); + if ( importName == null || entityName == null ) { + throw new IllegalArgumentException( "Import name or entity name is null" ); } LOG.trace( "Import: " + importName + " -> " + entityName ); String old = imports.put( importName, entityName ); @@ -312,6 +390,10 @@ public class MetadataImpl implements MetadataImplementor, Serializable { } } + public Iterable> getImports() { + return imports.entrySet(); + } + public Iterable getFetchProfiles() { return fetchProfiles.values(); } @@ -320,6 +402,11 @@ public class MetadataImpl implements MetadataImplementor, Serializable { return typeResolver; } + @Override + public SessionFactoryBuilder getSessionFactoryBuilder() { + return sessionFactoryBuilder; + } + @Override public NamingStrategy getNamingStrategy() { return options.getNamingStrategy(); @@ -347,6 +434,48 @@ public class MetadataImpl implements MetadataImplementor, Serializable { private static final String DEFAULT_CASCADE = "none"; private static final String DEFAULT_PROPERTY_ACCESS = "property"; + @Override + public IdentifierGeneratorFactory getIdentifierGeneratorFactory() { + return identifierGeneratorFactory; + } + + @Override + public Type getIdentifierType(String entityName) throws MappingException { + EntityBinding entityBinding = getEntityBinding( entityName ); + if ( entityBinding == null ) { + throw new MappingException( "Entity binding not known: " + entityName ); + } + return entityBinding + .getEntityIdentifier() + .getValueBinding() + .getHibernateTypeDescriptor() + .getExplicitType(); + } + + @Override + public String getIdentifierPropertyName(String entityName) throws MappingException { + EntityBinding entityBinding = getEntityBinding( entityName ); + if ( entityBinding == null ) { + throw new MappingException( "Entity binding not known: " + entityName ); + } + AttributeBinding idBinding = entityBinding.getEntityIdentifier().getValueBinding(); + return idBinding == null ? null : idBinding.getAttribute().getName(); + } + + @Override + public Type getReferencedPropertyType(String entityName, String propertyName) throws MappingException { + EntityBinding entityBinding = getEntityBinding( entityName ); + if ( entityBinding == null ) { + throw new MappingException( "Entity binding not known: " + entityName ); + } + // TODO: should this call EntityBinding.getReferencedAttributeBindingString), which does not exist yet? + AttributeBinding attributeBinding = entityBinding.getAttributeBinding( propertyName ); + if ( attributeBinding == null ) { + throw new MappingException( "unknown property: " + entityName + '.' + propertyName ); + } + return attributeBinding.getHibernateTypeDescriptor().getExplicitType(); + } + private class MappingDefaultsImpl implements MappingDefaults { @Override diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/source/internal/SessionFactoryBuilderImpl.java b/hibernate-core/src/main/java/org/hibernate/metamodel/source/internal/SessionFactoryBuilderImpl.java new file mode 100644 index 0000000000..c3ec4978eb --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/source/internal/SessionFactoryBuilderImpl.java @@ -0,0 +1,88 @@ +/* + * 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.metamodel.source.internal; + +import java.io.Serializable; + +import org.hibernate.EmptyInterceptor; +import org.hibernate.Interceptor; +import org.hibernate.ObjectNotFoundException; +import org.hibernate.SessionFactory; +import org.hibernate.internal.SessionFactoryImpl; +import org.hibernate.metamodel.SessionFactoryBuilder; +import org.hibernate.metamodel.source.spi.MetadataImplementor; +import org.hibernate.proxy.EntityNotFoundDelegate; + +/** + * @author Gail Badner + */ +public class SessionFactoryBuilderImpl implements SessionFactoryBuilder { + SessionFactoryOptionsImpl options; + + private final MetadataImplementor metadata; + + /* package-protected */ + SessionFactoryBuilderImpl(MetadataImplementor metadata) { + this.metadata = metadata; + options = new SessionFactoryOptionsImpl(); + } + + @Override + public SessionFactoryBuilder with(Interceptor interceptor) { + this.options.interceptor = interceptor; + return this; + } + + @Override + public SessionFactoryBuilder with(EntityNotFoundDelegate entityNotFoundDelegate) { + this.options.entityNotFoundDelegate = entityNotFoundDelegate; + return this; + } + + @Override + public SessionFactory buildSessionFactory() { + return new SessionFactoryImpl(metadata, options, null ); + } + + private static class SessionFactoryOptionsImpl implements SessionFactory.SessionFactoryOptions { + private Interceptor interceptor = EmptyInterceptor.INSTANCE; + + // TODO: should there be a DefaultEntityNotFoundDelegate.INSTANCE? + private EntityNotFoundDelegate entityNotFoundDelegate = new EntityNotFoundDelegate() { + public void handleEntityNotFound(String entityName, Serializable id) { + throw new ObjectNotFoundException( id, entityName ); + } + }; + + @Override + public Interceptor getInterceptor() { + return interceptor; + } + + @Override + public EntityNotFoundDelegate getEntityNotFoundDelegate() { + return entityNotFoundDelegate; + } + } +} \ No newline at end of file diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/source/spi/MetadataImplementor.java b/hibernate-core/src/main/java/org/hibernate/metamodel/source/spi/MetadataImplementor.java index 8afd249da7..0ab0f2619e 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/source/spi/MetadataImplementor.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/source/spi/MetadataImplementor.java @@ -23,10 +23,13 @@ */ package org.hibernate.metamodel.source.spi; +import org.hibernate.engine.ResultSetMappingDefinition; import org.hibernate.engine.spi.FilterDefinition; +import org.hibernate.engine.spi.Mapping; import org.hibernate.engine.spi.NamedQueryDefinition; import org.hibernate.engine.spi.NamedSQLQueryDefinition; import org.hibernate.metamodel.Metadata; +import org.hibernate.metamodel.SessionFactoryBuilder; import org.hibernate.metamodel.binding.EntityBinding; import org.hibernate.metamodel.binding.FetchProfile; import org.hibernate.metamodel.binding.IdGenerator; @@ -40,7 +43,7 @@ import org.hibernate.type.TypeResolver; /** * @author Steve Ebersole */ -public interface MetadataImplementor extends Metadata, BindingContext { +public interface MetadataImplementor extends Metadata, BindingContext, Mapping { public BasicServiceRegistry getServiceRegistry(); public Database getDatabase(); @@ -63,9 +66,11 @@ public interface MetadataImplementor extends Metadata, BindingContext { public void registerIdentifierGenerator(String name, String clazz); - public void addNamedNativeQuery(String name, NamedSQLQueryDefinition def); + public void addNamedNativeQuery(NamedSQLQueryDefinition def); - public void addNamedQuery(String name, NamedQueryDefinition def); + public void addNamedQuery(NamedQueryDefinition def); + + public void addResultSetMapping(ResultSetMappingDefinition resultSetMappingDefinition); public void addAuxiliaryDatabaseObject(AuxiliaryDatabaseObject auxiliaryDatabaseObject); } 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 a02bada59e..82f6c457f0 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 @@ -92,6 +92,7 @@ import org.hibernate.mapping.PersistentClass; import org.hibernate.mapping.Property; import org.hibernate.mapping.Selectable; import org.hibernate.metadata.ClassMetadata; +import org.hibernate.metamodel.binding.EntityBinding; import org.hibernate.pretty.MessageHelper; import org.hibernate.property.BackrefPropertyAccessor; import org.hibernate.sql.Alias; @@ -754,6 +755,75 @@ public abstract class AbstractEntityPersister temporaryIdTableDDL = persistentClass.getTemporaryIdTableDDL(); } + + public AbstractEntityPersister( + final EntityBinding entityBinding, + final EntityRegionAccessStrategy cacheAccessStrategy, + final SessionFactoryImplementor factory) throws HibernateException { + // TODO: Implement! Initializing final fields to make compiler happy + this.factory = factory; + this.cacheAccessStrategy = cacheAccessStrategy; + isLazyPropertiesCacheable = false; + cacheEntryStructure = null; + entityMetamodel = null; + rootTableKeyColumnNames = null; + rootTableKeyColumnReaders = null; + rootTableKeyColumnReaderTemplates = null; + identifierAliases = null; + identifierColumnSpan = -1; + versionColumnName = null; + hasFormulaProperties = false; + batchSize = -1; + hasSubselectLoadableCollections = false; + rowIdName = null; + lazyProperties = null; + sqlWhereString = null; + sqlWhereStringTemplate = null; + propertyColumnSpans = null; + propertySubclassNames = null; + propertyColumnAliases = null; + propertyColumnNames = null; + propertyColumnFormulaTemplates = null; + propertyColumnReaderTemplates = null; + propertyColumnWriters = null; + propertyColumnUpdateable = null; + propertyColumnInsertable = null; + propertyUniqueness = null; + propertySelectable = null; + lazyPropertyNames = null; + lazyPropertyNumbers = null; + lazyPropertyTypes = null; + lazyPropertyColumnAliases = null; + subclassPropertyNameClosure = null; + subclassPropertySubclassNameClosure = null; + subclassPropertyTypeClosure = null; + subclassPropertyFormulaTemplateClosure = null; + subclassPropertyColumnNameClosure = null; + subclassPropertyColumnReaderClosure = null; + subclassPropertyColumnReaderTemplateClosure = null; + subclassPropertyFetchModeClosure = null; + subclassPropertyNullabilityClosure = null; + propertyDefinedOnSubclass = null; + subclassPropertyColumnNumberClosure = null; + subclassPropertyFormulaNumberClosure = null; + subclassPropertyCascadeStyleClosure = null; + subclassColumnClosure = null; + subclassColumnLazyClosure = null; + subclassColumnAliasClosure = null; + subclassColumnSelectableClosure = null; + subclassColumnReaderTemplateClosure = null; + subclassFormulaClosure = null; + subclassFormulaTemplateClosure = null; + subclassFormulaAliasClosure = null; + subclassFormulaLazyClosure = null; + filterHelper = null; + loaderName = null; + queryLoader = null; + temporaryIdTableName = null; + temporaryIdTableDDL = null; + propertyMapping = null; + } + protected String generateLazySelectString() { if ( !entityMetamodel.hasLazyProperties() ) { diff --git a/hibernate-core/src/main/java/org/hibernate/persister/entity/JoinedSubclassEntityPersister.java b/hibernate-core/src/main/java/org/hibernate/persister/entity/JoinedSubclassEntityPersister.java index 17793e33bc..9b367a5cf4 100644 --- a/hibernate-core/src/main/java/org/hibernate/persister/entity/JoinedSubclassEntityPersister.java +++ b/hibernate-core/src/main/java/org/hibernate/persister/entity/JoinedSubclassEntityPersister.java @@ -47,6 +47,7 @@ import org.hibernate.mapping.Property; import org.hibernate.mapping.Selectable; import org.hibernate.mapping.Subclass; import org.hibernate.mapping.Table; +import org.hibernate.metamodel.binding.EntityBinding; import org.hibernate.sql.CaseFragment; import org.hibernate.sql.SelectFragment; import org.hibernate.type.StandardBasicTypes; @@ -492,6 +493,43 @@ public class JoinedSubclassEntityPersister extends AbstractEntityPersister { } + public JoinedSubclassEntityPersister( + final EntityBinding entityBinding, + final EntityRegionAccessStrategy cacheAccessStrategy, + final SessionFactoryImplementor factory, + final Mapping mapping) throws HibernateException { + super( entityBinding, cacheAccessStrategy, factory ); + // TODO: implement!!! initializing final fields to null to make compiler happy + tableSpan = -1; + tableNames = null; + naturalOrderTableNames = null; + tableKeyColumns = null; + tableKeyColumnReaders = null; + tableKeyColumnReaderTemplates = null; + naturalOrderTableKeyColumns = null; + naturalOrderTableKeyColumnReaders = null; + naturalOrderTableKeyColumnReaderTemplates = null; + naturalOrderCascadeDeleteEnabled = null; + spaces = null; + subclassClosure = null; + subclassTableNameClosure = null; + subclassTableKeyColumnClosure= null; + isClassOrSuperclassTable = null; + naturalOrderPropertyTableNumbers = null; + propertyTableNumbers = null; + subclassPropertyTableNumberClosure = null; + subclassColumnTableNumberClosure = null; + subclassFormulaTableNumberClosure = null; + subclassTableSequentialSelect = null; + subclassTableIsLazyClosure = null; + discriminatorValues = null; + notNullColumnNames = null; + notNullColumnTableNumbers = null; + constraintOrderedTableNames = null; + constraintOrderedKeyColumnNames = null; + discriminatorSQLString = null; + } + protected boolean isSubclassTableSequentialSelect(int j) { return subclassTableSequentialSelect[j] && !isClassOrSuperclassTable[j]; } diff --git a/hibernate-core/src/main/java/org/hibernate/persister/entity/SingleTableEntityPersister.java b/hibernate-core/src/main/java/org/hibernate/persister/entity/SingleTableEntityPersister.java index fc6501a6b7..8585b5d718 100644 --- a/hibernate-core/src/main/java/org/hibernate/persister/entity/SingleTableEntityPersister.java +++ b/hibernate-core/src/main/java/org/hibernate/persister/entity/SingleTableEntityPersister.java @@ -47,6 +47,7 @@ import org.hibernate.mapping.Selectable; import org.hibernate.mapping.Subclass; import org.hibernate.mapping.Table; import org.hibernate.mapping.Value; +import org.hibernate.metamodel.binding.EntityBinding; import org.hibernate.sql.InFragment; import org.hibernate.sql.Insert; import org.hibernate.sql.SelectFragment; @@ -438,6 +439,49 @@ public class SingleTableEntityPersister extends AbstractEntityPersister { } + public SingleTableEntityPersister( + final EntityBinding entityBinding, + final EntityRegionAccessStrategy cacheAccessStrategy, + final SessionFactoryImplementor factory, + final Mapping mapping) throws HibernateException { + + super( entityBinding, cacheAccessStrategy, factory ); + + //TODO: implement!!!! initializing final fields to make compiler happy... + joinSpan = -1; + qualifiedTableNames = null; + isInverseTable = null; + isNullableTable = null; + keyColumnNames = null; + cascadeDeleteEnabled = null; + hasSequentialSelects = false; + spaces = null; + subclassClosure = null; + subclassTableNameClosure = null; + subclassTableIsLazyClosure = null; + isInverseSubclassTable = null; + isNullableSubclassTable = null; + subclassTableSequentialSelect = null; + subclassTableKeyColumnClosure = null; + isClassOrSuperclassTable = null; + propertyTableNumbers = null; + subclassPropertyTableNumberClosure = null; + subclassColumnTableNumberClosure = null; + subclassFormulaTableNumberClosure = null; + forceDiscriminator = false; + discriminatorColumnName = null; + discriminatorColumnReaders = null; + discriminatorColumnReaderTemplate = null; + discriminatorFormula = null; + discriminatorFormulaTemplate = null; + discriminatorAlias = null; + discriminatorType = null; + discriminatorSQLValue = null; + discriminatorInsertable = false; + constraintOrderedTableNames = null; + constraintOrderedKeyColumnNames = null; + } + protected boolean isInverseTable(int j) { return isInverseTable[j]; } diff --git a/hibernate-core/src/main/java/org/hibernate/persister/entity/UnionSubclassEntityPersister.java b/hibernate-core/src/main/java/org/hibernate/persister/entity/UnionSubclassEntityPersister.java index b041286f0a..d9347ddcf4 100644 --- a/hibernate-core/src/main/java/org/hibernate/persister/entity/UnionSubclassEntityPersister.java +++ b/hibernate-core/src/main/java/org/hibernate/persister/entity/UnionSubclassEntityPersister.java @@ -49,6 +49,7 @@ import org.hibernate.mapping.Column; import org.hibernate.mapping.PersistentClass; import org.hibernate.mapping.Subclass; import org.hibernate.mapping.Table; +import org.hibernate.metamodel.binding.EntityBinding; import org.hibernate.sql.SelectFragment; import org.hibernate.sql.SimpleSelect; import org.hibernate.type.StandardBasicTypes; @@ -235,6 +236,23 @@ public class UnionSubclassEntityPersister extends AbstractEntityPersister { } + public UnionSubclassEntityPersister( + final EntityBinding entityBinding, + final EntityRegionAccessStrategy cacheAccessStrategy, + final SessionFactoryImplementor factory, + final Mapping mapping) throws HibernateException { + super(entityBinding, cacheAccessStrategy, factory ); + // TODO: implement!!! initializing final fields to null to make compiler happy. + subquery = null; + tableName = null; + subclassClosure = null; + spaces = null; + subclassSpaces = null; + discriminatorSQLValue = null; + constraintOrderedTableNames = null; + constraintOrderedKeyColumnNames = null; + } + public Serializable[] getQuerySpaces() { return subclassSpaces; } diff --git a/hibernate-core/src/main/java/org/hibernate/persister/internal/PersisterFactoryImpl.java b/hibernate-core/src/main/java/org/hibernate/persister/internal/PersisterFactoryImpl.java index 271c78856c..fd81d4962b 100644 --- a/hibernate-core/src/main/java/org/hibernate/persister/internal/PersisterFactoryImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/persister/internal/PersisterFactoryImpl.java @@ -34,6 +34,7 @@ import org.hibernate.mapping.Collection; import org.hibernate.mapping.PersistentClass; import org.hibernate.metamodel.binding.EntityBinding; import org.hibernate.metamodel.binding.PluralAttributeBinding; +import org.hibernate.metamodel.source.spi.MetadataImplementor; import org.hibernate.persister.collection.CollectionPersister; import org.hibernate.persister.entity.EntityPersister; import org.hibernate.persister.spi.PersisterClassResolver; @@ -104,7 +105,7 @@ public final class PersisterFactoryImpl implements PersisterFactory, ServiceRegi private static final Class[] COLLECTION_PERSISTER_CONSTRUCTOR_ARGS_NEW = new Class[] { PluralAttributeBinding.class, CollectionRegionAccessStrategy.class, - Configuration.class, + MetadataImplementor.class, SessionFactoryImplementor.class }; @@ -183,44 +184,44 @@ public final class PersisterFactoryImpl implements PersisterFactory, ServiceRegi @SuppressWarnings( {"unchecked"}) public CollectionPersister createCollectionPersister( Configuration cfg, - Collection metadata, + Collection collectionMetadata, CollectionRegionAccessStrategy cacheAccessStrategy, SessionFactoryImplementor factory) throws HibernateException { - Class persisterClass = metadata.getCollectionPersisterClass(); + Class persisterClass = collectionMetadata.getCollectionPersisterClass(); if ( persisterClass == null ) { - persisterClass = serviceRegistry.getService( PersisterClassResolver.class ).getCollectionPersisterClass( metadata ); + persisterClass = serviceRegistry.getService( PersisterClassResolver.class ).getCollectionPersisterClass( collectionMetadata ); } - return create( persisterClass, COLLECTION_PERSISTER_CONSTRUCTOR_ARGS, cfg, metadata, cacheAccessStrategy, factory ); + return create( persisterClass, COLLECTION_PERSISTER_CONSTRUCTOR_ARGS, cfg, collectionMetadata, cacheAccessStrategy, factory ); } @Override @SuppressWarnings( {"unchecked"}) - - public CollectionPersister createCollectionPersister(Configuration cfg, - PluralAttributeBinding metadata, + public CollectionPersister createCollectionPersister(MetadataImplementor metadata, + PluralAttributeBinding collectionMetadata, CollectionRegionAccessStrategy cacheAccessStrategy, SessionFactoryImplementor factory) throws HibernateException { - Class persisterClass = metadata.getCollectionPersisterClass(); + Class persisterClass = collectionMetadata.getCollectionPersisterClass(); if ( persisterClass == null ) { - persisterClass = serviceRegistry.getService( PersisterClassResolver.class ).getCollectionPersisterClass( metadata ); + persisterClass = serviceRegistry.getService( PersisterClassResolver.class ).getCollectionPersisterClass( collectionMetadata ); } - return create( persisterClass, COLLECTION_PERSISTER_CONSTRUCTOR_ARGS_NEW, cfg, metadata, cacheAccessStrategy, factory ); + return create( persisterClass, COLLECTION_PERSISTER_CONSTRUCTOR_ARGS_NEW, metadata, collectionMetadata, cacheAccessStrategy, factory ); } - // TODO: change metadata arg type to PluralAttributeBinding when new metadata is integrated + // TODO: change collectionMetadata arg type to PluralAttributeBinding when new metadata is integrated + // TODO: change metadata arg type to MetadataImplementor when new metadata is integrated private static CollectionPersister create( Class persisterClass, Class[] persisterConstructorArgs, - Configuration cfg, - Object metadata, + Object cfg, + Object collectionMetadata, CollectionRegionAccessStrategy cacheAccessStrategy, SessionFactoryImplementor factory) throws HibernateException { try { Constructor constructor = persisterClass.getConstructor( persisterConstructorArgs ); try { - return constructor.newInstance( metadata, cacheAccessStrategy, cfg, factory ); + return constructor.newInstance( collectionMetadata, cacheAccessStrategy, cfg, factory ); } catch (MappingException e) { throw e; diff --git a/hibernate-core/src/main/java/org/hibernate/persister/internal/StandardPersisterClassResolver.java b/hibernate-core/src/main/java/org/hibernate/persister/internal/StandardPersisterClassResolver.java index 9c6ab9b647..e67fa86a1f 100644 --- a/hibernate-core/src/main/java/org/hibernate/persister/internal/StandardPersisterClassResolver.java +++ b/hibernate-core/src/main/java/org/hibernate/persister/internal/StandardPersisterClassResolver.java @@ -47,9 +47,13 @@ public class StandardPersisterClassResolver implements PersisterClassResolver { public Class getEntityPersisterClass(EntityBinding metadata) { // todo : make sure this is based on an attribute kept on the metamodel in the new code, not the concrete PersistentClass impl found! + + if ( metadata.isRoot() ) { + return singleTableEntityPersister(); // EARLY RETURN! + } switch ( metadata.getInheritanceType() ) { case JOINED: { - joinedSubclassEntityPersister(); + return joinedSubclassEntityPersister(); } case SINGLE_TABLE: { return singleTableEntityPersister(); diff --git a/hibernate-core/src/main/java/org/hibernate/persister/spi/PersisterFactory.java b/hibernate-core/src/main/java/org/hibernate/persister/spi/PersisterFactory.java index b8cf709380..7cc75f8c32 100644 --- a/hibernate-core/src/main/java/org/hibernate/persister/spi/PersisterFactory.java +++ b/hibernate-core/src/main/java/org/hibernate/persister/spi/PersisterFactory.java @@ -33,6 +33,7 @@ import org.hibernate.mapping.Collection; import org.hibernate.mapping.PersistentClass; import org.hibernate.metamodel.binding.EntityBinding; import org.hibernate.metamodel.binding.PluralAttributeBinding; +import org.hibernate.metamodel.source.spi.MetadataImplementor; import org.hibernate.persister.collection.CollectionPersister; import org.hibernate.persister.entity.EntityPersister; import org.hibernate.service.Service; @@ -110,7 +111,7 @@ public interface PersisterFactory extends Service { /** * Create a collection persister instance. * - * @param cfg The configuration + * @param metadata The metadata * @param model The O/R mapping metamodel definition for the collection * @param cacheAccessStrategy The caching strategy for this collection * @param factory The session factory @@ -120,7 +121,7 @@ public interface PersisterFactory extends Service { * @throws HibernateException Indicates a problem building the persister. */ public CollectionPersister createCollectionPersister( - Configuration cfg, + MetadataImplementor metadata, PluralAttributeBinding model, CollectionRegionAccessStrategy cacheAccessStrategy, SessionFactoryImplementor factory) throws HibernateException; diff --git a/hibernate-core/src/test/java/org/hibernate/metamodel/binding/AbstractBasicBindingTests.java b/hibernate-core/src/test/java/org/hibernate/metamodel/binding/AbstractBasicBindingTests.java index 3754334ed6..6e54be196b 100644 --- a/hibernate-core/src/test/java/org/hibernate/metamodel/binding/AbstractBasicBindingTests.java +++ b/hibernate-core/src/test/java/org/hibernate/metamodel/binding/AbstractBasicBindingTests.java @@ -33,6 +33,7 @@ import org.junit.Test; import org.hibernate.metamodel.MetadataSources; import org.hibernate.metamodel.relational.Column; import org.hibernate.metamodel.source.internal.MetadataImpl; +import org.hibernate.metamodel.source.spi.MetadataImplementor; import org.hibernate.service.BasicServiceRegistry; import org.hibernate.service.ServiceRegistryBuilder; import org.hibernate.service.internal.BasicServiceRegistryImpl; @@ -74,6 +75,7 @@ public abstract class AbstractBasicBindingTests extends BaseUnitTestCase { public void testSimpleEntityMapping() { MetadataImpl metadata = addSourcesForSimpleEntityBinding( sources ); EntityBinding entityBinding = metadata.getEntityBinding( SimpleEntity.class.getName() ); + assertRoot( metadata, entityBinding ); assertIdAndSimpleProperty( entityBinding ); assertNull( entityBinding.getVersioningValueBinding() ); @@ -123,7 +125,6 @@ public abstract class AbstractBasicBindingTests extends BaseUnitTestCase { assertNotNull( entityBinding ); assertNotNull( entityBinding.getEntityIdentifier() ); assertNotNull( entityBinding.getEntityIdentifier().getValueBinding() ); - assertTrue( entityBinding.isRoot() ); AttributeBinding idAttributeBinding = entityBinding.getAttributeBinding( "id" ); assertNotNull( idAttributeBinding ); @@ -137,4 +138,9 @@ public abstract class AbstractBasicBindingTests extends BaseUnitTestCase { assertNotNull( nameBinding.getAttribute() ); assertNotNull( nameBinding.getValue() ); } + + protected void assertRoot(MetadataImplementor metadata, EntityBinding entityBinding) { + assertTrue( entityBinding.isRoot() ); + assertSame( entityBinding, metadata.getRootEntityBinding( entityBinding.getEntity().getName() ) ); + } } diff --git a/hibernate-core/src/test/java/org/hibernate/metamodel/source/annotations/entity/BaseAnnotationBindingTestCase.java b/hibernate-core/src/test/java/org/hibernate/metamodel/source/annotations/entity/BaseAnnotationBindingTestCase.java index 6ff3fc50c6..787968c82f 100644 --- a/hibernate-core/src/test/java/org/hibernate/metamodel/source/annotations/entity/BaseAnnotationBindingTestCase.java +++ b/hibernate-core/src/test/java/org/hibernate/metamodel/source/annotations/entity/BaseAnnotationBindingTestCase.java @@ -57,6 +57,14 @@ public abstract class BaseAnnotationBindingTestCase extends BaseUnitTestCase { } return meta.getEntityBinding( clazz.getName() ); } + + public EntityBinding getRootEntityBinding(Class clazz) { + if ( meta == null ) { + meta = (MetadataImpl) sources.buildMetadata(); + } + return meta.getRootEntityBinding( clazz.getName() ); + } + } diff --git a/hibernate-core/src/test/java/org/hibernate/metamodel/source/annotations/entity/InheritanceTypeTest.java b/hibernate-core/src/test/java/org/hibernate/metamodel/source/annotations/entity/InheritanceTypeTest.java index cf914916aa..9fc6b785ea 100644 --- a/hibernate-core/src/test/java/org/hibernate/metamodel/source/annotations/entity/InheritanceTypeTest.java +++ b/hibernate-core/src/test/java/org/hibernate/metamodel/source/annotations/entity/InheritanceTypeTest.java @@ -34,6 +34,7 @@ import org.hibernate.metamodel.binding.EntityBinding; import static junit.framework.Assert.assertEquals; import static junit.framework.Assert.assertFalse; import static junit.framework.Assert.assertNull; +import static junit.framework.Assert.assertSame; import static junit.framework.Assert.assertTrue; /** @@ -44,7 +45,6 @@ public class InheritanceTypeTest extends BaseAnnotationBindingTestCase { public void testNoInheritance() { buildMetadataSources( SingleEntity.class ); EntityBinding entityBinding = getEntityBinding( SingleEntity.class ); - assertTrue( entityBinding.isRoot() ); assertNull( entityBinding.getEntityDiscriminator() ); } @@ -54,10 +54,29 @@ public class InheritanceTypeTest extends BaseAnnotationBindingTestCase { RootOfSingleTableInheritance.class, SubclassOfSingleTableInheritance.class ); EntityBinding entityBinding = getEntityBinding( SubclassOfSingleTableInheritance.class ); - assertFalse( entityBinding.isRoot() ); assertEquals( "Wrong discriminator value", "foo", entityBinding.getDiscriminatorValue() ); } + @Test + public void testRootEntityBinding() { + buildMetadataSources( + SubclassOfSingleTableInheritance.class, SingleEntity.class, RootOfSingleTableInheritance.class + ); + + EntityBinding noInheritanceEntityBinding = getEntityBinding( SingleEntity.class ); + EntityBinding subclassEntityBinding = getEntityBinding( SubclassOfSingleTableInheritance.class ); + EntityBinding rootEntityBinding = getEntityBinding( RootOfSingleTableInheritance.class ); + + assertTrue( noInheritanceEntityBinding.isRoot() ); + assertSame( noInheritanceEntityBinding, getRootEntityBinding( SingleEntity.class ) ); + + assertFalse( subclassEntityBinding.isRoot() ); + assertSame( rootEntityBinding, getRootEntityBinding( SubclassOfSingleTableInheritance.class ) ); + + assertTrue( rootEntityBinding.isRoot() ); + assertSame( rootEntityBinding, getRootEntityBinding( RootOfSingleTableInheritance.class )); + } + @Entity class SingleEntity { @Id diff --git a/hibernate-core/src/test/java/org/hibernate/metamodel/source/internal/MetadataImplTest.java b/hibernate-core/src/test/java/org/hibernate/metamodel/source/internal/MetadataImplTest.java index 607e295299..dd35e2836d 100644 --- a/hibernate-core/src/test/java/org/hibernate/metamodel/source/internal/MetadataImplTest.java +++ b/hibernate-core/src/test/java/org/hibernate/metamodel/source/internal/MetadataImplTest.java @@ -27,14 +27,21 @@ import java.util.Iterator; import org.junit.Test; +import org.hibernate.EmptyInterceptor; import org.hibernate.HibernateException; +import org.hibernate.SessionFactory; +import org.hibernate.metamodel.Metadata; import org.hibernate.metamodel.MetadataSources; +import org.hibernate.metamodel.SessionFactoryBuilder; import org.hibernate.metamodel.binding.FetchProfile; +import org.hibernate.proxy.EntityNotFoundDelegate; import org.hibernate.service.ServiceRegistryBuilder; import org.hibernate.testing.junit4.BaseUnitTestCase; import static junit.framework.Assert.assertEquals; import static junit.framework.Assert.assertFalse; +import static junit.framework.Assert.assertNotNull; +import static junit.framework.Assert.assertSame; import static junit.framework.Assert.assertTrue; /** @@ -81,6 +88,19 @@ public class MetadataImplTest extends BaseUnitTestCase { assertFetchProfile( metadata ); } + @Test + public void testGettingSessionFactoryBuilder() { + MetadataSources sources = new MetadataSources( new ServiceRegistryBuilder().buildServiceRegistry() ); + Metadata metadata = sources.buildMetadata(); + + SessionFactoryBuilder sessionFactoryBuilder = metadata.getSessionFactoryBuilder(); + assertNotNull( sessionFactoryBuilder ); + assertTrue( SessionFactoryBuilderImpl.class.isInstance( sessionFactoryBuilder ) ); + + SessionFactory sessionFactory = metadata.buildSessionFactory(); + assertNotNull( sessionFactory ); + } + private void assertFetchProfile(MetadataImpl metadata) { Iterator profiles = metadata.getFetchProfiles().iterator(); assertTrue( profiles.hasNext() ); diff --git a/hibernate-core/src/test/java/org/hibernate/metamodel/source/internal/SessionFactoryBuilderImplTest.java b/hibernate-core/src/test/java/org/hibernate/metamodel/source/internal/SessionFactoryBuilderImplTest.java new file mode 100644 index 0000000000..75c5ec0ef1 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/metamodel/source/internal/SessionFactoryBuilderImplTest.java @@ -0,0 +1,195 @@ +/* + * 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.metamodel.source.internal; + +import java.io.Serializable; +import java.util.Iterator; + +import org.junit.Test; + +import org.hibernate.CallbackException; +import org.hibernate.EmptyInterceptor; +import org.hibernate.EntityMode; +import org.hibernate.Interceptor; +import org.hibernate.ObjectNotFoundException; +import org.hibernate.SessionFactory; +import org.hibernate.Transaction; +import org.hibernate.metamodel.MetadataSources; +import org.hibernate.metamodel.SessionFactoryBuilder; +import org.hibernate.proxy.EntityNotFoundDelegate; +import org.hibernate.service.ServiceRegistryBuilder; +import org.hibernate.testing.junit4.BaseUnitTestCase; +import org.hibernate.type.Type; + +import static junit.framework.Assert.assertNotNull; +import static junit.framework.Assert.assertSame; +import static junit.framework.Assert.assertTrue; + +/** + * @author Gail Badner + */ +public class SessionFactoryBuilderImplTest extends BaseUnitTestCase { + + @Test + public void testGettingSessionFactoryBuilder() { + SessionFactoryBuilder sessionFactoryBuilder = getSessionFactoryBuilder(); + assertNotNull( sessionFactoryBuilder ); + assertTrue( SessionFactoryBuilderImpl.class.isInstance( sessionFactoryBuilder ) ); + } + + @Test + public void testBuildSessionFactoryWithDefaultOptions() { + SessionFactoryBuilder sessionFactoryBuilder = getSessionFactoryBuilder(); + SessionFactory sessionFactory = sessionFactoryBuilder.buildSessionFactory(); + assertSame( EmptyInterceptor.INSTANCE, sessionFactory.getSessionFactoryOptions().getInterceptor() ); + assertTrue( EntityNotFoundDelegate.class.isInstance( + sessionFactory.getSessionFactoryOptions().getEntityNotFoundDelegate() + ) ); + } + + @Test + public void testBuildSessionFactoryWithUpdatedOptions() { + SessionFactoryBuilder sessionFactoryBuilder = getSessionFactoryBuilder(); + Interceptor interceptor = new AnInterceptor(); + EntityNotFoundDelegate entityNotFoundDelegate = new EntityNotFoundDelegate() { + @Override + public void handleEntityNotFound(String entityName, Serializable id) { + throw new ObjectNotFoundException( id, entityName ); + } + }; + sessionFactoryBuilder.with( interceptor ); + sessionFactoryBuilder.with( entityNotFoundDelegate ); + SessionFactory sessionFactory = sessionFactoryBuilder.buildSessionFactory(); + assertSame( interceptor, sessionFactory.getSessionFactoryOptions().getInterceptor() ); + assertSame( entityNotFoundDelegate, sessionFactory.getSessionFactoryOptions().getEntityNotFoundDelegate() ); + } + + private SessionFactoryBuilder getSessionFactoryBuilder() { + MetadataSources sources = new MetadataSources( new ServiceRegistryBuilder().buildServiceRegistry() ); + sources.addAnnotatedClass( SimpleEntity.class ); + MetadataImpl metadata = (MetadataImpl) sources.buildMetadata(); + return metadata.getSessionFactoryBuilder(); + } + + private static class AnInterceptor implements Interceptor { + private static final Interceptor INSTANCE = EmptyInterceptor.INSTANCE; + + @Override + public boolean onLoad(Object entity, Serializable id, Object[] state, String[] propertyNames, Type[] types) + throws CallbackException { + return INSTANCE.onLoad( entity, id, state, propertyNames, types ); + } + + @Override + public boolean onFlushDirty(Object entity, Serializable id, Object[] currentState, Object[] previousState, String[] propertyNames, Type[] types) + throws CallbackException { + return INSTANCE.onFlushDirty( entity, id, currentState, previousState, propertyNames, types ); + } + + @Override + public boolean onSave(Object entity, Serializable id, Object[] state, String[] propertyNames, Type[] types) + throws CallbackException { + return INSTANCE.onSave( entity, id, state, propertyNames, types ); + } + + @Override + public void onDelete(Object entity, Serializable id, Object[] state, String[] propertyNames, Type[] types) + throws CallbackException { + INSTANCE.onDelete( entity, id, state, propertyNames, types ); + } + + @Override + public void onCollectionRecreate(Object collection, Serializable key) throws CallbackException { + INSTANCE.onCollectionRecreate( collection, key ); + } + + @Override + public void onCollectionRemove(Object collection, Serializable key) throws CallbackException { + INSTANCE.onCollectionRemove( collection, key ); + } + + @Override + public void onCollectionUpdate(Object collection, Serializable key) throws CallbackException { + INSTANCE.onCollectionUpdate( collection, key ); + } + + @Override + public void preFlush(Iterator entities) throws CallbackException { + INSTANCE.preFlush( entities ); + } + + @Override + public void postFlush(Iterator entities) throws CallbackException { + INSTANCE.postFlush( entities ); + } + + @Override + public Boolean isTransient(Object entity) { + return INSTANCE.isTransient( entity ); + } + + @Override + public int[] findDirty(Object entity, Serializable id, Object[] currentState, Object[] previousState, String[] propertyNames, Type[] types) { + return INSTANCE.findDirty( entity, id, currentState, previousState, propertyNames, types ); + } + + @Override + public Object instantiate(String entityName, EntityMode entityMode, Serializable id) + throws CallbackException { + return INSTANCE.instantiate( entityName, entityMode, id ); + } + + @Override + public String getEntityName(Object object) throws CallbackException { + return INSTANCE.getEntityName( object ); + } + + @Override + public Object getEntity(String entityName, Serializable id) throws CallbackException { + return INSTANCE.getEntity( entityName, id ); + } + + @Override + public void afterTransactionBegin(Transaction tx) { + INSTANCE.afterTransactionBegin( tx ); + } + + @Override + public void beforeTransactionCompletion(Transaction tx) { + INSTANCE.beforeTransactionCompletion( tx ); + } + + @Override + public void afterTransactionCompletion(Transaction tx) { + INSTANCE.afterTransactionCompletion( tx ); + } + + @Override + public String onPrepareStatement(String sql) { + return INSTANCE.onPrepareStatement( sql ); + } + } +} + + diff --git a/hibernate-core/src/test/java/org/hibernate/metamodel/source/internal/SimpleEntity.java b/hibernate-core/src/test/java/org/hibernate/metamodel/source/internal/SimpleEntity.java new file mode 100644 index 0000000000..c6f1c5c763 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/metamodel/source/internal/SimpleEntity.java @@ -0,0 +1,60 @@ +/* + * 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.metamodel.source.internal; + +import javax.persistence.Entity; +import javax.persistence.Id; + +/** + * @author Steve Ebersole + */ +@Entity +public class SimpleEntity { + @Id + private Long id; + private String name; + + public SimpleEntity() { + } + + public SimpleEntity(String name) { + this.name = name; + } + + 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; + } +}