0001: //$Id: SessionFactoryImpl.java 10863 2006-11-22 12:53:53Z steve.ebersole@jboss.com $
0002: package org.hibernate.impl;
0003:
0004: import java.io.IOException;
0005: import java.io.InvalidObjectException;
0006: import java.io.ObjectInputStream;
0007: import java.io.ObjectOutputStream;
0008: import java.io.ObjectStreamException;
0009: import java.io.Serializable;
0010: import java.sql.Connection;
0011: import java.util.ArrayList;
0012: import java.util.Collections;
0013: import java.util.HashMap;
0014: import java.util.HashSet;
0015: import java.util.Iterator;
0016: import java.util.Map;
0017: import java.util.Properties;
0018: import java.util.Set;
0019:
0020: import javax.naming.NamingException;
0021: import javax.naming.Reference;
0022: import javax.naming.StringRefAddr;
0023: import javax.transaction.TransactionManager;
0024:
0025: import org.apache.commons.logging.Log;
0026: import org.apache.commons.logging.LogFactory;
0027: import org.hibernate.AssertionFailure;
0028: import org.hibernate.ConnectionReleaseMode;
0029: import org.hibernate.EntityMode;
0030: import org.hibernate.HibernateException;
0031: import org.hibernate.Interceptor;
0032: import org.hibernate.MappingException;
0033: import org.hibernate.ObjectNotFoundException;
0034: import org.hibernate.QueryException;
0035: import org.hibernate.SessionFactory;
0036: import org.hibernate.StatelessSession;
0037: import org.hibernate.engine.query.sql.NativeSQLQuerySpecification;
0038: import org.hibernate.cache.Cache;
0039: import org.hibernate.cache.CacheConcurrencyStrategy;
0040: import org.hibernate.cache.CacheFactory;
0041: import org.hibernate.cache.CacheKey;
0042: import org.hibernate.cache.OptimisticCache;
0043: import org.hibernate.cache.QueryCache;
0044: import org.hibernate.cache.UpdateTimestampsCache;
0045: import org.hibernate.cfg.Configuration;
0046: import org.hibernate.cfg.Environment;
0047: import org.hibernate.cfg.Settings;
0048: import org.hibernate.connection.ConnectionProvider;
0049: import org.hibernate.context.CurrentSessionContext;
0050: import org.hibernate.context.JTASessionContext;
0051: import org.hibernate.context.ManagedSessionContext;
0052: import org.hibernate.context.ThreadLocalSessionContext;
0053: import org.hibernate.dialect.Dialect;
0054: import org.hibernate.dialect.function.SQLFunctionRegistry;
0055: import org.hibernate.engine.FilterDefinition;
0056: import org.hibernate.engine.Mapping;
0057: import org.hibernate.engine.NamedQueryDefinition;
0058: import org.hibernate.engine.NamedSQLQueryDefinition;
0059: import org.hibernate.engine.ResultSetMappingDefinition;
0060: import org.hibernate.engine.SessionFactoryImplementor;
0061: import org.hibernate.engine.query.QueryPlanCache;
0062: import org.hibernate.event.EventListeners;
0063: import org.hibernate.exception.SQLExceptionConverter;
0064: import org.hibernate.id.IdentifierGenerator;
0065: import org.hibernate.id.UUIDHexGenerator;
0066: import org.hibernate.jdbc.BatcherFactory;
0067: import org.hibernate.mapping.Collection;
0068: import org.hibernate.mapping.PersistentClass;
0069: import org.hibernate.mapping.RootClass;
0070: import org.hibernate.metadata.ClassMetadata;
0071: import org.hibernate.metadata.CollectionMetadata;
0072: import org.hibernate.persister.PersisterFactory;
0073: import org.hibernate.persister.collection.CollectionPersister;
0074: import org.hibernate.persister.entity.EntityPersister;
0075: import org.hibernate.persister.entity.Queryable;
0076: import org.hibernate.pretty.MessageHelper;
0077: import org.hibernate.proxy.EntityNotFoundDelegate;
0078: import org.hibernate.stat.Statistics;
0079: import org.hibernate.stat.StatisticsImpl;
0080: import org.hibernate.stat.StatisticsImplementor;
0081: import org.hibernate.tool.hbm2ddl.SchemaExport;
0082: import org.hibernate.tool.hbm2ddl.SchemaUpdate;
0083: import org.hibernate.tool.hbm2ddl.SchemaValidator;
0084: import org.hibernate.transaction.TransactionFactory;
0085: import org.hibernate.type.AssociationType;
0086: import org.hibernate.type.Type;
0087: import org.hibernate.util.CollectionHelper;
0088: import org.hibernate.util.ReflectHelper;
0089:
0090: /**
0091: * Concrete implementation of the <tt>SessionFactory</tt> interface. Has the following
0092: * responsibilites
0093: * <ul>
0094: * <li>caches configuration settings (immutably)
0095: * <li>caches "compiled" mappings ie. <tt>EntityPersister</tt>s and
0096: * <tt>CollectionPersister</tt>s (immutable)
0097: * <li>caches "compiled" queries (memory sensitive cache)
0098: * <li>manages <tt>PreparedStatement</tt>s
0099: * <li> delegates JDBC <tt>Connection</tt> management to the <tt>ConnectionProvider</tt>
0100: * <li>factory for instances of <tt>SessionImpl</tt>
0101: * </ul>
0102: * This class must appear immutable to clients, even if it does all kinds of caching
0103: * and pooling under the covers. It is crucial that the class is not only thread
0104: * safe, but also highly concurrent. Synchronization must be used extremely sparingly.
0105: *
0106: * @see org.hibernate.connection.ConnectionProvider
0107: * @see org.hibernate.classic.Session
0108: * @see org.hibernate.hql.QueryTranslator
0109: * @see org.hibernate.persister.entity.EntityPersister
0110: * @see org.hibernate.persister.collection.CollectionPersister
0111: * @author Gavin King
0112: */
0113: public final class SessionFactoryImpl implements SessionFactory,
0114: SessionFactoryImplementor {
0115:
0116: private final String name;
0117: private final String uuid;
0118:
0119: private final transient Map entityPersisters;
0120: private final transient Map classMetadata;
0121: private final transient Map collectionPersisters;
0122: private final transient Map collectionMetadata;
0123: private final transient Map collectionRolesByEntityParticipant;
0124: private final transient Map identifierGenerators;
0125: private final transient Map namedQueries;
0126: private final transient Map namedSqlQueries;
0127: private final transient Map sqlResultSetMappings;
0128: private final transient Map filters;
0129: private final transient Map imports;
0130: private final transient Interceptor interceptor;
0131: private final transient Settings settings;
0132: private final transient Properties properties;
0133: private transient SchemaExport schemaExport;
0134: private final transient TransactionManager transactionManager;
0135: private final transient QueryCache queryCache;
0136: private final transient UpdateTimestampsCache updateTimestampsCache;
0137: private final transient Map queryCaches;
0138: private final transient Map allCacheRegions = new HashMap();
0139: private final transient StatisticsImpl statistics = new StatisticsImpl(
0140: this );
0141: private final transient EventListeners eventListeners;
0142: private final transient CurrentSessionContext currentSessionContext;
0143: private final transient EntityNotFoundDelegate entityNotFoundDelegate;
0144: private final transient SQLFunctionRegistry sqlFunctionRegistry;
0145:
0146: private final QueryPlanCache queryPlanCache = new QueryPlanCache(
0147: this );
0148:
0149: private transient boolean isClosed = false;
0150:
0151: private static final IdentifierGenerator UUID_GENERATOR = new UUIDHexGenerator();
0152:
0153: private static final Log log = LogFactory
0154: .getLog(SessionFactoryImpl.class);
0155:
0156: public SessionFactoryImpl(Configuration cfg, Mapping mapping,
0157: Settings settings, EventListeners listeners)
0158: throws HibernateException {
0159:
0160: log.info("building session factory");
0161:
0162: this .properties = new Properties();
0163: this .properties.putAll(cfg.getProperties());
0164: this .interceptor = cfg.getInterceptor();
0165: this .settings = settings;
0166: this .sqlFunctionRegistry = new SQLFunctionRegistry(settings
0167: .getDialect(), cfg.getSqlFunctions());
0168: this .eventListeners = listeners;
0169: this .filters = new HashMap();
0170: this .filters.putAll(cfg.getFilterDefinitions());
0171:
0172: if (log.isDebugEnabled()) {
0173: log
0174: .debug("Session factory constructed with filter configurations : "
0175: + filters);
0176: }
0177:
0178: if (log.isDebugEnabled()) {
0179: log.debug("instantiating session factory with properties: "
0180: + properties);
0181: }
0182:
0183: // Caches
0184: settings.getCacheProvider().start(properties);
0185:
0186: //Generators:
0187:
0188: identifierGenerators = new HashMap();
0189: Iterator classes = cfg.getClassMappings();
0190: while (classes.hasNext()) {
0191: PersistentClass model = (PersistentClass) classes.next();
0192: if (!model.isInherited()) {
0193: IdentifierGenerator generator = model.getIdentifier()
0194: .createIdentifierGenerator(
0195: settings.getDialect(),
0196: settings.getDefaultCatalogName(),
0197: settings.getDefaultSchemaName(),
0198: (RootClass) model);
0199: identifierGenerators.put(model.getEntityName(),
0200: generator);
0201: }
0202: }
0203:
0204: //Persisters:
0205:
0206: Map caches = new HashMap();
0207: entityPersisters = new HashMap();
0208: Map classMeta = new HashMap();
0209: classes = cfg.getClassMappings();
0210: while (classes.hasNext()) {
0211: PersistentClass model = (PersistentClass) classes.next();
0212: model
0213: .prepareTemporaryTables(mapping, settings
0214: .getDialect());
0215: String cacheRegion = model.getRootClass()
0216: .getCacheRegionName();
0217: CacheConcurrencyStrategy cache = (CacheConcurrencyStrategy) caches
0218: .get(cacheRegion);
0219: if (cache == null) {
0220: cache = CacheFactory.createCache(model
0221: .getCacheConcurrencyStrategy(), cacheRegion,
0222: model.isMutable(), settings, properties);
0223: if (cache != null) {
0224: caches.put(cacheRegion, cache);
0225: allCacheRegions.put(cache.getRegionName(), cache
0226: .getCache());
0227: }
0228: }
0229: EntityPersister cp = PersisterFactory.createClassPersister(
0230: model, cache, this , mapping);
0231: if (cache != null
0232: && cache.getCache() instanceof OptimisticCache) {
0233: ((OptimisticCache) cache.getCache()).setSource(cp);
0234: }
0235: entityPersisters.put(model.getEntityName(), cp);
0236: classMeta.put(model.getEntityName(), cp.getClassMetadata());
0237: }
0238: classMetadata = Collections.unmodifiableMap(classMeta);
0239:
0240: Map tmpEntityToCollectionRoleMap = new HashMap();
0241: collectionPersisters = new HashMap();
0242: Iterator collections = cfg.getCollectionMappings();
0243: while (collections.hasNext()) {
0244: Collection model = (Collection) collections.next();
0245: CacheConcurrencyStrategy cache = CacheFactory.createCache(
0246: model.getCacheConcurrencyStrategy(), model
0247: .getCacheRegionName(), model.isMutable(),
0248: settings, properties);
0249: if (cache != null) {
0250: allCacheRegions.put(cache.getRegionName(), cache
0251: .getCache());
0252: }
0253: CollectionPersister persister = PersisterFactory
0254: .createCollectionPersister(cfg, model, cache, this );
0255: collectionPersisters.put(model.getRole(), persister
0256: .getCollectionMetadata());
0257: Type indexType = persister.getIndexType();
0258: if (indexType != null && indexType.isAssociationType()
0259: && !indexType.isAnyType()) {
0260: String entityName = ((AssociationType) indexType)
0261: .getAssociatedEntityName(this );
0262: Set roles = (Set) tmpEntityToCollectionRoleMap
0263: .get(entityName);
0264: if (roles == null) {
0265: roles = new HashSet();
0266: tmpEntityToCollectionRoleMap.put(entityName, roles);
0267: }
0268: roles.add(persister.getRole());
0269: }
0270: Type elementType = persister.getElementType();
0271: if (elementType.isAssociationType()
0272: && !elementType.isAnyType()) {
0273: String entityName = ((AssociationType) elementType)
0274: .getAssociatedEntityName(this );
0275: Set roles = (Set) tmpEntityToCollectionRoleMap
0276: .get(entityName);
0277: if (roles == null) {
0278: roles = new HashSet();
0279: tmpEntityToCollectionRoleMap.put(entityName, roles);
0280: }
0281: roles.add(persister.getRole());
0282: }
0283: }
0284: collectionMetadata = Collections
0285: .unmodifiableMap(collectionPersisters);
0286: Iterator itr = tmpEntityToCollectionRoleMap.entrySet()
0287: .iterator();
0288: while (itr.hasNext()) {
0289: final Map.Entry entry = (Map.Entry) itr.next();
0290: entry.setValue(Collections.unmodifiableSet((Set) entry
0291: .getValue()));
0292: }
0293: collectionRolesByEntityParticipant = Collections
0294: .unmodifiableMap(tmpEntityToCollectionRoleMap);
0295:
0296: //Named Queries:
0297: namedQueries = new HashMap(cfg.getNamedQueries());
0298: namedSqlQueries = new HashMap(cfg.getNamedSQLQueries());
0299: sqlResultSetMappings = new HashMap(cfg
0300: .getSqlResultSetMappings());
0301: imports = new HashMap(cfg.getImports());
0302:
0303: // after *all* persisters and named queries are registered
0304: Iterator iter = entityPersisters.values().iterator();
0305: while (iter.hasNext()) {
0306: ((EntityPersister) iter.next()).postInstantiate();
0307: }
0308: iter = collectionPersisters.values().iterator();
0309: while (iter.hasNext()) {
0310: ((CollectionPersister) iter.next()).postInstantiate();
0311: }
0312:
0313: //JNDI + Serialization:
0314:
0315: name = settings.getSessionFactoryName();
0316: try {
0317: uuid = (String) UUID_GENERATOR.generate(null, null);
0318: } catch (Exception e) {
0319: throw new AssertionFailure("Could not generate UUID");
0320: }
0321: SessionFactoryObjectFactory.addInstance(uuid, name, this ,
0322: properties);
0323:
0324: log.debug("instantiated session factory");
0325:
0326: if (settings.isAutoCreateSchema()) {
0327: new SchemaExport(cfg, settings).create(false, true);
0328: }
0329: if (settings.isAutoUpdateSchema()) {
0330: new SchemaUpdate(cfg, settings).execute(false, true);
0331: }
0332: if (settings.isAutoValidateSchema()) {
0333: new SchemaValidator(cfg, settings).validate();
0334: }
0335: if (settings.isAutoDropSchema()) {
0336: schemaExport = new SchemaExport(cfg, settings);
0337: }
0338:
0339: if (settings.getTransactionManagerLookup() != null) {
0340: log.debug("obtaining JTA TransactionManager");
0341: transactionManager = settings.getTransactionManagerLookup()
0342: .getTransactionManager(properties);
0343: } else {
0344: if (settings.getTransactionFactory()
0345: .isTransactionManagerRequired()) {
0346: throw new HibernateException(
0347: "The chosen transaction strategy requires access to the JTA TransactionManager");
0348: }
0349: transactionManager = null;
0350: }
0351:
0352: currentSessionContext = buildCurrentSessionContext();
0353:
0354: if (settings.isQueryCacheEnabled()) {
0355: updateTimestampsCache = new UpdateTimestampsCache(settings,
0356: properties);
0357: queryCache = settings.getQueryCacheFactory().getQueryCache(
0358: null, updateTimestampsCache, settings, properties);
0359: queryCaches = new HashMap();
0360: allCacheRegions.put(updateTimestampsCache.getRegionName(),
0361: updateTimestampsCache.getCache());
0362: allCacheRegions.put(queryCache.getRegionName(), queryCache
0363: .getCache());
0364: } else {
0365: updateTimestampsCache = null;
0366: queryCache = null;
0367: queryCaches = null;
0368: }
0369:
0370: //checking for named queries
0371: if (settings.isNamedQueryStartupCheckingEnabled()) {
0372: Map errors = checkNamedQueries();
0373: if (!errors.isEmpty()) {
0374: Set keys = errors.keySet();
0375: StringBuffer failingQueries = new StringBuffer(
0376: "Errors in named queries: ");
0377: for (Iterator iterator = keys.iterator(); iterator
0378: .hasNext();) {
0379: String queryName = (String) iterator.next();
0380: HibernateException e = (HibernateException) errors
0381: .get(queryName);
0382: failingQueries.append(queryName);
0383: if (iterator.hasNext()) {
0384: failingQueries.append(", ");
0385: }
0386: log.error("Error in named query: " + queryName, e);
0387: }
0388: throw new HibernateException(failingQueries.toString());
0389: }
0390: }
0391:
0392: //stats
0393: getStatistics().setStatisticsEnabled(
0394: settings.isStatisticsEnabled());
0395:
0396: // EntityNotFoundDelegate
0397: EntityNotFoundDelegate entityNotFoundDelegate = cfg
0398: .getEntityNotFoundDelegate();
0399: if (entityNotFoundDelegate == null) {
0400: entityNotFoundDelegate = new EntityNotFoundDelegate() {
0401: public void handleEntityNotFound(String entityName,
0402: Serializable id) {
0403: throw new ObjectNotFoundException(id, entityName);
0404: }
0405: };
0406: }
0407: this .entityNotFoundDelegate = entityNotFoundDelegate;
0408: }
0409:
0410: public QueryPlanCache getQueryPlanCache() {
0411: return queryPlanCache;
0412: }
0413:
0414: private Map checkNamedQueries() throws HibernateException {
0415: Map errors = new HashMap();
0416:
0417: // Check named HQL queries
0418: log.debug("Checking " + namedQueries.size()
0419: + " named HQL queries");
0420: Iterator itr = namedQueries.entrySet().iterator();
0421: while (itr.hasNext()) {
0422: final Map.Entry entry = (Map.Entry) itr.next();
0423: final String queryName = (String) entry.getKey();
0424: final NamedQueryDefinition qd = (NamedQueryDefinition) entry
0425: .getValue();
0426: // this will throw an error if there's something wrong.
0427: try {
0428: log.debug("Checking named query: " + queryName);
0429: //TODO: BUG! this currently fails for named queries for non-POJO entities
0430: queryPlanCache.getHQLQueryPlan(qd.getQueryString(),
0431: false, CollectionHelper.EMPTY_MAP);
0432: } catch (QueryException e) {
0433: errors.put(queryName, e);
0434: } catch (MappingException e) {
0435: errors.put(queryName, e);
0436: }
0437: }
0438:
0439: log.debug("Checking " + namedSqlQueries.size()
0440: + " named SQL queries");
0441: itr = namedSqlQueries.entrySet().iterator();
0442: while (itr.hasNext()) {
0443: final Map.Entry entry = (Map.Entry) itr.next();
0444: final String queryName = (String) entry.getKey();
0445: final NamedSQLQueryDefinition qd = (NamedSQLQueryDefinition) entry
0446: .getValue();
0447: // this will throw an error if there's something wrong.
0448: try {
0449: log.debug("Checking named SQL query: " + queryName);
0450: // TODO : would be really nice to cache the spec on the query-def so as to not have to re-calc the hash;
0451: // currently not doable though because of the resultset-ref stuff...
0452: NativeSQLQuerySpecification spec = null;
0453: if (qd.getResultSetRef() != null) {
0454: ResultSetMappingDefinition definition = (ResultSetMappingDefinition) sqlResultSetMappings
0455: .get(qd.getResultSetRef());
0456: if (definition == null) {
0457: throw new MappingException(
0458: "Unable to find resultset-ref definition: "
0459: + qd.getResultSetRef());
0460: }
0461: spec = new NativeSQLQuerySpecification(qd
0462: .getQueryString(), definition
0463: .getQueryReturns(), qd.getQuerySpaces());
0464: } else {
0465: spec = new NativeSQLQuerySpecification(qd
0466: .getQueryString(), qd.getQueryReturns(), qd
0467: .getQuerySpaces());
0468: }
0469: queryPlanCache.getNativeSQLQueryPlan(spec);
0470: } catch (QueryException e) {
0471: errors.put(queryName, e);
0472: } catch (MappingException e) {
0473: errors.put(queryName, e);
0474: }
0475: }
0476:
0477: return errors;
0478: }
0479:
0480: public StatelessSession openStatelessSession() {
0481: return new StatelessSessionImpl(null, this );
0482: }
0483:
0484: public StatelessSession openStatelessSession(Connection connection) {
0485: return new StatelessSessionImpl(connection, this );
0486: }
0487:
0488: private SessionImpl openSession(Connection connection,
0489: boolean autoClose, long timestamp,
0490: Interceptor sessionLocalInterceptor) {
0491: return new SessionImpl(connection, this , autoClose, timestamp,
0492: sessionLocalInterceptor == null ? interceptor
0493: : sessionLocalInterceptor, settings
0494: .getDefaultEntityMode(), settings
0495: .isFlushBeforeCompletionEnabled(), settings
0496: .isAutoCloseSessionEnabled(), settings
0497: .getConnectionReleaseMode());
0498: }
0499:
0500: public org.hibernate.classic.Session openSession(
0501: Connection connection, Interceptor sessionLocalInterceptor) {
0502: return openSession(connection, false, Long.MIN_VALUE,
0503: sessionLocalInterceptor);
0504: }
0505:
0506: public org.hibernate.classic.Session openSession(
0507: Interceptor sessionLocalInterceptor)
0508: throws HibernateException {
0509: // note that this timestamp is not correct if the connection provider
0510: // returns an older JDBC connection that was associated with a
0511: // transaction that was already begun before openSession() was called
0512: // (don't know any possible solution to this!)
0513: long timestamp = settings.getCacheProvider().nextTimestamp();
0514: return openSession(null, true, timestamp,
0515: sessionLocalInterceptor);
0516: }
0517:
0518: public org.hibernate.classic.Session openSession(
0519: Connection connection) {
0520: return openSession(connection, interceptor); //prevents this session from adding things to cache
0521: }
0522:
0523: public org.hibernate.classic.Session openSession()
0524: throws HibernateException {
0525: return openSession(interceptor);
0526: }
0527:
0528: public org.hibernate.classic.Session openTemporarySession()
0529: throws HibernateException {
0530: return new SessionImpl(null, this , true, settings
0531: .getCacheProvider().nextTimestamp(), interceptor,
0532: settings.getDefaultEntityMode(), false, false,
0533: ConnectionReleaseMode.AFTER_STATEMENT);
0534: }
0535:
0536: public org.hibernate.classic.Session openSession(
0537: final Connection connection,
0538: final boolean flushBeforeCompletionEnabled,
0539: final boolean autoCloseSessionEnabled,
0540: final ConnectionReleaseMode connectionReleaseMode)
0541: throws HibernateException {
0542: return new SessionImpl(connection, this , true, settings
0543: .getCacheProvider().nextTimestamp(), interceptor,
0544: settings.getDefaultEntityMode(),
0545: flushBeforeCompletionEnabled, autoCloseSessionEnabled,
0546: connectionReleaseMode);
0547: }
0548:
0549: public org.hibernate.classic.Session getCurrentSession()
0550: throws HibernateException {
0551: if (currentSessionContext == null) {
0552: throw new HibernateException(
0553: "No CurrentSessionContext configured!");
0554: }
0555: return currentSessionContext.currentSession();
0556: }
0557:
0558: public EntityPersister getEntityPersister(String entityName)
0559: throws MappingException {
0560: EntityPersister result = (EntityPersister) entityPersisters
0561: .get(entityName);
0562: if (result == null) {
0563: throw new MappingException("Unknown entity: " + entityName);
0564: }
0565: return result;
0566: }
0567:
0568: public CollectionPersister getCollectionPersister(String role)
0569: throws MappingException {
0570: CollectionPersister result = (CollectionPersister) collectionPersisters
0571: .get(role);
0572: if (result == null) {
0573: throw new MappingException("Unknown collection role: "
0574: + role);
0575: }
0576: return result;
0577: }
0578:
0579: public Settings getSettings() {
0580: return settings;
0581: }
0582:
0583: public Dialect getDialect() {
0584: return settings.getDialect();
0585: }
0586:
0587: public Interceptor getInterceptor() {
0588: return interceptor;
0589: }
0590:
0591: public TransactionFactory getTransactionFactory() {
0592: return settings.getTransactionFactory();
0593: }
0594:
0595: public TransactionManager getTransactionManager() {
0596: return transactionManager;
0597: }
0598:
0599: public SQLExceptionConverter getSQLExceptionConverter() {
0600: return settings.getSQLExceptionConverter();
0601: }
0602:
0603: public Set getCollectionRolesByEntityParticipant(String entityName) {
0604: return (Set) collectionRolesByEntityParticipant.get(entityName);
0605: }
0606:
0607: // from javax.naming.Referenceable
0608: public Reference getReference() throws NamingException {
0609: log.debug("Returning a Reference to the SessionFactory");
0610: return new Reference(SessionFactoryImpl.class.getName(),
0611: new StringRefAddr("uuid", uuid),
0612: SessionFactoryObjectFactory.class.getName(), null);
0613: }
0614:
0615: private Object readResolve() throws ObjectStreamException {
0616: log.trace("Resolving serialized SessionFactory");
0617: // look for the instance by uuid
0618: Object result = SessionFactoryObjectFactory.getInstance(uuid);
0619: if (result == null) {
0620: // in case we were deserialized in a different JVM, look for an instance with the same name
0621: // (alternatively we could do an actual JNDI lookup here....)
0622: result = SessionFactoryObjectFactory.getNamedInstance(name);
0623: if (result == null) {
0624: throw new InvalidObjectException(
0625: "Could not find a SessionFactory named: "
0626: + name);
0627: } else {
0628: log.debug("resolved SessionFactory by name");
0629: }
0630: } else {
0631: log.debug("resolved SessionFactory by uid");
0632: }
0633: return result;
0634: }
0635:
0636: public NamedQueryDefinition getNamedQuery(String queryName) {
0637: return (NamedQueryDefinition) namedQueries.get(queryName);
0638: }
0639:
0640: public NamedSQLQueryDefinition getNamedSQLQuery(String queryName) {
0641: return (NamedSQLQueryDefinition) namedSqlQueries.get(queryName);
0642: }
0643:
0644: public ResultSetMappingDefinition getResultSetMapping(
0645: String resultSetName) {
0646: return (ResultSetMappingDefinition) sqlResultSetMappings
0647: .get(resultSetName);
0648: }
0649:
0650: public Type getIdentifierType(String className)
0651: throws MappingException {
0652: return getEntityPersister(className).getIdentifierType();
0653: }
0654:
0655: public String getIdentifierPropertyName(String className)
0656: throws MappingException {
0657: return getEntityPersister(className)
0658: .getIdentifierPropertyName();
0659: }
0660:
0661: private final void readObject(ObjectInputStream in)
0662: throws IOException, ClassNotFoundException {
0663: log.trace("deserializing");
0664: in.defaultReadObject();
0665: log.debug("deserialized: " + uuid);
0666: }
0667:
0668: private final void writeObject(ObjectOutputStream out)
0669: throws IOException {
0670: log.debug("serializing: " + uuid);
0671: out.defaultWriteObject();
0672: log.trace("serialized");
0673: }
0674:
0675: public Type[] getReturnTypes(String queryString)
0676: throws HibernateException {
0677: return queryPlanCache.getHQLQueryPlan(queryString, false,
0678: CollectionHelper.EMPTY_MAP).getReturnMetadata()
0679: .getReturnTypes();
0680: }
0681:
0682: public String[] getReturnAliases(String queryString)
0683: throws HibernateException {
0684: return queryPlanCache.getHQLQueryPlan(queryString, false,
0685: CollectionHelper.EMPTY_MAP).getReturnMetadata()
0686: .getReturnAliases();
0687: }
0688:
0689: public ClassMetadata getClassMetadata(Class persistentClass)
0690: throws HibernateException {
0691: return getClassMetadata(persistentClass.getName());
0692: }
0693:
0694: public CollectionMetadata getCollectionMetadata(String roleName)
0695: throws HibernateException {
0696: return (CollectionMetadata) collectionMetadata.get(roleName);
0697: }
0698:
0699: public ClassMetadata getClassMetadata(String entityName)
0700: throws HibernateException {
0701: return (ClassMetadata) classMetadata.get(entityName);
0702: }
0703:
0704: /**
0705: * Return the names of all persistent (mapped) classes that extend or implement the
0706: * given class or interface, accounting for implicit/explicit polymorphism settings
0707: * and excluding mapped subclasses/joined-subclasses of other classes in the result.
0708: */
0709: public String[] getImplementors(String className)
0710: throws MappingException {
0711:
0712: final Class clazz;
0713: try {
0714: clazz = ReflectHelper.classForName(className);
0715: } catch (ClassNotFoundException cnfe) {
0716: return new String[] { className }; //for a dynamic-class
0717: }
0718:
0719: ArrayList results = new ArrayList();
0720: Iterator iter = entityPersisters.values().iterator();
0721: while (iter.hasNext()) {
0722: //test this entity to see if we must query it
0723: EntityPersister testPersister = (EntityPersister) iter
0724: .next();
0725: if (testPersister instanceof Queryable) {
0726: Queryable testQueryable = (Queryable) testPersister;
0727: String testClassName = testQueryable.getEntityName();
0728: boolean isMappedClass = className.equals(testClassName);
0729: if (testQueryable.isExplicitPolymorphism()) {
0730: if (isMappedClass) {
0731: return new String[] { className }; //NOTE EARLY EXIT
0732: }
0733: } else {
0734: if (isMappedClass) {
0735: results.add(testClassName);
0736: } else {
0737: final Class mappedClass = testQueryable
0738: .getMappedClass(EntityMode.POJO);
0739: if (mappedClass != null
0740: && clazz.isAssignableFrom(mappedClass)) {
0741: final boolean assignableSuperclass;
0742: if (testQueryable.isInherited()) {
0743: Class mappedSuperclass = getEntityPersister(
0744: testQueryable
0745: .getMappedSuperclass())
0746: .getMappedClass(EntityMode.POJO);
0747: assignableSuperclass = clazz
0748: .isAssignableFrom(mappedSuperclass);
0749: } else {
0750: assignableSuperclass = false;
0751: }
0752: if (!assignableSuperclass) {
0753: results.add(testClassName);
0754: }
0755: }
0756: }
0757: }
0758: }
0759: }
0760: return (String[]) results.toArray(new String[results.size()]);
0761: }
0762:
0763: public String getImportedClassName(String className) {
0764: String result = (String) imports.get(className);
0765: if (result == null) {
0766: try {
0767: ReflectHelper.classForName(className);
0768: return className;
0769: } catch (ClassNotFoundException cnfe) {
0770: return null;
0771: }
0772: } else {
0773: return result;
0774: }
0775: }
0776:
0777: public Map getAllClassMetadata() throws HibernateException {
0778: return classMetadata;
0779: }
0780:
0781: public Map getAllCollectionMetadata() throws HibernateException {
0782: return collectionMetadata;
0783: }
0784:
0785: /**
0786: * Closes the session factory, releasing all held resources.
0787: *
0788: * <ol>
0789: * <li>cleans up used cache regions and "stops" the cache provider.
0790: * <li>close the JDBC connection
0791: * <li>remove the JNDI binding
0792: * </ol>
0793: *
0794: * Note: Be aware that the sessionfactory instance still can
0795: * be a "heavy" object memory wise after close() has been called. Thus
0796: * it is important to not keep referencing the instance to let the garbage
0797: * collector release the memory.
0798: */
0799: public void close() throws HibernateException {
0800:
0801: log.info("closing");
0802:
0803: isClosed = true;
0804:
0805: Iterator iter = entityPersisters.values().iterator();
0806: while (iter.hasNext()) {
0807: EntityPersister p = (EntityPersister) iter.next();
0808: if (p.hasCache()) {
0809: p.getCache().destroy();
0810: }
0811: }
0812:
0813: iter = collectionPersisters.values().iterator();
0814: while (iter.hasNext()) {
0815: CollectionPersister p = (CollectionPersister) iter.next();
0816: if (p.hasCache()) {
0817: p.getCache().destroy();
0818: }
0819: }
0820:
0821: if (settings.isQueryCacheEnabled()) {
0822: queryCache.destroy();
0823:
0824: iter = queryCaches.values().iterator();
0825: while (iter.hasNext()) {
0826: QueryCache cache = (QueryCache) iter.next();
0827: cache.destroy();
0828: }
0829: updateTimestampsCache.destroy();
0830: }
0831:
0832: settings.getCacheProvider().stop();
0833:
0834: try {
0835: settings.getConnectionProvider().close();
0836: } finally {
0837: SessionFactoryObjectFactory.removeInstance(uuid, name,
0838: properties);
0839: }
0840:
0841: if (settings.isAutoDropSchema()) {
0842: schemaExport.drop(false, true);
0843: }
0844:
0845: }
0846:
0847: public void evictEntity(String entityName, Serializable id)
0848: throws HibernateException {
0849: EntityPersister p = getEntityPersister(entityName);
0850: if (p.hasCache()) {
0851: if (log.isDebugEnabled()) {
0852: log.debug("evicting second-level cache: "
0853: + MessageHelper.infoString(p, id, this ));
0854: }
0855: CacheKey cacheKey = new CacheKey(id, p.getIdentifierType(),
0856: p.getRootEntityName(), EntityMode.POJO, this );
0857: p.getCache().remove(cacheKey);
0858: }
0859: }
0860:
0861: public void evictEntity(String entityName)
0862: throws HibernateException {
0863: EntityPersister p = getEntityPersister(entityName);
0864: if (p.hasCache()) {
0865: if (log.isDebugEnabled()) {
0866: log.debug("evicting second-level cache: "
0867: + p.getEntityName());
0868: }
0869: p.getCache().clear();
0870: }
0871: }
0872:
0873: public void evict(Class persistentClass, Serializable id)
0874: throws HibernateException {
0875: EntityPersister p = getEntityPersister(persistentClass
0876: .getName());
0877: if (p.hasCache()) {
0878: if (log.isDebugEnabled()) {
0879: log.debug("evicting second-level cache: "
0880: + MessageHelper.infoString(p, id, this ));
0881: }
0882: CacheKey cacheKey = new CacheKey(id, p.getIdentifierType(),
0883: p.getRootEntityName(), EntityMode.POJO, this );
0884: p.getCache().remove(cacheKey);
0885: }
0886: }
0887:
0888: public void evict(Class persistentClass) throws HibernateException {
0889: EntityPersister p = getEntityPersister(persistentClass
0890: .getName());
0891: if (p.hasCache()) {
0892: if (log.isDebugEnabled()) {
0893: log.debug("evicting second-level cache: "
0894: + p.getEntityName());
0895: }
0896: p.getCache().clear();
0897: }
0898: }
0899:
0900: public void evictCollection(String roleName, Serializable id)
0901: throws HibernateException {
0902: CollectionPersister p = getCollectionPersister(roleName);
0903: if (p.hasCache()) {
0904: if (log.isDebugEnabled()) {
0905: log.debug("evicting second-level cache: "
0906: + MessageHelper.collectionInfoString(p, id,
0907: this ));
0908: }
0909: CacheKey cacheKey = new CacheKey(id, p.getKeyType(), p
0910: .getRole(), EntityMode.POJO, this );
0911: p.getCache().remove(cacheKey);
0912: }
0913: }
0914:
0915: public void evictCollection(String roleName)
0916: throws HibernateException {
0917: CollectionPersister p = getCollectionPersister(roleName);
0918: if (p.hasCache()) {
0919: if (log.isDebugEnabled()) {
0920: log
0921: .debug("evicting second-level cache: "
0922: + p.getRole());
0923: }
0924: p.getCache().clear();
0925: }
0926: }
0927:
0928: public Type getReferencedPropertyType(String className,
0929: String propertyName) throws MappingException {
0930: return getEntityPersister(className).getPropertyType(
0931: propertyName);
0932: }
0933:
0934: public ConnectionProvider getConnectionProvider() {
0935: return settings.getConnectionProvider();
0936: }
0937:
0938: public UpdateTimestampsCache getUpdateTimestampsCache() {
0939: return updateTimestampsCache;
0940: }
0941:
0942: public QueryCache getQueryCache() {
0943: return queryCache;
0944: }
0945:
0946: public QueryCache getQueryCache(String cacheRegion)
0947: throws HibernateException {
0948: if (cacheRegion == null) {
0949: return getQueryCache();
0950: }
0951:
0952: if (!settings.isQueryCacheEnabled()) {
0953: return null;
0954: }
0955:
0956: synchronized (allCacheRegions) {
0957: QueryCache currentQueryCache = (QueryCache) queryCaches
0958: .get(cacheRegion);
0959: if (currentQueryCache == null) {
0960: currentQueryCache = settings.getQueryCacheFactory()
0961: .getQueryCache(cacheRegion,
0962: updateTimestampsCache, settings,
0963: properties);
0964: queryCaches.put(cacheRegion, currentQueryCache);
0965: allCacheRegions.put(currentQueryCache.getRegionName(),
0966: currentQueryCache.getCache());
0967: }
0968: return currentQueryCache;
0969: }
0970: }
0971:
0972: public Cache getSecondLevelCacheRegion(String regionName) {
0973: synchronized (allCacheRegions) {
0974: return (Cache) allCacheRegions.get(regionName);
0975: }
0976: }
0977:
0978: public Map getAllSecondLevelCacheRegions() {
0979: synchronized (allCacheRegions) {
0980: return new HashMap(allCacheRegions);
0981: }
0982: }
0983:
0984: public boolean isClosed() {
0985: return isClosed;
0986: }
0987:
0988: public Statistics getStatistics() {
0989: return statistics;
0990: }
0991:
0992: public StatisticsImplementor getStatisticsImplementor() {
0993: return statistics;
0994: }
0995:
0996: public void evictQueries() throws HibernateException {
0997: if (settings.isQueryCacheEnabled()) {
0998: queryCache.clear();
0999: }
1000: }
1001:
1002: public void evictQueries(String cacheRegion)
1003: throws HibernateException {
1004: if (cacheRegion == null) {
1005: throw new NullPointerException(
1006: "use the zero-argument form to evict the default query cache");
1007: } else {
1008: synchronized (allCacheRegions) {
1009: if (settings.isQueryCacheEnabled()) {
1010: QueryCache currentQueryCache = (QueryCache) queryCaches
1011: .get(cacheRegion);
1012: if (currentQueryCache != null) {
1013: currentQueryCache.clear();
1014: }
1015: }
1016: }
1017: }
1018: }
1019:
1020: public FilterDefinition getFilterDefinition(String filterName)
1021: throws HibernateException {
1022: FilterDefinition def = (FilterDefinition) filters
1023: .get(filterName);
1024: if (def == null) {
1025: throw new HibernateException("No such filter configured ["
1026: + filterName + "]");
1027: }
1028: return def;
1029: }
1030:
1031: public Set getDefinedFilterNames() {
1032: return filters.keySet();
1033: }
1034:
1035: public BatcherFactory getBatcherFactory() {
1036: return settings.getBatcherFactory();
1037: }
1038:
1039: public IdentifierGenerator getIdentifierGenerator(
1040: String rootEntityName) {
1041: return (IdentifierGenerator) identifierGenerators
1042: .get(rootEntityName);
1043: }
1044:
1045: private CurrentSessionContext buildCurrentSessionContext() {
1046: String impl = properties
1047: .getProperty(Environment.CURRENT_SESSION_CONTEXT_CLASS);
1048: // for backward-compatability
1049: if (impl == null && transactionManager != null) {
1050: impl = "jta";
1051: }
1052:
1053: if (impl == null) {
1054: return null;
1055: } else if ("jta".equals(impl)) {
1056: if (settings.getTransactionFactory()
1057: .areCallbacksLocalToHibernateTransactions()) {
1058: log
1059: .warn("JTASessionContext being used with JDBCTransactionFactory; auto-flush will not operate correctly with getCurrentSession()");
1060: }
1061: return new JTASessionContext(this );
1062: } else if ("thread".equals(impl)) {
1063: return new ThreadLocalSessionContext(this );
1064: } else if ("managed".equals(impl)) {
1065: return new ManagedSessionContext(this );
1066: } else {
1067: try {
1068: Class implClass = ReflectHelper.classForName(impl);
1069: return (CurrentSessionContext) implClass
1070: .getConstructor(
1071: new Class[] { SessionFactoryImplementor.class })
1072: .newInstance(new Object[] { this });
1073: } catch (Throwable t) {
1074: log.error(
1075: "Unable to construct current session context ["
1076: + impl + "]", t);
1077: return null;
1078: }
1079: }
1080: }
1081:
1082: public EventListeners getEventListeners() {
1083: return eventListeners;
1084: }
1085:
1086: public EntityNotFoundDelegate getEntityNotFoundDelegate() {
1087: return entityNotFoundDelegate;
1088: }
1089:
1090: /**
1091: * Custom serialization hook used during Session serialization.
1092: *
1093: * @param oos The stream to which to write the factory
1094: * @throws IOException
1095: */
1096: void serialize(ObjectOutputStream oos) throws IOException {
1097: oos.writeUTF(uuid);
1098: oos.writeBoolean(name != null);
1099: if (name != null) {
1100: oos.writeUTF(name);
1101: }
1102: }
1103:
1104: /**
1105: * Custom deserialization hook used during Session deserialization.
1106: *
1107: * @param ois The stream from which to "read" the factory
1108: * @throws IOException
1109: */
1110: static SessionFactoryImpl deserialize(ObjectInputStream ois)
1111: throws IOException, ClassNotFoundException {
1112: String uuid = ois.readUTF();
1113: boolean isNamed = ois.readBoolean();
1114: String name = null;
1115: if (isNamed) {
1116: name = ois.readUTF();
1117: }
1118: Object result = SessionFactoryObjectFactory.getInstance(uuid);
1119: if (result == null) {
1120: log.trace("could not locate session factory by uuid ["
1121: + uuid
1122: + "] during session deserialization; trying name");
1123: if (isNamed) {
1124: result = SessionFactoryObjectFactory
1125: .getNamedInstance(name);
1126: }
1127: if (result == null) {
1128: throw new InvalidObjectException(
1129: "could not resolve session factory during session deserialization [uuid="
1130: + uuid + ", name=" + name + "]");
1131: }
1132: }
1133: return (SessionFactoryImpl) result;
1134: }
1135:
1136: public SQLFunctionRegistry getSqlFunctionRegistry() {
1137: return sqlFunctionRegistry;
1138: }
1139: }
|