private void integrate(
     SessionFactoryServiceRegistry serviceRegistry, SessionFactoryImplementor sessionFactory) {
   if (!sessionFactory.getSettings().isAutoEvictCollectionCache()) {
     // feature is disabled
     return;
   }
   if (!sessionFactory.getSettings().isSecondLevelCacheEnabled()) {
     // Nothing to do, if caching is disabled
     return;
   }
   EventListenerRegistry eventListenerRegistry =
       serviceRegistry.getService(EventListenerRegistry.class);
   eventListenerRegistry.appendListeners(EventType.POST_INSERT, this);
   eventListenerRegistry.appendListeners(EventType.POST_DELETE, this);
   eventListenerRegistry.appendListeners(EventType.POST_UPDATE, this);
 }
 @Override
 @SuppressWarnings("unchecked")
 public <T> T unwrap(Class<T> cls) {
   if (RegionFactory.class.isAssignableFrom(cls)) {
     return (T) sessionFactory.getSettings().getRegionFactory();
   }
   if (org.hibernate.Cache.class.isAssignableFrom(cls)) {
     return (T) sessionFactory.getCache();
   }
   throw new PersistenceException("Hibernate cannot unwrap Cache as " + cls.getName());
 }
  @Test
  public void testRedeployment() throws Exception {
    addEntityCheckCache(sessionFactory());
    sessionFactory().close();
    bindToJndi = false;

    SessionFactoryImplementor sessionFactory =
        (SessionFactoryImplementor) configuration().buildSessionFactory(serviceRegistry());
    addEntityCheckCache(sessionFactory);
    JndiInfinispanRegionFactory regionFactory =
        (JndiInfinispanRegionFactory) sessionFactory.getSettings().getRegionFactory();
    Cache cache =
        regionFactory
            .getCacheManager()
            .getCache("org.hibernate.test.cache.infinispan.functional.Item");
    assertEquals(ComponentStatus.RUNNING, cache.getStatus());
  }
 /*  77:    */
 /*  78:    */ protected String generateLockString(int lockTimeout) /*  79:    */ {
   /*  80:122 */ SessionFactoryImplementor factory = getLockable().getFactory();
   /*  81:123 */ LockOptions lockOptions = new LockOptions(getLockMode());
   /*  82:124 */ lockOptions.setTimeOut(lockTimeout);
   /*  83:125 */ SimpleSelect select =
       new SimpleSelect(factory.getDialect())
           .setLockOptions(lockOptions)
           .setTableName(getLockable().getRootTableName())
           .addColumn(getLockable().getRootTableIdentifierColumnNames()[0])
           .addCondition(getLockable().getRootTableIdentifierColumnNames(), "=?");
   /*  84:130 */ if (getLockable().isVersioned()) {
     /*  85:131 */ select.addCondition(getLockable().getVersionColumnName(), "=?");
     /*  86:    */ }
   /*  87:133 */ if (factory.getSettings().isCommentsEnabled()) {
     /*  88:134 */ select.setComment(getLockMode() + " lock " + getLockable().getEntityName());
     /*  89:    */ }
   /*  90:136 */ return select.toStatementString();
   /*  91:    */ }
 protected String generateLockString(int lockTimeout) {
   SessionFactoryImplementor factory = getLockable().getFactory();
   LockOptions lockOptions = new LockOptions(getLockMode());
   lockOptions.setTimeOut(lockTimeout);
   SimpleSelect select =
       new SimpleSelect(factory.getDialect())
           .setLockOptions(lockOptions)
           .setTableName(getLockable().getRootTableName())
           .addColumn(getLockable().getRootTableIdentifierColumnNames()[0])
           .addCondition(getLockable().getRootTableIdentifierColumnNames(), "=?");
   if (getLockable().isVersioned()) {
     select.addCondition(getLockable().getVersionColumnName(), "=?");
   }
   if (factory.getSettings().isCommentsEnabled()) {
     select.setComment(getLockMode() + " lock " + getLockable().getEntityName());
   }
   return select.toStatementString();
 }
  OgmEntityPersister(
      final PersistentClass persistentClass,
      final EntityRegionAccessStrategy cacheAccessStrategy,
      final NaturalIdRegionAccessStrategy naturalIdRegionAccessStrategy,
      final SessionFactoryImplementor factory,
      final Mapping mapping,
      final EntityDiscriminator discriminator)
      throws HibernateException {
    super(persistentClass, cacheAccessStrategy, naturalIdRegionAccessStrategy, factory);
    if (log.isTraceEnabled()) {
      log.tracef("Creating OgmEntityPersister for %s", persistentClass.getClassName());
    }
    ServiceRegistryImplementor serviceRegistry = factory.getServiceRegistry();
    this.gridDialect = serviceRegistry.getService(GridDialect.class);
    this.optionsService = serviceRegistry.getService(OptionsService.class);

    tableName =
        persistentClass
            .getTable()
            .getQualifiedName(
                factory.getDialect(),
                factory.getSettings().getDefaultCatalogName(),
                factory.getSettings().getDefaultSchemaName());

    this.discriminator = discriminator;

    // SPACES
    // TODO: i'm not sure, but perhaps we should exclude
    //      abstract denormalized tables?

    int spacesSize = 1 + persistentClass.getSynchronizedTables().size();
    spaces = new String[spacesSize];
    spaces[0] = tableName;
    @SuppressWarnings("unchecked")
    Iterator<String> syncTablesIter = persistentClass.getSynchronizedTables().iterator();
    for (int i = 1; i < spacesSize; i++) {
      spaces[i] = syncTablesIter.next();
    }

    HashSet<String> subclassTables = new HashSet<String>();
    Iterator<Table> tableIter = persistentClass.getSubclassTableClosureIterator();
    while (tableIter.hasNext()) {
      Table table = tableIter.next();
      subclassTables.add(
          table.getQualifiedName(
              factory.getDialect(),
              factory.getSettings().getDefaultCatalogName(),
              factory.getSettings().getDefaultSchemaName()));
    }
    subclassSpaces = ArrayHelper.toStringArray(subclassTables);

    if (isMultiTable()) {
      int idColumnSpan = getIdentifierColumnSpan();
      ArrayList<String> tableNames = new ArrayList<String>();
      ArrayList<String[]> keyColumns = new ArrayList<String[]>();
      if (!isAbstract()) {
        tableNames.add(tableName);
        keyColumns.add(getIdentifierColumnNames());
      }
      @SuppressWarnings("unchecked")
      Iterator<Table> iter = persistentClass.getSubclassTableClosureIterator();
      while (iter.hasNext()) {
        Table tab = iter.next();
        if (!tab.isAbstractUnionTable()) {
          String tableName =
              tab.getQualifiedName(
                  factory.getDialect(),
                  factory.getSettings().getDefaultCatalogName(),
                  factory.getSettings().getDefaultSchemaName());
          tableNames.add(tableName);
          String[] key = new String[idColumnSpan];
          @SuppressWarnings("unchecked")
          Iterator<Column> citer = tab.getPrimaryKey().getColumnIterator();
          for (int k = 0; k < idColumnSpan; k++) {
            key[k] = citer.next().getQuotedName(factory.getDialect());
          }
          keyColumns.add(key);
        }
      }

      constraintOrderedTableNames = ArrayHelper.toStringArray(tableNames);
      constraintOrderedKeyColumnNames = ArrayHelper.to2DStringArray(keyColumns);
    } else {
      constraintOrderedTableNames = new String[] {tableName};
      constraintOrderedKeyColumnNames = new String[][] {getIdentifierColumnNames()};
    }

    initPropertyPaths(mapping);

    // Grid related metadata
    TypeTranslator typeTranslator = serviceRegistry.getService(TypeTranslator.class);
    final Type[] types = getPropertyTypes();
    final int length = types.length;
    gridPropertyTypes = new GridType[length];
    for (int index = 0; index < length; index++) {
      gridPropertyTypes[index] = typeTranslator.getType(types[index]);
    }
    gridVersionType = typeTranslator.getType(getVersionType());
    gridIdentifierType = typeTranslator.getType(getIdentifierType());
    List<String> columnNames = new ArrayList<String>();
    for (int propertyCount = 0; propertyCount < this.getPropertySpan(); propertyCount++) {
      String[] property = this.getPropertyColumnNames(propertyCount);
      for (int columnCount = 0; columnCount < property.length; columnCount++) {
        columnNames.add(property[columnCount]);
      }
    }
    if (discriminator.getColumnName() != null) {
      columnNames.add(discriminator.getColumnName());
    }
    this.tupleContext =
        new TupleContext(columnNames, optionsService.context().getEntityOptions(getMappedClass()));
    jpaEntityName = persistentClass.getJpaEntityName();
    entityKeyMetadata = new EntityKeyMetadata(getTableName(), getIdentifierColumnNames());
    // load unique key association key metadata
    associationKeyMetadataPerPropertyName = new HashMap<String, AssociationKeyMetadata>();
    initAssociationKeyMetadata();
    initCustomSQLStrings();
  }
  // TODO: should "record" how many properties we have reffered to - and if we
  //       don't get'em'all we throw an exception! Way better than trial and error ;)
  private String substituteBrackets(String sqlQuery) throws QueryException {

    StringBuffer result = new StringBuffer(sqlQuery.length() + 20);
    int left, right;

    // replace {....} with corresponding column aliases
    for (int curr = 0; curr < sqlQuery.length(); curr = right + 1) {
      if ((left = sqlQuery.indexOf('{', curr)) < 0) {
        // No additional open braces found in the string, append the
        // rest of the string in its entirty and quit this loop
        result.append(sqlQuery.substring(curr));
        break;
      }

      // apend everything up until the next encountered open brace
      result.append(sqlQuery.substring(curr, left));

      if ((right = sqlQuery.indexOf('}', left + 1)) < 0) {
        throw new QueryException("Unmatched braces for alias path", sqlQuery);
      }

      final String aliasPath = sqlQuery.substring(left + 1, right);
      boolean isPlaceholder = aliasPath.startsWith(HIBERNATE_PLACEHOLDER_PREFIX);

      if (isPlaceholder) {
        // Domain replacement
        if (DOMAIN_PLACEHOLDER.equals(aliasPath)) {
          final String catalogName = factory.getSettings().getDefaultCatalogName();
          if (catalogName != null) {
            result.append(catalogName);
            result.append(".");
          }
          final String schemaName = factory.getSettings().getDefaultSchemaName();
          if (schemaName != null) {
            result.append(schemaName);
            result.append(".");
          }
        }
        // Schema replacement
        else if (SCHEMA_PLACEHOLDER.equals(aliasPath)) {
          final String schemaName = factory.getSettings().getDefaultSchemaName();
          if (schemaName != null) {
            result.append(schemaName);
            result.append(".");
          }
        }
        // Catalog replacement
        else if (CATALOG_PLACEHOLDER.equals(aliasPath)) {
          final String catalogName = factory.getSettings().getDefaultCatalogName();
          if (catalogName != null) {
            result.append(catalogName);
            result.append(".");
          }
        } else {
          throw new QueryException("Unknown placeholder ", aliasPath);
        }
      } else {
        int firstDot = aliasPath.indexOf('.');
        if (firstDot == -1) {
          if (context.isEntityAlias(aliasPath)) {
            // it is a simple table alias {foo}
            result.append(aliasPath);
            aliasesFound++;
          } else {
            // passing through anything we do not know : to support jdbc escape sequences HB-898
            result.append('{').append(aliasPath).append('}');
          }
        } else {
          final String aliasName = aliasPath.substring(0, firstDot);
          if (context.isCollectionAlias(aliasName)) {
            // The current alias is referencing the collection to be eagerly fetched
            String propertyName = aliasPath.substring(firstDot + 1);
            result.append(resolveCollectionProperties(aliasName, propertyName));
            aliasesFound++;
          } else if (context.isEntityAlias(aliasName)) {
            // it is a property reference {foo.bar}
            String propertyName = aliasPath.substring(firstDot + 1);
            result.append(resolveProperties(aliasName, propertyName));
            aliasesFound++;
          } else {
            // passing through anything we do not know : to support jdbc escape sequences HB-898
            result.append('{').append(aliasPath).append('}');
          }
        }
      }
    }

    // Possibly handle :something parameters for the query ?

    return result.toString();
  }
  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 EntityMetamodel(EntityBinding entityBinding, SessionFactoryImplementor sessionFactory) {
    this.sessionFactory = sessionFactory;

    name = entityBinding.getEntity().getName();

    rootName = entityBinding.getHierarchyDetails().getRootEntityBinding().getEntity().getName();
    entityType = sessionFactory.getTypeResolver().getTypeFactory().manyToOne(name);

    identifierProperty =
        PropertyFactory.buildIdentifierProperty(
            entityBinding, sessionFactory.getIdentifierGenerator(rootName));

    versioned = entityBinding.isVersioned();

    boolean hasPojoRepresentation = false;
    Class<?> mappedClass = null;
    Class<?> proxyInterfaceClass = null;
    if (entityBinding.getEntity().getClassReferenceUnresolved() != null) {
      hasPojoRepresentation = true;
      mappedClass = entityBinding.getEntity().getClassReference();
      proxyInterfaceClass = entityBinding.getProxyInterfaceType().getValue();
    }
    instrumentationMetadata =
        Environment.getBytecodeProvider().getEntityInstrumentationMetadata(mappedClass);

    boolean hasLazy = false;

    // TODO: Fix after HHH-6337 is fixed; for now assume entityBinding is the root binding
    BasicAttributeBinding rootEntityIdentifier =
        entityBinding.getHierarchyDetails().getEntityIdentifier().getValueBinding();
    // entityBinding.getAttributeClosureSpan() includes the identifier binding;
    // "properties" here excludes the ID, so subtract 1 if the identifier binding is non-null
    propertySpan =
        rootEntityIdentifier == null
            ? entityBinding.getAttributeBindingClosureSpan()
            : entityBinding.getAttributeBindingClosureSpan() - 1;

    properties = new StandardProperty[propertySpan];
    List naturalIdNumbers = new ArrayList();
    // temporary ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    propertyNames = new String[propertySpan];
    propertyTypes = new Type[propertySpan];
    propertyUpdateability = new boolean[propertySpan];
    propertyInsertability = new boolean[propertySpan];
    insertInclusions = new ValueInclusion[propertySpan];
    updateInclusions = new ValueInclusion[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];
    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

    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;

    for (AttributeBinding attributeBinding : entityBinding.getAttributeBindingClosure()) {
      if (attributeBinding == rootEntityIdentifier) {
        // skip the identifier attribute binding
        continue;
      }

      if (attributeBinding == entityBinding.getHierarchyDetails().getVersioningAttributeBinding()) {
        tempVersionProperty = i;
        properties[i] =
            PropertyFactory.buildVersionProperty(
                entityBinding.getHierarchyDetails().getVersioningAttributeBinding(),
                instrumentationMetadata.isInstrumented());
      } else {
        properties[i] =
            PropertyFactory.buildStandardProperty(
                attributeBinding, instrumentationMetadata.isInstrumented());
      }

      // TODO: fix when natural IDs are added (HHH-6354)
      // if ( attributeBinding.isNaturalIdentifier() ) {
      //	naturalIdNumbers.add( i );
      //	if ( attributeBinding.isUpdateable() ) {
      //		foundUpdateableNaturalIdProperty = true;
      //	}
      // }

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

      // temporary ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
      boolean lazy = attributeBinding.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();
      insertInclusions[i] = determineInsertValueGenerationType(attributeBinding, properties[i]);
      updateInclusions[i] = determineUpdateValueGenerationType(attributeBinding, properties[i]);
      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();
      // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

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

      if (insertInclusions[i] != ValueInclusion.NONE) {
        foundInsertGeneratedValue = true;
      }

      if (updateInclusions[i] != ValueInclusion.NONE) {
        foundUpdateGeneratedValue = true;
      }

      mapPropertyToIndex(attributeBinding.getAttribute(), i);
      i++;
    }

    if (naturalIdNumbers.size() == 0) {
      naturalIdPropertyNumbers = null;
      hasImmutableNaturalId = false;
      hasCacheableNaturalId = false;
    } else {
      naturalIdPropertyNumbers = ArrayHelper.toIntArray(naturalIdNumbers);
      hasImmutableNaturalId = !foundUpdateableNaturalIdProperty;
      hasCacheableNaturalId = false; // See previous TODO and HHH-6354
    }

    hasInsertGeneratedValues = foundInsertGeneratedValue;
    hasUpdateGeneratedValues = foundUpdateGeneratedValue;

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

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

    hasSubclasses = entityBinding.hasSubEntityBindings();
    polymorphic = entityBinding.isPolymorphic();

    explicitPolymorphism = entityBinding.getHierarchyDetails().isExplicitPolymorphism();
    inherited = !entityBinding.isRoot();
    superclass = inherited ? entityBinding.getEntity().getSuperType().getName() : null;

    optimisticLockStyle = entityBinding.getHierarchyDetails().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;

    for (EntityBinding subEntityBinding : entityBinding.getPostOrderSubEntityBindingClosure()) {
      subclassEntityNames.add(subEntityBinding.getEntity().getName());
      if (subEntityBinding.getEntity().getClassReference() != null) {
        entityNameByInheritenceClassMap.put(
            subEntityBinding.getEntity().getClassReference(),
            subEntityBinding.getEntity().getName());
      }
    }
    subclassEntityNames.add(name);
    if (mappedClass != null) {
      entityNameByInheritenceClassMap.put(mappedClass, name);
    }

    entityMode = hasPojoRepresentation ? EntityMode.POJO : EntityMode.MAP;
    final EntityTuplizerFactory entityTuplizerFactory =
        sessionFactory.getSettings().getEntityTuplizerFactory();
    Class<? extends EntityTuplizer> tuplizerClass = entityBinding.getCustomEntityTuplizerClass();

    if (tuplizerClass == null) {
      entityTuplizer =
          entityTuplizerFactory.constructDefaultTuplizer(entityMode, this, entityBinding);
    } else {
      entityTuplizer = entityTuplizerFactory.constructTuplizer(tuplizerClass, this, entityBinding);
    }
  }
 @Override
 public Settings getSettings() {
   return delegate.getSettings();
 }