Package org.hibernate.metamodel.source.hbm

Source Code of org.hibernate.metamodel.source.hbm.AbstractEntityBinder

/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2010, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors.  All third-party contributions are
* distributed under license by Red Hat Inc.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA  02110-1301  USA
*/
package org.hibernate.metamodel.source.hbm;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;

import org.dom4j.Attribute;
import org.dom4j.Element;

import org.hibernate.EntityMode;
import org.hibernate.MappingException;
import org.hibernate.cfg.NamingStrategy;
import org.hibernate.engine.Versioning;
import org.hibernate.internal.util.ReflectHelper;
import org.hibernate.internal.util.StringHelper;
import org.hibernate.mapping.MetaAttribute;
import org.hibernate.mapping.PropertyGeneration;
import org.hibernate.metamodel.binding.AttributeBinding;
import org.hibernate.metamodel.binding.BagBinding;
import org.hibernate.metamodel.binding.EntityBinding;
import org.hibernate.metamodel.binding.PluralAttributeBinding;
import org.hibernate.metamodel.binding.SimpleAttributeBinding;
import org.hibernate.metamodel.domain.Entity;
import org.hibernate.metamodel.domain.Hierarchical;
import org.hibernate.metamodel.domain.PluralAttribute;
import org.hibernate.metamodel.domain.PluralAttributeNature;
import org.hibernate.metamodel.domain.SingularAttribute;
import org.hibernate.metamodel.relational.Column;
import org.hibernate.metamodel.relational.Index;
import org.hibernate.metamodel.relational.Schema;
import org.hibernate.metamodel.relational.SimpleValue;
import org.hibernate.metamodel.relational.Table;
import org.hibernate.metamodel.relational.TableSpecification;
import org.hibernate.metamodel.relational.Tuple;
import org.hibernate.metamodel.relational.UniqueKey;
import org.hibernate.metamodel.relational.Value;
import org.hibernate.metamodel.source.Metadata;
import org.hibernate.metamodel.source.util.DomHelper;

/**
* TODO : javadoc
*
* @author Steve Ebersole
*/
abstract class AbstractEntityBinder {

  protected final HibernateMappingBinder hibernateMappingBinder;
  protected final Map<String, MetaAttribute> entityMetas;
  protected final Schema.Name schemaName;

  AbstractEntityBinder(HibernateMappingBinder hibernateMappingBinder, Element entityElement) {
    this.hibernateMappingBinder = hibernateMappingBinder;

    entityMetas = HbmHelper.extractMetas( entityElement, true, hibernateMappingBinder.getMappingMetas() );

    final Attribute schemaAttribute = entityElement.attribute( "schema" );
    String schemaName = ( schemaAttribute == null )
        ? hibernateMappingBinder.getDefaultSchemaName()
        : schemaAttribute.getValue();

    final Attribute catalogAttribute = entityElement.attribute( "catalog" );
    String catalogName = ( catalogAttribute == null )
        ? hibernateMappingBinder.getDefaultCatalogName()
        : catalogAttribute.getValue();

    this.schemaName = new Schema.Name( schemaName, catalogName );
  }

  protected HibernateXmlBinder getHibernateXmlBinder() {
    return hibernateMappingBinder.getHibernateXmlBinder();
  }

  protected Metadata getMetadata() {
    return hibernateMappingBinder.getHibernateXmlBinder().getMetadata();
  }

  protected NamingStrategy getNamingStrategy() {
    return getMetadata().getNamingStrategy();
  }

  protected void basicEntityBinding(Element node, EntityBinding entityBinding, Hierarchical superType) {
    entityBinding.setMetaAttributes( entityMetas );

    // transfer an explicitly defined lazy attribute
    Attribute lazyNode = node.attribute( "lazy" );
    boolean lazy = ( lazyNode == null )
        ? hibernateMappingBinder.isDefaultLazy()
        : Boolean.valueOf( lazyNode.getValue() );
    // go ahead and set the lazy here, since pojo.proxy can override it.
    entityBinding.setLazy( lazy );

    String entityName = hibernateMappingBinder.extractEntityName( node );
    if ( entityName == null ) {
      throw new MappingException( "Unable to determine entity name" );
    }
    entityBinding.setEntity( new Entity( entityName, superType ) );

    bindPojoRepresentation( node, entityBinding );
    bindDom4jRepresentation( node, entityBinding );
    bindMapRepresentation( node, entityBinding );

    Iterator itr = node.elementIterator( "fetch-profile" );
    while ( itr.hasNext() ) {
      final Element profileElement = ( Element ) itr.next();
      hibernateMappingBinder.parseFetchProfile( profileElement, entityName );
    }

    entityBinding.setDiscriminatorValue( DomHelper.extractAttributeValue( node, "discriminator-value", entityName ) );
    entityBinding.setDynamicUpdate( DomHelper.extractBooleanAttributeValue( node, "dynamic-update", false ) );
    entityBinding.setDynamicInsert( DomHelper.extractBooleanAttributeValue( node, "dynamic-insert", false ) );

    getMetadata().addImport( entityName, entityName );
    if ( hibernateMappingBinder.isAutoImport() ) {
      if ( entityName.indexOf( '.' ) > 0 ) {
        getMetadata().addImport( StringHelper.unqualify( entityName ), entityName );
      }
    }

    final Attribute batchNode = node.attribute( "batch-size" );
    if ( batchNode != null ) {
      entityBinding.setBatchSize( Integer.parseInt( batchNode.getValue() ) );
    }

    final Attribute sbuNode = node.attribute( "select-before-update" );
    if ( sbuNode != null ) {
      entityBinding.setSelectBeforeUpdate( Boolean.valueOf( sbuNode.getValue() ) );
    }

    // OPTIMISTIC LOCK MODE
    Attribute olNode = node.attribute( "optimistic-lock" );
    entityBinding.setOptimisticLockMode( getOptimisticLockMode( olNode ) );


    // PERSISTER
    Attribute persisterNode = node.attribute( "persister" );
    if ( persisterNode != null ) {
      try {
        entityBinding.setEntityPersisterClass(
            ReflectHelper.classForName( persisterNode.getValue() )
        );
      }
      catch (ClassNotFoundException cnfe) {
        throw new MappingException( "Could not find persister class: "
          + persisterNode.getValue() );
      }
    }

    // CUSTOM SQL
    handleCustomSQL( node, entityBinding );

    Iterator tables = node.elementIterator( "synchronize" );
    while ( tables.hasNext() ) {
      entityBinding.addSynchronizedTable( ( (Element) tables.next() ).attributeValue( "table" ) );
    }

    Attribute abstractNode = node.attribute( "abstract" );
    Boolean isAbstract = abstractNode == null
        ? null
            : "true".equals( abstractNode.getValue() )
            ? Boolean.TRUE
                      : "false".equals( abstractNode.getValue() )
                ? Boolean.FALSE
                              : null;
    entityBinding.setAbstract( isAbstract );
  }

  private void bindPojoRepresentation(Element node, EntityBinding entityBinding) {
    String className = hibernateMappingBinder.getClassName( node.attribute( "name" ) );
    String proxyName = hibernateMappingBinder.getClassName( node.attribute( "proxy" ) );

    entityBinding.getEntity().getPojoEntitySpecifics().setClassName( className );

    if ( proxyName != null ) {
      entityBinding.getEntity().getPojoEntitySpecifics().setProxyInterfaceName( proxyName );
      entityBinding.setLazy( true );
    }
    else if ( entityBinding.isLazy() ) {
      entityBinding.getEntity().getPojoEntitySpecifics().setProxyInterfaceName( className );
    }

    Element tuplizer = locateTuplizerDefinition( node, EntityMode.POJO );
    if ( tuplizer != null ) {
      entityBinding.getEntity().getPojoEntitySpecifics().setTuplizerClassName( tuplizer.attributeValue( "class" ) );
    }
  }

  private void bindDom4jRepresentation(Element node, EntityBinding entityBinding) {
    String nodeName = node.attributeValue( "node" );
    if ( nodeName == null ) {
      nodeName = StringHelper.unqualify( entityBinding.getEntity().getName() );
    }
    entityBinding.getEntity().getDom4jEntitySpecifics().setNodeName(nodeName);

    Element tuplizer = locateTuplizerDefinition( node, EntityMode.DOM4J );
    if ( tuplizer != null ) {
      entityBinding.getEntity().getDom4jEntitySpecifics().setTuplizerClassName( tuplizer.attributeValue( "class" ) );
    }
  }

  private void bindMapRepresentation(Element node, EntityBinding entityBinding) {
    Element tuplizer = locateTuplizerDefinition( node, EntityMode.MAP );
    if ( tuplizer != null ) {
      entityBinding.getEntity().getMapEntitySpecifics().setTuplizerClassName( tuplizer.attributeValue( "class" ) );
    }
  }

  /**
   * Locate any explicit tuplizer definition in the metadata, for the given entity-mode.
   *
   * @param container The containing element (representing the entity/component)
   * @param entityMode The entity-mode for which to locate the tuplizer element
   *
   * @return The tuplizer element, or null.
   */
  private static Element locateTuplizerDefinition(Element container, EntityMode entityMode) {
    Iterator itr = container.elementIterator( "tuplizer" );
    while( itr.hasNext() ) {
      final Element tuplizerElem = ( Element ) itr.next();
      if ( entityMode.toString().equals( tuplizerElem.attributeValue( "entity-mode") ) ) {
        return tuplizerElem;
      }
    }
    return null;
  }

  int getOptimisticLockMode(Attribute olAtt) throws MappingException {
    if ( olAtt == null ) {
      return Versioning.OPTIMISTIC_LOCK_VERSION;
    }
    String olMode = olAtt.getValue();
    if ( olMode == null || "version".equals( olMode ) ) {
      return Versioning.OPTIMISTIC_LOCK_VERSION;
    }
    else if ( "dirty".equals( olMode ) ) {
      return Versioning.OPTIMISTIC_LOCK_DIRTY;
    }
    else if ( "all".equals( olMode ) ) {
      return Versioning.OPTIMISTIC_LOCK_ALL;
    }
    else if ( "none".equals( olMode ) ) {
      return Versioning.OPTIMISTIC_LOCK_NONE;
    }
    else {
      throw new MappingException( "Unsupported optimistic-lock style: " + olMode );
    }
  }

  private static void handleCustomSQL(Element entityElement, EntityBinding entityBinding)
      throws MappingException {
    Element element = entityElement.element( "sql-insert" );
    if ( element != null ) {
      boolean callable = HbmHelper.isCallable( element );
      entityBinding.setCustomSqlInsert( element.getTextTrim(), callable, HbmHelper.getResultCheckStyle( element, callable ) );
    }

    element = entityElement.element( "sql-delete" );
    if ( element != null ) {
      boolean callable = HbmHelper.isCallable( element );
      entityBinding.setCustomSqlDelete( element.getTextTrim(), callable, HbmHelper.getResultCheckStyle( element, callable ) );
    }

    element = entityElement.element( "sql-update" );
    if ( element != null ) {
      boolean callable = HbmHelper.isCallable( element );
      entityBinding.setCustomSqlUpdate( element.getTextTrim(), callable, HbmHelper.getResultCheckStyle( element, callable ) );
    }

    element = entityElement.element( "loader" );
    if ( element != null ) {
      entityBinding.setLoaderName( element.attributeValue( "query-ref" ) );
    }
  }

  protected String getClassTableName(
      Element entityElement,
      EntityBinding entityBinding,
      Table denormalizedSuperTable) {
    final String entityName = entityBinding.getEntity().getName();
    final Attribute tableNameNode = entityElement.attribute( "table" );
    String logicalTableName;
    String physicalTableName;
    if ( tableNameNode == null ) {
      logicalTableName = StringHelper.unqualify( entityName );
      physicalTableName = getHibernateXmlBinder().getMetadata().getNamingStrategy().classToTableName( entityName );
    }
    else {
      logicalTableName = tableNameNode.getValue();
      physicalTableName = getHibernateXmlBinder().getMetadata().getNamingStrategy().tableName( logicalTableName );
    }
// todo : find out the purpose of these logical bindings
//      mappings.addTableBinding( schema, catalog, logicalTableName, physicalTableName, denormalizedSuperTable );
    return physicalTableName;
  }

  protected void buildAttributeBindings(Element entityElement, EntityBinding entityBinding) {
    // null = UniqueKey (we are not binding a natural-id mapping)
    // true = mutable, by default properties are mutable
    // true = nullable, by default properties are nullable.
    buildAttributeBindings( entityElement, entityBinding, null, true, true );
  }

  /**
   * This form is essentially used to create natural-id mappings.  But the processing is the same, aside from these
   * extra parameterized values, so we encapsulate it here.
   *
   * @param entityElement
   * @param entityBinding
   * @param uniqueKey
   * @param mutable
   * @param nullable
   */
  protected void buildAttributeBindings(
      Element entityElement,
      EntityBinding entityBinding,
      UniqueKey uniqueKey,
      boolean mutable,
      boolean nullable) {
    final boolean naturalId = uniqueKey != null;

    final String entiytName = entityBinding.getEntity().getName();
    final TableSpecification tabe = entityBinding.getBaseTable();

    AttributeBinding attributeBinding = null;

    Iterator iter = entityElement.elementIterator();
    while ( iter.hasNext() ) {
      final Element subElement = (Element) iter.next();
      final String subElementName = subElement.getName();
      final String propertyName = subElement.attributeValue( "name" );

      if ( "bag".equals( subElementName ) ) {
        BagBinding bagBinding = entityBinding.makeBagAttributeBinding( propertyName );
        bindCollection( subElement, bagBinding, entityBinding, PluralAttributeNature.BAG, propertyName );
        hibernateMappingBinder.getHibernateXmlBinder().getMetadata().addCollection( bagBinding );
        attributeBinding = bagBinding;
      }
      else if ( "idbag".equals( subElementName ) ) {
        BagBinding bagBinding = entityBinding.makeBagAttributeBinding( propertyName );
        bindCollection( subElement, bagBinding, entityBinding, PluralAttributeNature.BAG, propertyName );
        hibernateMappingBinder.getHibernateXmlBinder().getMetadata().addCollection( bagBinding );
        attributeBinding = bagBinding;
        // todo: handle identifier
      }
      else if ( "set".equals( subElementName ) ) {
        BagBinding bagBinding = entityBinding.makeBagAttributeBinding( propertyName );
        bindCollection( subElement, bagBinding, entityBinding, PluralAttributeNature.SET, propertyName );
        hibernateMappingBinder.getHibernateXmlBinder().getMetadata().addCollection( bagBinding );
        attributeBinding = bagBinding;
      }
      else if ( "list".equals( subElementName ) ) {
        BagBinding bagBinding = entityBinding.makeBagAttributeBinding( propertyName );
        bindCollection( subElement, bagBinding, entityBinding, PluralAttributeNature.LIST, propertyName );
        hibernateMappingBinder.getHibernateXmlBinder().getMetadata().addCollection( bagBinding );
        attributeBinding = bagBinding;
        // todo : handle list index
      }
      else if ( "map".equals( subElementName ) ) {
        BagBinding bagBinding = entityBinding.makeBagAttributeBinding( propertyName );
        bindCollection( subElement, bagBinding, entityBinding, PluralAttributeNature.MAP, propertyName );
        hibernateMappingBinder.getHibernateXmlBinder().getMetadata().addCollection( bagBinding );
        attributeBinding = bagBinding;
        // todo : handle map key
      }
      else if ( "many-to-one".equals( subElementName ) ) {
// todo : implement
//        value = new ManyToOne( mappings, table );
//        bindManyToOne( subElement, (ManyToOne) value, propertyName, nullable, mappings );
      }
      else if ( "any".equals( subElementName ) ) {
// todo : implement
//        value = new Any( mappings, table );
//        bindAny( subElement, (Any) value, nullable, mappings );
      }
      else if ( "one-to-one".equals( subElementName ) ) {
// todo : implement
//        value = new OneToOne( mappings, table, persistentClass );
//        bindOneToOne( subElement, (OneToOne) value, propertyName, true, mappings );
      }
      else if ( "property".equals( subElementName ) ) {
        SimpleAttributeBinding binding = entityBinding.makeSimpleAttributeBinding( propertyName );
        bindSimpleAttribute( subElement, binding, entityBinding, propertyName );
        attributeBinding = binding;
      }
      else if ( "component".equals( subElementName )
          || "dynamic-component".equals( subElementName )
          || "properties".equals( subElementName ) ) {
// todo : implement
//        String subpath = StringHelper.qualify( entityName, propertyName );
//        value = new Component( mappings, persistentClass );
//
//        bindComponent(
//            subElement,
//            (Component) value,
//            persistentClass.getClassName(),
//            propertyName,
//            subpath,
//            true,
//            "properties".equals( subElementName ),
//            mappings,
//            inheritedMetas,
//            false
//          );
      }
      else if ( "join".equals( subElementName ) ) {
// todo : implement
//        Join join = new Join();
//        join.setPersistentClass( persistentClass );
//        bindJoin( subElement, join, mappings, inheritedMetas );
//        persistentClass.addJoin( join );
      }
      else if ( "subclass".equals( subElementName ) ) {
// todo : implement
//        handleSubclass( persistentClass, mappings, subElement, inheritedMetas );
      }
      else if ( "joined-subclass".equals( subElementName ) ) {
// todo : implement
//        handleJoinedSubclass( persistentClass, mappings, subElement, inheritedMetas );
      }
      else if ( "union-subclass".equals( subElementName ) ) {
// todo : implement
//        handleUnionSubclass( persistentClass, mappings, subElement, inheritedMetas );
      }
      else if ( "filter".equals( subElementName ) ) {
// todo : implement
//        parseFilter( subElement, entityBinding );
      }
      else if ( "natural-id".equals( subElementName ) ) {
// todo : implement
//        UniqueKey uk = new UniqueKey();
//        uk.setName("_UniqueKey");
//        uk.setTable(table);
//        //by default, natural-ids are "immutable" (constant)
//        boolean mutableId = "true".equals( subElement.attributeValue("mutable") );
//        createClassProperties(
//            subElement,
//            persistentClass,
//            mappings,
//            inheritedMetas,
//            uk,
//            mutableId,
//            false,
//            true
//          );
//        table.addUniqueKey(uk);
      }
      else if ( "query".equals(subElementName) ) {
// todo : implement
//        bindNamedQuery(subElement, persistentClass.getEntityName(), mappings);
      }
      else if ( "sql-query".equals(subElementName) ) {
// todo : implement
//        bindNamedSQLQuery(subElement, persistentClass.getEntityName(), mappings);
      }
      else if ( "resultset".equals(subElementName) ) {
// todo : implement
//        bindResultSetMappingDefinition( subElement, persistentClass.getEntityName(), mappings );
      }

//      if ( value != null ) {
//        Property property = createProperty( value, propertyName, persistentClass
//          .getClassName(), subElement, mappings, inheritedMetas );
//        if ( !mutable ) property.setUpdateable(false);
//        if ( naturalId ) property.setNaturalIdentifier(true);
//        persistentClass.addProperty( property );
//        if ( uniqueKey!=null ) uniqueKey.addColumns( property.getColumnIterator() );
//      }

    }
  }

  protected void bindSimpleAttribute(Element propertyElement, SimpleAttributeBinding attributeBinding, EntityBinding entityBinding, String attributeName) {
    if ( attributeBinding.getAttribute() == null ) {
      // attribute has not been bound yet
      SingularAttribute attribute = entityBinding.getEntity().getOrCreateSingularAttribute( attributeName );
      attributeBinding.setAttribute( attribute );
      basicAttributeBinding( propertyElement, attributeBinding );
    }

    if ( attributeBinding.getValue() == null ) {
      // relational model has not been bound yet
      Value idValue = processValues( propertyElement, entityBinding.getBaseTable(), attributeName );
      attributeBinding.setValue( idValue );
    }
  }

  protected void bindCollection(
      Element collectionElement,
      PluralAttributeBinding collectionBinding,
      EntityBinding entityBinding,
      PluralAttributeNature attributeNature,
      String attributeName) {
    if ( collectionBinding.getAttribute() == null ) {
      // domain model has not been bound yet
      PluralAttribute attribute = entityBinding.getEntity().getOrCreatePluralAttribute( attributeName, attributeNature );
      collectionBinding.setAttribute( attribute );
      basicCollectionBinding( collectionElement, collectionBinding );
    }

    // todo : relational model binding
  }

  protected void basicCollectionBinding(Element collectionElement, PluralAttributeBinding collectionBinding) {
    // todo : implement
  }

//  private static Property createProperty(
//      final Value value,
//          final String propertyName,
//      final String className,
//          final Element subnode,
//          final Mappings mappings,
//      java.util.Map inheritedMetas) throws MappingException {
//
//    if ( StringHelper.isEmpty( propertyName ) ) {
//      throw new MappingException( subnode.getName() + " mapping must defined a name attribute [" + className + "]" );
//    }
//
//    value.setTypeUsingReflection( className, propertyName );
//
//    // this is done here 'cos we might only know the type here (ugly!)
//    // TODO: improve this a lot:
//    if ( value instanceof ToOne ) {
//      ToOne toOne = (ToOne) value;
//      String propertyRef = toOne.getReferencedPropertyName();
//      if ( propertyRef != null ) {
//        mappings.addUniquePropertyReference( toOne.getReferencedEntityName(), propertyRef );
//      }
//    }
//    else if ( value instanceof Collection ) {
//      Collection coll = (Collection) value;
//      String propertyRef = coll.getReferencedPropertyName();
//      // not necessarily a *unique* property reference
//      if ( propertyRef != null ) {
//        mappings.addPropertyReference( coll.getOwnerEntityName(), propertyRef );
//      }
//    }
//
//    value.createForeignKey();
//    Property prop = new Property();
//    prop.setValue( value );
//    bindProperty( subnode, prop, mappings, inheritedMetas );
//    return prop;
//  }

















  protected Value processValues(Element identifierElement, TableSpecification baseTable, String propertyPath) {
    // first boolean (false here) indicates that by default columns are nullable
    // second boolean (true here) indicates that by default column names should be guessed
    return processValues( identifierElement, baseTable, false, true, propertyPath );
  }

  protected Value processValues(
      Element propertyElement,
      TableSpecification table,
      boolean isNullableByDefault,
      boolean autoColumnCreation,
      String propertyPath) {
    final UniqueKeyBinder propertyUniqueKeyBinder = new UniqueKeyBinder( propertyElement.attribute( "unique-key" ), table );
    final IndexBinder propertyIndexBinder = new IndexBinder( propertyElement.attribute( "index" ), table );

    final Attribute columnAttribute = propertyElement.attribute( "column" );

    if ( columnAttribute == null ) {
      SimpleValue value = null;
      Tuple tuple = null;
      final Iterator valueElements = propertyElement.elementIterator();
      while ( valueElements.hasNext() ) {
        if ( value != null ) {
          if ( tuple == null ) {
            tuple = table.createTuple( "[" + propertyPath + "]" );
          }
          tuple.addValue( value );
        }

        final Element valueElement = (Element) valueElements.next();
        if ( "column".equals( valueElement.getName() ) ) {
          final Element columnElement = valueElement;
          final String explicitName = columnElement.attributeValue( "name" );
          final String logicalColumnName = getNamingStrategy().logicalColumnName( explicitName, propertyPath );
          final String columnName = getNamingStrategy().columnName( explicitName );
// todo : find out the purpose of these logical bindings
//        mappings.addColumnBinding( logicalColumnName, column, table );
          Column column = table.createColumn( columnName );
          value = column;
          basicColumnBinding( columnElement, column, isNullableByDefault );

          propertyUniqueKeyBinder.bindColumn( column );
          propertyIndexBinder.bindColumn( column );
          new UniqueKeyBinder( columnElement.attribute( "unique-key" ), table ).bindColumn( column );
          new IndexBinder( columnElement.attribute( "index" ), table ).bindColumn( column );
        }
        else if ( "formula".equals( valueElement.getName() ) ) {
          value = table.createDerivedValue( valueElement.getTextTrim() );
        }
      }

// todo : logical 1-1 handling
//      final Attribute uniqueAttribute = node.attribute( "unique" );
//      if ( uniqueAttribute != null
//          && "true".equals( uniqueAttribute.getValue() )
//          && ManyToOne.class.isInstance( simpleValue ) ) {
//        ( (ManyToOne) simpleValue ).markAsLogicalOneToOne();
//      }

      if ( tuple != null ) {
        return tuple;
      }
      else if ( value != null ) {
        return value;
      }
      else if ( autoColumnCreation  ) {
        final String columnName = getNamingStrategy().propertyToColumnName( propertyPath );
        final String logicalColumnName = getNamingStrategy().logicalColumnName( null, propertyPath );
// todo : find out the purpose of these logical bindings
//        mappings.addColumnBinding( logicalColumnName, column, table );
        Column column = table.createColumn( columnName );
        basicColumnBinding( propertyElement, column, isNullableByDefault );
        propertyUniqueKeyBinder.bindColumn( column );
        propertyIndexBinder.bindColumn( column );
        return column;
      }
    }

    if ( propertyElement.elementIterator( "column" ).hasNext() ) {
      throw new MappingException( "column attribute may not be used together with <column> subelement" );
    }

    if ( propertyElement.elementIterator( "formula" ).hasNext() ) {
      throw new MappingException( "column attribute may not be used together with <formula> subelement" );
    }

    final String explicitName = columnAttribute.getValue();
    final String logicalColumnName = getNamingStrategy().logicalColumnName( explicitName, propertyPath );
    final String columnName = getNamingStrategy().columnName( explicitName );
// todo : find out the purpose of these logical bindings
//    mappings.addColumnBinding( logicalColumnName, column, table );
    Column column = table.createColumn( columnName );
    basicColumnBinding( propertyElement, column, isNullableByDefault );
    propertyUniqueKeyBinder.bindColumn( column );
    propertyIndexBinder.bindColumn( column );
    return column;
  }

  protected static class UniqueKeyBinder {
    private final List<UniqueKey> uniqueKeys;

    UniqueKeyBinder(Attribute uniqueKeyAttribute, TableSpecification table) {
      if ( uniqueKeyAttribute == null ) {
        uniqueKeys = Collections.emptyList();
      }
      else {
        uniqueKeys = new ArrayList<UniqueKey>();
        StringTokenizer uniqueKeyNames = new StringTokenizer( uniqueKeyAttribute.getValue(), ", " );
        while ( uniqueKeyNames.hasMoreTokens() ) {
          uniqueKeys.add( table.getOrCreateUniqueKey( uniqueKeyNames.nextToken() ) );
        }
      }
    }

    void bindColumn(Column column) {
      for ( UniqueKey uniqueKey : uniqueKeys ) {
        uniqueKey.addColumn( column );
      }
    }
  }

  protected static class IndexBinder {
    private final List<Index> indexes;

    IndexBinder(Attribute indexAttribute, TableSpecification table) {
      if ( indexAttribute == null ) {
        indexes = Collections.emptyList();
      }
      else {
        indexes = new ArrayList<Index>();
        StringTokenizer indexNames = new StringTokenizer( indexAttribute.getValue(), ", " );
        while ( indexNames.hasMoreTokens() ) {
          indexes.add( table.getOrCreateIndex( indexNames.nextToken() ) );
        }
      }
    }

    void bindColumn(Column column) {
      for ( Index index : indexes ) {
        index.addColumn( column );
      }
    }
  }

  public static void basicColumnBinding(Element node, Column column, boolean isNullable) throws MappingException {
    Attribute lengthNode = node.attribute( "length" );
    if ( lengthNode != null ) {
      column.getSize().setLength( Integer.parseInt( lengthNode.getValue() ) );
    }
    Attribute scalNode = node.attribute( "scale" );
    if ( scalNode != null ) {
      column.getSize().setScale( Integer.parseInt( scalNode.getValue() ) );
    }
    Attribute precNode = node.attribute( "precision" );
    if ( precNode != null ) {
      column.getSize().setPrecision( Integer.parseInt( precNode.getValue() ) );
    }

    Attribute nullNode = node.attribute( "not-null" );
    column.setNullable( nullNode == null ? isNullable : nullNode.getValue().equals( "false" ) );

    Attribute unqNode = node.attribute( "unique" );
    if ( unqNode != null ) {
      column.setUnique( unqNode.getValue().equals( "true" ) );
    }

    column.setCheckCondition( node.attributeValue( "check" ) );
    column.setDefaultValue( node.attributeValue( "default" ) );

    Attribute typeNode = node.attribute( "sql-type" );
    if ( typeNode != null ) column.setSqlType( typeNode.getValue() );

    String customWrite = node.attributeValue( "write" );
    if(customWrite != null && !customWrite.matches("[^?]*\\?[^?]*")) {
      throw new MappingException("write expression must contain exactly one value placeholder ('?') character");
    }
    column.setWriteFragment( customWrite );
    column.setReadFragment( node.attributeValue( "read" ) );

    Element comment = node.element("comment");
    if ( comment != null ) {
      column.setComment( comment.getTextTrim() );
    }
  }

  protected void basicAttributeBinding(Element propertyElement, SimpleAttributeBinding valueBinding) {
    Attribute typeAttribute = propertyElement.attribute( "type" );
    if ( typeAttribute != null ) {
      valueBinding.getHibernateTypeDescriptor().setTypeName( typeAttribute.getValue() );
    }

    valueBinding.setMetaAttributes( HbmHelper.extractMetas( propertyElement, entityMetas ) );

    final String propertyName = valueBinding.getAttribute().getName();
    final String explicitNodename = propertyElement.attributeValue( "node" );
    final String nodeName = explicitNodename != null ? explicitNodename : propertyName;
    valueBinding.setNodeName( nodeName );

    final Attribute accessNode = propertyElement.attribute( "access" );
    if ( accessNode != null ) {
      valueBinding.setPropertyAccessorName( accessNode.getValue() );
    }
    else if ( propertyElement.getName().equals( "properties" ) ) {
      valueBinding.setPropertyAccessorName( "embedded" );
    }
    else {
      valueBinding.setPropertyAccessorName( hibernateMappingBinder.getDefaultAccess() );
    }

    final String explicitCascade = propertyElement.attributeValue( "cascade" );
    final String cascade = StringHelper.isNotEmpty( explicitCascade ) ? explicitCascade : hibernateMappingBinder.getDefaultCascade();
    valueBinding.setCascade( cascade );

    final Attribute updateAttribute = propertyElement.attribute( "update" );
    valueBinding.setUpdateable( updateAttribute == null || "true".equals( updateAttribute.getValue() ) );

    final Attribute insertAttribute = propertyElement.attribute( "insert" );
    valueBinding.setInsertable( insertAttribute == null || "true".equals( insertAttribute.getValue() ) );

    final Attribute optimisticLockAttribute = propertyElement.attribute( "optimistic-lock" );
    valueBinding.setOptimisticLockable( optimisticLockAttribute == null || "true".equals( optimisticLockAttribute.getValue() ) );

    final Attribute generatedAttribute= propertyElement.attribute( "generated" );
        final String generationName = generatedAttribute == null ? null : generatedAttribute.getValue();
        final PropertyGeneration generation = PropertyGeneration.parse( generationName );
    valueBinding.setGeneration( generation );

        if ( generation == PropertyGeneration.ALWAYS || generation == PropertyGeneration.INSERT ) {
          // generated properties can *never* be insertable...
          if ( valueBinding.isInsertable() ) {
            if ( insertAttribute == null ) {
              // insertable simply because the user did not specify anything; just override it
          valueBinding.setInsertable( false );
            }
            else {
              // the user specifically supplied insert="true", which constitutes an illegal combo
          throw new MappingException(
              "cannot specify both insert=\"true\" and generated=\"" + generation.getName() +
              "\" for property: " +
              propertyName
          );
            }
          }

          // properties generated on update can never be updateable...
          if ( valueBinding.isUpdateable() && generation == PropertyGeneration.ALWAYS ) {
            if ( updateAttribute == null ) {
              // updateable only because the user did not specify
              // anything; just override it
              valueBinding.setUpdateable( false );
            }
            else {
              // the user specifically supplied update="true",
              // which constitutes an illegal combo
          throw new MappingException(
              "cannot specify both update=\"true\" and generated=\"" + generation.getName() +
              "\" for property: " +
              propertyName
          );
            }
          }
        }

    boolean isLazyable = "property".equals( propertyElement.getName() )
        || "component".equals( propertyElement.getName() )
        || "many-to-one".equals( propertyElement.getName() )
        || "one-to-one".equals( propertyElement.getName() )
        || "any".equals( propertyElement.getName() );
    if ( isLazyable ) {
      Attribute lazyNode = propertyElement.attribute( "lazy" );
      valueBinding.setLazy( lazyNode != null && "true".equals( lazyNode.getValue() ) );
    }

  }
}
TOP

Related Classes of org.hibernate.metamodel.source.hbm.AbstractEntityBinder

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.