@SuppressWarnings({CompilerWarnings.UNCHECKED})
  private void buildEntityMetadatas() throws Exception {
    SessionFactoryImpl sessionFactory =
        ((SessionFactoryImpl) this.entityManagerFactory.getSessionFactory());
    Class<?> entityBindingMappedClass;
    Class<? extends SdcctEntity> entityMappedClass;
    String entityName, entityPropName, entityPropFieldName;
    EntityMetadata entityMetadata;
    Map<String, PropertyMetadata> entityPropMetadatas;
    IndexedTypeDescriptor indexedEntityDesc;
    Method entityPropGetterMethod;
    boolean entityIndexed, entityPropIndexed;
    PropertyDescriptor indexedEntityPropDesc;
    PropertyMetadata entityPropMetadata;
    BidiMap<Integer, String> entityPropOrder;
    String[] entityPropOrderNames;

    for (PersistentClass entityBinding : metadata.getEntityBindings()) {
      if (((entityBindingMappedClass = entityBinding.getMappedClass()) == null)
          || !SdcctEntity.class.isAssignableFrom(entityBindingMappedClass)) {
        continue;
      }

      entityPropMetadatas =
          (entityMetadata =
                  new EntityMetadataImpl(
                      (entityName = entityBinding.getEntityName()),
                      (entityIndexed =
                          (indexedEntityDesc =
                                  searchIntegrator.getIndexedTypeDescriptor(
                                      (entityMappedClass =
                                          ((Class<? extends SdcctEntity>)
                                              entityBindingMappedClass))))
                              .isIndexed()),
                      entityMappedClass,
                      entityBinding.getTable().getName()))
              .getProperties();

      this.entityMetadatas.put(
          ((Class<? extends SdcctEntity>) entityMappedClass.getInterfaces()[0]), entityMetadata);

      for (Property entityProp :
          IteratorUtils.asIterable(
              IteratorUtils.chainedIterator(
                  ((Iterator<Property>) entityBinding.getRootClass().getPropertyIterator()),
                  ((Iterator<Property>) entityBinding.getPropertyIterator())))) {
        entityPropName = entityProp.getName();
        entityPropGetterMethod = entityProp.getGetter(entityMappedClass).getMethod();

        if (entityProp.getColumnSpan() == 0) {
          continue;
        }

        entityPropIndexed =
            (entityIndexed
                && entityPropGetterMethod.isAnnotationPresent(Fields.class)
                && ((indexedEntityPropDesc = indexedEntityDesc.getProperty(entityPropName)) != null)
                && !indexedEntityPropDesc.isId());

        entityPropMetadatas.put(
            entityPropName,
            (entityPropMetadata =
                new PropertyMetadataImpl(
                    entityPropName,
                    entityPropIndexed,
                    ((Column) entityProp.getColumnIterator().next()).getName(),
                    entityProp.getType())));

        if (entityPropIndexed) {
          for (Field entityPropFieldAnno :
              entityPropGetterMethod.getAnnotation(Fields.class).value()) {
            if (entityPropFieldAnno.analyze() == Analyze.NO) {
              continue;
            }

            entityPropFieldName = entityPropFieldAnno.name();

            switch (entityPropFieldAnno.analyzer().definition()) {
              case DbAnalyzerNames.EDGE_NGRAM:
                entityPropMetadata.setEdgeNgramFieldName(entityPropFieldName);
                break;

              case DbAnalyzerNames.LOWERCASE:
                entityPropMetadata.setLowercaseFieldName(entityPropFieldName);
                break;

              case DbAnalyzerNames.NGRAM:
                entityPropMetadata.setNgramFieldName(entityPropFieldName);
                break;

              case DbAnalyzerNames.PHONETIC:
                entityPropMetadata.setPhoneticFieldName(entityPropFieldName);
                break;
            }
          }
        }
      }

      entityMetadata.setIdProperty(
          entityPropMetadatas.get(entityBinding.getIdentifierProperty().getName()));

      entityPropOrder = entityMetadata.getPropertyOrder();
      entityPropOrderNames = sessionFactory.getEntityPersister(entityName).getPropertyNames();

      for (int a = 0; a < entityPropOrderNames.length; a++) {
        entityPropOrder.put(a, entityPropOrderNames[a]);
      }
    }

    LOGGER.debug(
        String.format(
            "Processed metadata for %d entities: [%s]",
            this.entityMetadatas.size(),
            this.entityMetadatas
                .values()
                .stream()
                .map(NamedBean::getName)
                .collect(Collectors.joining(", "))));
  }
  public EntityMetamodel(
      PersistentClass persistentClass,
      AbstractEntityPersister persister,
      SessionFactoryImplementor sessionFactory) {
    this.sessionFactory = sessionFactory;
    this.persister = persister;

    name = persistentClass.getEntityName();
    rootName = persistentClass.getRootClass().getEntityName();
    entityType = sessionFactory.getTypeResolver().getTypeFactory().manyToOne(name);

    identifierAttribute =
        PropertyFactory.buildIdentifierAttribute(
            persistentClass, sessionFactory.getIdentifierGenerator(rootName));

    versioned = persistentClass.isVersioned();

    instrumentationMetadata =
        persistentClass.hasPojoRepresentation()
            ? Environment.getBytecodeProvider()
                .getEntityInstrumentationMetadata(persistentClass.getMappedClass())
            : new NonPojoInstrumentationMetadata(persistentClass.getEntityName());

    boolean hasLazy = false;

    propertySpan = persistentClass.getPropertyClosureSpan();
    properties = new NonIdentifierAttribute[propertySpan];
    List<Integer> naturalIdNumbers = new ArrayList<Integer>();
    // temporary ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    propertyNames = new String[propertySpan];
    propertyTypes = new Type[propertySpan];
    propertyUpdateability = new boolean[propertySpan];
    propertyInsertability = new boolean[propertySpan];
    nonlazyPropertyUpdateability = new boolean[propertySpan];
    propertyCheckability = new boolean[propertySpan];
    propertyNullability = new boolean[propertySpan];
    propertyVersionability = new boolean[propertySpan];
    propertyLaziness = new boolean[propertySpan];
    cascadeStyles = new CascadeStyle[propertySpan];
    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

    // generated value strategies
    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    this.inMemoryValueGenerationStrategies = new InMemoryValueGenerationStrategy[propertySpan];
    this.inDatabaseValueGenerationStrategies = new InDatabaseValueGenerationStrategy[propertySpan];

    boolean foundPreInsertGeneratedValues = false;
    boolean foundPreUpdateGeneratedValues = false;
    boolean foundPostInsertGeneratedValues = false;
    boolean foundPostUpdateGeneratedValues = false;
    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

    Iterator iter = persistentClass.getPropertyClosureIterator();
    int i = 0;
    int tempVersionProperty = NO_VERSION_INDX;
    boolean foundCascade = false;
    boolean foundCollection = false;
    boolean foundMutable = false;
    boolean foundNonIdentifierPropertyNamedId = false;
    boolean foundInsertGeneratedValue = false;
    boolean foundUpdateGeneratedValue = false;
    boolean foundUpdateableNaturalIdProperty = false;

    while (iter.hasNext()) {
      Property prop = (Property) iter.next();

      if (prop == persistentClass.getVersion()) {
        tempVersionProperty = i;
        properties[i] =
            PropertyFactory.buildVersionProperty(
                persister, sessionFactory, i, prop, instrumentationMetadata.isInstrumented());
      } else {
        properties[i] =
            PropertyFactory.buildEntityBasedAttribute(
                persister, sessionFactory, i, prop, instrumentationMetadata.isInstrumented());
      }

      if (prop.isNaturalIdentifier()) {
        naturalIdNumbers.add(i);
        if (prop.isUpdateable()) {
          foundUpdateableNaturalIdProperty = true;
        }
      }

      if ("id".equals(prop.getName())) {
        foundNonIdentifierPropertyNamedId = true;
      }

      // temporary ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
      boolean lazy = prop.isLazy() && instrumentationMetadata.isInstrumented();
      if (lazy) hasLazy = true;
      propertyLaziness[i] = lazy;

      propertyNames[i] = properties[i].getName();
      propertyTypes[i] = properties[i].getType();
      propertyNullability[i] = properties[i].isNullable();
      propertyUpdateability[i] = properties[i].isUpdateable();
      propertyInsertability[i] = properties[i].isInsertable();
      propertyVersionability[i] = properties[i].isVersionable();
      nonlazyPropertyUpdateability[i] = properties[i].isUpdateable() && !lazy;
      propertyCheckability[i] =
          propertyUpdateability[i]
              || (propertyTypes[i].isAssociationType()
                  && ((AssociationType) propertyTypes[i]).isAlwaysDirtyChecked());

      cascadeStyles[i] = properties[i].getCascadeStyle();
      // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

      // generated value strategies
      // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
      GenerationStrategyPair pair = buildGenerationStrategyPair(sessionFactory, prop);
      inMemoryValueGenerationStrategies[i] = pair.getInMemoryStrategy();
      inDatabaseValueGenerationStrategies[i] = pair.getInDatabaseStrategy();

      if (pair.getInMemoryStrategy() != null) {
        final GenerationTiming timing = pair.getInMemoryStrategy().getGenerationTiming();
        if (timing != GenerationTiming.NEVER) {
          final ValueGenerator generator = pair.getInMemoryStrategy().getValueGenerator();
          if (generator != null) {
            // we have some level of generation indicated
            if (timing == GenerationTiming.INSERT) {
              foundPreInsertGeneratedValues = true;
            } else if (timing == GenerationTiming.ALWAYS) {
              foundPreInsertGeneratedValues = true;
              foundPreUpdateGeneratedValues = true;
            }
          }
        }
      }
      if (pair.getInDatabaseStrategy() != null) {
        final GenerationTiming timing = pair.getInDatabaseStrategy().getGenerationTiming();
        if (timing == GenerationTiming.INSERT) {
          foundPostInsertGeneratedValues = true;
        } else if (timing == GenerationTiming.ALWAYS) {
          foundPostInsertGeneratedValues = true;
          foundPostUpdateGeneratedValues = true;
        }
      }
      // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

      if (properties[i].isLazy()) {
        hasLazy = true;
      }

      if (properties[i].getCascadeStyle() != CascadeStyles.NONE) {
        foundCascade = true;
      }

      if (indicatesCollection(properties[i].getType())) {
        foundCollection = true;
      }

      if (propertyTypes[i].isMutable() && propertyCheckability[i]) {
        foundMutable = true;
      }

      mapPropertyToIndex(prop, i);
      i++;
    }

    if (naturalIdNumbers.size() == 0) {
      naturalIdPropertyNumbers = null;
      hasImmutableNaturalId = false;
      hasCacheableNaturalId = false;
    } else {
      naturalIdPropertyNumbers = ArrayHelper.toIntArray(naturalIdNumbers);
      hasImmutableNaturalId = !foundUpdateableNaturalIdProperty;
      hasCacheableNaturalId = persistentClass.getNaturalIdCacheRegionName() != null;
    }

    this.hasPreInsertGeneratedValues = foundPreInsertGeneratedValues;
    this.hasPreUpdateGeneratedValues = foundPreUpdateGeneratedValues;
    this.hasInsertGeneratedValues = foundPostInsertGeneratedValues;
    this.hasUpdateGeneratedValues = foundPostUpdateGeneratedValues;

    hasCascades = foundCascade;
    hasNonIdentifierPropertyNamedId = foundNonIdentifierPropertyNamedId;
    versionPropertyIndex = tempVersionProperty;
    hasLazyProperties = hasLazy;
    if (hasLazyProperties) LOG.lazyPropertyFetchingAvailable(name);

    lazy =
        persistentClass.isLazy()
            && (
            // TODO: this disables laziness even in non-pojo entity modes:
            !persistentClass.hasPojoRepresentation()
                || !ReflectHelper.isFinalClass(persistentClass.getProxyInterface()));
    mutable = persistentClass.isMutable();
    if (persistentClass.isAbstract() == null) {
      // legacy behavior (with no abstract attribute specified)
      isAbstract =
          persistentClass.hasPojoRepresentation()
              && ReflectHelper.isAbstractClass(persistentClass.getMappedClass());
    } else {
      isAbstract = persistentClass.isAbstract().booleanValue();
      if (!isAbstract
          && persistentClass.hasPojoRepresentation()
          && ReflectHelper.isAbstractClass(persistentClass.getMappedClass())) {
        LOG.entityMappedAsNonAbstract(name);
      }
    }
    selectBeforeUpdate = persistentClass.hasSelectBeforeUpdate();
    dynamicUpdate = persistentClass.useDynamicUpdate();
    dynamicInsert = persistentClass.useDynamicInsert();

    polymorphic = persistentClass.isPolymorphic();
    explicitPolymorphism = persistentClass.isExplicitPolymorphism();
    inherited = persistentClass.isInherited();
    superclass = inherited ? persistentClass.getSuperclass().getEntityName() : null;
    hasSubclasses = persistentClass.hasSubclasses();

    optimisticLockStyle = persistentClass.getOptimisticLockStyle();
    final boolean isAllOrDirty =
        optimisticLockStyle == OptimisticLockStyle.ALL
            || optimisticLockStyle == OptimisticLockStyle.DIRTY;
    if (isAllOrDirty && !dynamicUpdate) {
      throw new MappingException(
          "optimistic-lock=all|dirty requires dynamic-update=\"true\": " + name);
    }
    if (versionPropertyIndex != NO_VERSION_INDX && isAllOrDirty) {
      throw new MappingException(
          "version and optimistic-lock=all|dirty are not a valid combination : " + name);
    }

    hasCollections = foundCollection;
    hasMutableProperties = foundMutable;

    iter = persistentClass.getSubclassIterator();
    while (iter.hasNext()) {
      subclassEntityNames.add(((PersistentClass) iter.next()).getEntityName());
    }
    subclassEntityNames.add(name);

    if (persistentClass.hasPojoRepresentation()) {
      entityNameByInheritenceClassMap.put(
          persistentClass.getMappedClass(), persistentClass.getEntityName());
      iter = persistentClass.getSubclassIterator();
      while (iter.hasNext()) {
        final PersistentClass pc = (PersistentClass) iter.next();
        entityNameByInheritenceClassMap.put(pc.getMappedClass(), pc.getEntityName());
      }
    }

    entityMode = persistentClass.hasPojoRepresentation() ? EntityMode.POJO : EntityMode.MAP;
    final EntityTuplizerFactory entityTuplizerFactory =
        sessionFactory.getSettings().getEntityTuplizerFactory();
    final String tuplizerClassName = persistentClass.getTuplizerImplClassName(entityMode);
    if (tuplizerClassName == null) {
      entityTuplizer =
          entityTuplizerFactory.constructDefaultTuplizer(entityMode, this, persistentClass);
    } else {
      entityTuplizer =
          entityTuplizerFactory.constructTuplizer(tuplizerClassName, this, persistentClass);
    }
  }
  public SessionFactoryImpl(
      Configuration cfg,
      Mapping mapping,
      Settings settings,
      EventListeners listeners,
      SessionFactoryObserver observer)
      throws HibernateException {
    log.info("building session factory");

    Statistics concurrentStatistics = null;
    try {
      Class concurrentStatsClass =
          ReflectHelper.classForName("org.hibernate.stat.ConcurrentStatisticsImpl");
      Constructor constructor =
          concurrentStatsClass.getConstructor(new Class[] {SessionFactoryImplementor.class});
      concurrentStatistics = (Statistics) constructor.newInstance(new Object[] {this});
      log.trace("JDK 1.5 concurrent classes present");
    } catch (NoClassDefFoundError noJava5) {
      log.trace("JDK 1.5 concurrent classes missing");
    } catch (Exception noJava5) {
      log.trace("JDK 1.5 concurrent classes missing");
    }

    if (concurrentStatistics != null) {
      this.statistics = concurrentStatistics;
    } else {
      this.statistics = new StatisticsImpl(this);
    }

    if (log.isTraceEnabled()) {
      log.trace("Statistics initialized with " + statistics.getClass().getName());
    }

    this.properties = new Properties();
    this.properties.putAll(cfg.getProperties());
    this.interceptor = cfg.getInterceptor();
    this.settings = settings;
    this.sqlFunctionRegistry =
        new SQLFunctionRegistry(settings.getDialect(), cfg.getSqlFunctions());
    this.eventListeners = listeners;
    this.observer =
        observer != null
            ? observer
            : new SessionFactoryObserver() {
              public void sessionFactoryCreated(SessionFactory factory) {}

              public void sessionFactoryClosed(SessionFactory factory) {}
            };

    this.filters = new HashMap();
    this.filters.putAll(cfg.getFilterDefinitions());

    if (log.isDebugEnabled()) {
      log.debug("Session factory constructed with filter configurations : " + filters);
    }

    if (log.isDebugEnabled()) {
      log.debug("instantiating session factory with properties: " + properties);
    }

    // Caches
    settings.getRegionFactory().start(settings, properties);

    // Generators:

    identifierGenerators = new HashMap();
    Iterator classes = cfg.getClassMappings();
    while (classes.hasNext()) {
      PersistentClass model = (PersistentClass) classes.next();
      if (!model.isInherited()) {
        IdentifierGenerator generator =
            model
                .getIdentifier()
                .createIdentifierGenerator(
                    cfg.getIdentifierGeneratorFactory(),
                    settings.getDialect(),
                    settings.getDefaultCatalogName(),
                    settings.getDefaultSchemaName(),
                    (RootClass) model);
        identifierGenerators.put(model.getEntityName(), generator);
      }
    }

    ///////////////////////////////////////////////////////////////////////
    // Prepare persisters and link them up with their cache
    // region/access-strategy

    final String cacheRegionPrefix =
        settings.getCacheRegionPrefix() == null ? "" : settings.getCacheRegionPrefix() + ".";

    entityPersisters = new HashMap();
    Map entityAccessStrategies = new HashMap();
    Map classMeta = new HashMap();
    classes = cfg.getClassMappings();
    while (classes.hasNext()) {
      final PersistentClass model = (PersistentClass) classes.next();
      model.prepareTemporaryTables(mapping, settings.getDialect());
      final String cacheRegionName = cacheRegionPrefix + model.getRootClass().getCacheRegionName();
      // cache region is defined by the root-class in the hierarchy...
      EntityRegionAccessStrategy accessStrategy =
          (EntityRegionAccessStrategy) entityAccessStrategies.get(cacheRegionName);
      if (accessStrategy == null && settings.isSecondLevelCacheEnabled()) {
        final AccessType accessType = AccessType.parse(model.getCacheConcurrencyStrategy());
        if (accessType != null) {
          log.trace("Building cache for entity data [" + model.getEntityName() + "]");
          EntityRegion entityRegion =
              settings
                  .getRegionFactory()
                  .buildEntityRegion(
                      cacheRegionName, properties, CacheDataDescriptionImpl.decode(model));
          accessStrategy = entityRegion.buildAccessStrategy(accessType);
          entityAccessStrategies.put(cacheRegionName, accessStrategy);
          allCacheRegions.put(cacheRegionName, entityRegion);
        }
      }
      EntityPersister cp =
          PersisterFactory.createClassPersister(model, accessStrategy, this, mapping);
      entityPersisters.put(model.getEntityName(), cp);
      classMeta.put(model.getEntityName(), cp.getClassMetadata());
    }
    classMetadata = Collections.unmodifiableMap(classMeta);

    Map tmpEntityToCollectionRoleMap = new HashMap();
    collectionPersisters = new HashMap();
    Iterator collections = cfg.getCollectionMappings();
    while (collections.hasNext()) {
      Collection model = (Collection) collections.next();
      final String cacheRegionName = cacheRegionPrefix + model.getCacheRegionName();
      final AccessType accessType = AccessType.parse(model.getCacheConcurrencyStrategy());
      CollectionRegionAccessStrategy accessStrategy = null;
      if (accessType != null && settings.isSecondLevelCacheEnabled()) {
        log.trace("Building cache for collection data [" + model.getRole() + "]");
        CollectionRegion collectionRegion =
            settings
                .getRegionFactory()
                .buildCollectionRegion(
                    cacheRegionName, properties, CacheDataDescriptionImpl.decode(model));
        accessStrategy = collectionRegion.buildAccessStrategy(accessType);
        entityAccessStrategies.put(cacheRegionName, accessStrategy);
        allCacheRegions.put(cacheRegionName, collectionRegion);
      }
      CollectionPersister persister =
          PersisterFactory.createCollectionPersister(cfg, model, accessStrategy, this);
      collectionPersisters.put(model.getRole(), persister.getCollectionMetadata());
      Type indexType = persister.getIndexType();
      if (indexType != null && indexType.isAssociationType() && !indexType.isAnyType()) {
        String entityName = ((AssociationType) indexType).getAssociatedEntityName(this);
        Set roles = (Set) 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 = (Set) 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(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();
    while (iter.hasNext()) {
      final EntityPersister persister = ((EntityPersister) iter.next());
      persister.postInstantiate();
      registerEntityNameResolvers(persister);
    }
    iter = collectionPersisters.values().iterator();
    while (iter.hasNext()) {
      final CollectionPersister persister = ((CollectionPersister) iter.next());
      persister.postInstantiate();
    }

    // JNDI + Serialization:

    name = settings.getSessionFactoryName();
    try {
      uuid = (String) UUID_GENERATOR.generate(null, null);
    } catch (Exception e) {
      throw new AssertionFailure("Could not generate UUID");
    }
    SessionFactoryObjectFactory.addInstance(uuid, name, this, properties);

    log.debug("instantiated session factory");

    if (settings.isAutoCreateSchema()) {
      new SchemaExport(cfg, settings).create(false, true);
    }
    if (settings.isAutoUpdateSchema()) {
      new SchemaUpdate(cfg, settings).execute(false, true);
    }
    if (settings.isAutoValidateSchema()) {
      new SchemaValidator(cfg, settings).validate();
    }
    if (settings.isAutoDropSchema()) {
      schemaExport = new SchemaExport(cfg, settings);
    }

    if (settings.getTransactionManagerLookup() != null) {
      log.debug("obtaining JTA TransactionManager");
      transactionManager = settings.getTransactionManagerLookup().getTransactionManager(properties);
    } else {
      if (settings.getTransactionFactory().isTransactionManagerRequired()) {
        throw new HibernateException(
            "The chosen transaction strategy requires access to the JTA TransactionManager");
      }
      transactionManager = null;
    }

    currentSessionContext = buildCurrentSessionContext();

    if (settings.isQueryCacheEnabled()) {
      updateTimestampsCache = new UpdateTimestampsCache(settings, properties);
      queryCache =
          settings
              .getQueryCacheFactory()
              .getQueryCache(null, updateTimestampsCache, settings, properties);
      queryCaches = new HashMap();
      allCacheRegions.put(
          updateTimestampsCache.getRegion().getName(), updateTimestampsCache.getRegion());
      allCacheRegions.put(queryCache.getRegion().getName(), queryCache.getRegion());
    } else {
      updateTimestampsCache = null;
      queryCache = null;
      queryCaches = null;
    }

    // checking for named queries
    if (settings.isNamedQueryStartupCheckingEnabled()) {
      Map errors = checkNamedQueries();
      if (!errors.isEmpty()) {
        Set keys = errors.keySet();
        StringBuffer failingQueries = new StringBuffer("Errors in named queries: ");
        for (Iterator iterator = keys.iterator(); iterator.hasNext(); ) {
          String queryName = (String) iterator.next();
          HibernateException e = (HibernateException) errors.get(queryName);
          failingQueries.append(queryName);
          if (iterator.hasNext()) {
            failingQueries.append(", ");
          }
          log.error("Error in named query: " + queryName, e);
        }
        throw new HibernateException(failingQueries.toString());
      }
    }

    // stats
    getStatistics().setStatisticsEnabled(settings.isStatisticsEnabled());

    // EntityNotFoundDelegate
    EntityNotFoundDelegate entityNotFoundDelegate = cfg.getEntityNotFoundDelegate();
    if (entityNotFoundDelegate == null) {
      entityNotFoundDelegate =
          new EntityNotFoundDelegate() {
            public void handleEntityNotFound(String entityName, Serializable id) {
              throw new ObjectNotFoundException(id, entityName);
            }

            public boolean isEntityNotFoundException(RuntimeException exception) {
              return ObjectNotFoundException.class.isInstance(exception);
            }
          };
    }
    this.entityNotFoundDelegate = entityNotFoundDelegate;

    // this needs to happen after persisters are all ready to go...
    this.fetchProfiles = new HashMap();
    itr = cfg.iterateFetchProfiles();
    while (itr.hasNext()) {
      final org.hibernate.mapping.FetchProfile mappingProfile =
          (org.hibernate.mapping.FetchProfile) itr.next();
      final FetchProfile fetchProfile = new FetchProfile(mappingProfile.getName());
      Iterator fetches = mappingProfile.getFetches().iterator();
      while (fetches.hasNext()) {
        final org.hibernate.mapping.FetchProfile.Fetch mappingFetch =
            (org.hibernate.mapping.FetchProfile.Fetch) fetches.next();
        // resolve the persister owning the fetch
        final String entityName = getImportedClassName(mappingFetch.getEntity());
        final EntityPersister owner =
            (EntityPersister) (entityName == null ? null : entityPersisters.get(entityName));
        if (owner == null) {
          throw new HibernateException(
              "Unable to resolve entity reference ["
                  + mappingFetch.getEntity()
                  + "] in fetch profile ["
                  + fetchProfile.getName()
                  + "]");
        }

        // validate the specified association fetch
        Type associationType = owner.getPropertyType(mappingFetch.getAssociation());
        if (associationType == null || !associationType.isAssociationType()) {
          throw new HibernateException(
              "Fetch profile [" + fetchProfile.getName() + "] specified an invalid association");
        }

        // resolve the style
        final Fetch.Style fetchStyle = Fetch.Style.parse(mappingFetch.getStyle());

        // then construct the fetch instance...
        fetchProfile.addFetch(new Association(owner, mappingFetch.getAssociation()), fetchStyle);
        ((Loadable) owner).registerAffectingFetchProfile(fetchProfile.getName());
      }
      fetchProfiles.put(fetchProfile.getName(), fetchProfile);
    }

    this.observer.sessionFactoryCreated(this);
  }