Package org.hibernate.cfg.annotations

Source Code of org.hibernate.cfg.annotations.TableBinder$AssociationTableNameSource

/*
* 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.cfg.annotations;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import javax.persistence.UniqueConstraint;
import org.hibernate.AnnotationException;
import org.hibernate.AssertionFailure;
import org.hibernate.HibernateLogger;
import org.hibernate.annotations.Index;
import org.hibernate.cfg.BinderHelper;
import org.hibernate.cfg.Ejb3JoinColumn;
import org.hibernate.cfg.IndexOrUniqueKeySecondPass;
import org.hibernate.cfg.Mappings;
import org.hibernate.cfg.NamingStrategy;
import org.hibernate.cfg.ObjectNameNormalizer;
import org.hibernate.cfg.ObjectNameSource;
import org.hibernate.cfg.UniqueConstraintHolder;
import org.hibernate.internal.util.StringHelper;
import org.hibernate.internal.util.collections.CollectionHelper;
import org.hibernate.mapping.Collection;
import org.hibernate.mapping.Column;
import org.hibernate.mapping.DependantValue;
import org.hibernate.mapping.JoinedSubclass;
import org.hibernate.mapping.PersistentClass;
import org.hibernate.mapping.Property;
import org.hibernate.mapping.SimpleValue;
import org.hibernate.mapping.Table;
import org.hibernate.mapping.ToOne;
import org.hibernate.mapping.Value;
import org.jboss.logging.Logger;

/**
* Table related operations
*
* @author Emmanuel Bernard
*/
@SuppressWarnings("unchecked")
public class TableBinder {
  //TODO move it to a getter/setter strategy
    private static final HibernateLogger LOG = Logger.getMessageLogger(HibernateLogger.class, TableBinder.class.getName());

  private String schema;
  private String catalog;
  private String name;
  private boolean isAbstract;
  private List<UniqueConstraintHolder> uniqueConstraints;
//  private List<String[]> uniqueConstraints;
  String constraints;
  Table denormalizedSuperTable;
  Mappings mappings;
  private String ownerEntityTable;
  private String associatedEntityTable;
  private String propertyName;
  private String ownerEntity;
  private String associatedEntity;
  private boolean isJPA2ElementCollection;

  public void setSchema(String schema) {
    this.schema = schema;
  }

  public void setCatalog(String catalog) {
    this.catalog = catalog;
  }

  public String getName() {
    return name;
  }

  public void setName(String name) {
    this.name = name;
  }

  public void setAbstract(boolean anAbstract) {
    isAbstract = anAbstract;
  }

  public void setUniqueConstraints(UniqueConstraint[] uniqueConstraints) {
    this.uniqueConstraints = TableBinder.buildUniqueConstraintHolders( uniqueConstraints );
  }

  public void setConstraints(String constraints) {
    this.constraints = constraints;
  }

  public void setDenormalizedSuperTable(Table denormalizedSuperTable) {
    this.denormalizedSuperTable = denormalizedSuperTable;
  }

  public void setMappings(Mappings mappings) {
    this.mappings = mappings;
  }

  public void setJPA2ElementCollection(boolean isJPA2ElementCollection) {
    this.isJPA2ElementCollection = isJPA2ElementCollection;
  }

  private static class AssociationTableNameSource implements ObjectNameSource {
    private final String explicitName;
    private final String logicalName;

    private AssociationTableNameSource(String explicitName, String logicalName) {
      this.explicitName = explicitName;
      this.logicalName = logicalName;
    }

    public String getExplicitName() {
      return explicitName;
    }

    public String getLogicalName() {
      return logicalName;
    }
  }

  // only bind association table currently
  public Table bind() {
    //logicalName only accurate for assoc table...
    final String unquotedOwnerTable = StringHelper.unquote( ownerEntityTable );
    final String unquotedAssocTable = StringHelper.unquote( associatedEntityTable );

    //@ElementCollection use ownerEntity_property instead of the cleaner ownerTableName_property
    // ownerEntity can be null when the table name is explicitly set
    final String ownerObjectName = isJPA2ElementCollection && ownerEntity != null ?
        StringHelper.unqualify( ownerEntity ) : unquotedOwnerTable;
    final ObjectNameSource nameSource = buildNameContext(
        ownerObjectName,
        unquotedAssocTable );

    final boolean ownerEntityTableQuoted = StringHelper.isQuoted( ownerEntityTable );
    final boolean associatedEntityTableQuoted = StringHelper.isQuoted( associatedEntityTable );
    final ObjectNameNormalizer.NamingStrategyHelper namingStrategyHelper = new ObjectNameNormalizer.NamingStrategyHelper() {
      public String determineImplicitName(NamingStrategy strategy) {

        final String strategyResult = strategy.collectionTableName(
            ownerEntity,
            ownerObjectName,
            associatedEntity,
            unquotedAssocTable,
            propertyName

        );
        return ownerEntityTableQuoted || associatedEntityTableQuoted
            ? StringHelper.quote( strategyResult )
            : strategyResult;
      }

      public String handleExplicitName(NamingStrategy strategy, String name) {
        return strategy.tableName( name );
      }
    };

    return buildAndFillTable(
        schema,
        catalog,
        nameSource,
        namingStrategyHelper,
        isAbstract,
        uniqueConstraints,
        constraints,
        denormalizedSuperTable,
        mappings,
        null
    );
  }

  private ObjectNameSource buildNameContext(String unquotedOwnerTable, String unquotedAssocTable) {
    String logicalName = mappings.getNamingStrategy().logicalCollectionTableName(
        name,
        unquotedOwnerTable,
        unquotedAssocTable,
        propertyName
    );
    if ( StringHelper.isQuoted( ownerEntityTable ) || StringHelper.isQuoted( associatedEntityTable ) ) {
      logicalName = StringHelper.quote( logicalName );
    }

    return new AssociationTableNameSource( name, logicalName );
  }

  public static Table buildAndFillTable(
      String schema,
      String catalog,
      ObjectNameSource nameSource,
      ObjectNameNormalizer.NamingStrategyHelper namingStrategyHelper,
      boolean isAbstract,
      List<UniqueConstraintHolder> uniqueConstraints,
      String constraints,
      Table denormalizedSuperTable,
      Mappings mappings,
      String subselect) {
    schema = BinderHelper.isEmptyAnnotationValue( schema ) ? mappings.getSchemaName() : schema;
    catalog = BinderHelper.isEmptyAnnotationValue( catalog ) ? mappings.getCatalogName() : catalog;

    String realTableName = mappings.getObjectNameNormalizer().normalizeDatabaseIdentifier(
        nameSource.getExplicitName(),
        namingStrategyHelper
    );

    final Table table;
    if ( denormalizedSuperTable != null ) {
      table = mappings.addDenormalizedTable(
          schema,
          catalog,
          realTableName,
          isAbstract,
          subselect,
          denormalizedSuperTable
      );
    }
    else {
      table = mappings.addTable(
          schema,
          catalog,
          realTableName,
          subselect,
          isAbstract
      );
    }

    if ( uniqueConstraints != null && uniqueConstraints.size() > 0 ) {
      mappings.addUniqueConstraintHolders( table, uniqueConstraints );
    }

    if ( constraints != null ) table.addCheckConstraint( constraints );

    // logicalName is null if we are in the second pass
    final String logicalName = nameSource.getLogicalName();
    if ( logicalName != null ) {
      mappings.addTableBinding( schema, catalog, logicalName, realTableName, denormalizedSuperTable );
    }
    return table;
  }

  /**
   *
   * @param schema
   * @param catalog
   * @param realTableName
   * @param logicalName
   * @param isAbstract
   * @param uniqueConstraints
   * @param constraints
   * @param denormalizedSuperTable
   * @param mappings
   * @return
   *
   * @deprecated Use {@link #buildAndFillTable} instead.
   */
  @Deprecated
    @SuppressWarnings({ "JavaDoc" })
  public static Table fillTable(
      String schema,
      String catalog,
      String realTableName,
      String logicalName,
      boolean isAbstract,
      List uniqueConstraints,
      String constraints,
      Table denormalizedSuperTable,
      Mappings mappings) {
    schema = BinderHelper.isEmptyAnnotationValue( schema ) ? mappings.getSchemaName() : schema;
    catalog = BinderHelper.isEmptyAnnotationValue( catalog ) ? mappings.getCatalogName() : catalog;
    Table table;
    if ( denormalizedSuperTable != null ) {
      table = mappings.addDenormalizedTable(
          schema,
          catalog,
          realTableName,
          isAbstract,
          null, //subselect
          denormalizedSuperTable
      );
    }
    else {
      table = mappings.addTable(
          schema,
          catalog,
          realTableName,
          null, //subselect
          isAbstract
      );
    }
    if ( uniqueConstraints != null && uniqueConstraints.size() > 0 ) {
      mappings.addUniqueConstraints( table, uniqueConstraints );
    }
    if ( constraints != null ) table.addCheckConstraint( constraints );
    //logicalName is null if we are in the second pass
    if ( logicalName != null ) {
      mappings.addTableBinding( schema, catalog, logicalName, realTableName, denormalizedSuperTable );
    }
    return table;
  }

  public static void bindFk(
      PersistentClass referencedEntity,
      PersistentClass destinationEntity,
      Ejb3JoinColumn[] columns,
      SimpleValue value,
      boolean unique,
      Mappings mappings) {
    PersistentClass associatedClass;
    if ( destinationEntity != null ) {
      //overridden destination
      associatedClass = destinationEntity;
    }
    else {
      associatedClass = columns[0].getPropertyHolder() == null
          ? null
          : columns[0].getPropertyHolder().getPersistentClass();
    }
    final String mappedByProperty = columns[0].getMappedBy();
    if ( StringHelper.isNotEmpty( mappedByProperty ) ) {
      /**
       * Get the columns of the mapped-by property
       * copy them and link the copy to the actual value
       */
            LOG.debugf("Retrieving property %s.%s", associatedClass.getEntityName(), mappedByProperty);

      final Property property = associatedClass.getRecursiveProperty( columns[0].getMappedBy() );
      Iterator mappedByColumns;
      if ( property.getValue() instanceof Collection ) {
        Collection collection = ( (Collection) property.getValue() );
        Value element = collection.getElement();
        if ( element == null ) {
          throw new AnnotationException(
              "Illegal use of mappedBy on both sides of the relationship: "
                  + associatedClass.getEntityName() + "." + mappedByProperty
          );
        }
        mappedByColumns = element.getColumnIterator();
      }
      else {
        mappedByColumns = property.getValue().getColumnIterator();
      }
      while ( mappedByColumns.hasNext() ) {
        Column column = (Column) mappedByColumns.next();
        columns[0].overrideFromReferencedColumnIfNecessary( column );
        columns[0].linkValueUsingAColumnCopy( column, value );
      }
    }
    else if ( columns[0].isImplicit() ) {
      /**
       * if columns are implicit, then create the columns based on the
       * referenced entity id columns
       */
      Iterator idColumns;
      if ( referencedEntity instanceof JoinedSubclass ) {
        idColumns = referencedEntity.getKey().getColumnIterator();
      }
      else {
        idColumns = referencedEntity.getIdentifier().getColumnIterator();
      }
      while ( idColumns.hasNext() ) {
        Column column = (Column) idColumns.next();
        columns[0].overrideFromReferencedColumnIfNecessary( column );
        columns[0].linkValueUsingDefaultColumnNaming( column, referencedEntity, value );
      }
    }
    else {
      int fkEnum = Ejb3JoinColumn.checkReferencedColumnsType( columns, referencedEntity, mappings );

      if ( Ejb3JoinColumn.NON_PK_REFERENCE == fkEnum ) {
        String referencedPropertyName;
        if ( value instanceof ToOne ) {
          referencedPropertyName = ( (ToOne) value ).getReferencedPropertyName();
        }
        else if ( value instanceof DependantValue ) {
          String propertyName = columns[0].getPropertyName();
          if ( propertyName != null ) {
            Collection collection = (Collection) referencedEntity.getRecursiveProperty( propertyName )
                .getValue();
            referencedPropertyName = collection.getReferencedPropertyName();
          }
          else {
            throw new AnnotationException( "SecondaryTable JoinColumn cannot reference a non primary key" );
          }

        }
        else {
          throw new AssertionFailure(
              "Do a property ref on an unexpected Value type: "
                  + value.getClass().getName()
          );
        }
        if ( referencedPropertyName == null ) {
          throw new AssertionFailure(
              "No property ref found while expected"
          );
        }
        Property synthProp = referencedEntity.getRecursiveProperty( referencedPropertyName );
        if ( synthProp == null ) {
          throw new AssertionFailure(
              "Cannot find synthProp: " + referencedEntity.getEntityName() + "." + referencedPropertyName
          );
        }
        linkJoinColumnWithValueOverridingNameIfImplicit(
            referencedEntity, synthProp.getColumnIterator(), columns, value
        );

      }
      else {
        if ( Ejb3JoinColumn.NO_REFERENCE == fkEnum ) {
          //implicit case, we hope PK and FK columns are in the same order
          if ( columns.length != referencedEntity.getIdentifier().getColumnSpan() ) {
            throw new AnnotationException(
                "A Foreign key refering " + referencedEntity.getEntityName()
                    + " from " + associatedClass.getEntityName()
                    + " has the wrong number of column. should be " + referencedEntity.getIdentifier()
                    .getColumnSpan()
            );
          }
          linkJoinColumnWithValueOverridingNameIfImplicit(
              referencedEntity,
              referencedEntity.getIdentifier().getColumnIterator(),
              columns,
              value
          );
        }
        else {
          //explicit referencedColumnName
          Iterator idColItr = referencedEntity.getKey().getColumnIterator();
          org.hibernate.mapping.Column col;
          Table table = referencedEntity.getTable(); //works cause the pk has to be on the primary table
                    if (!idColItr.hasNext()) LOG.debugf("No column in the identifier!");
          while ( idColItr.hasNext() ) {
            boolean match = false;
            //for each PK column, find the associated FK column.
            col = (org.hibernate.mapping.Column) idColItr.next();
            for (Ejb3JoinColumn joinCol : columns) {
              String referencedColumn = joinCol.getReferencedColumn();
              referencedColumn = mappings.getPhysicalColumnName( referencedColumn, table );
              //In JPA 2 referencedColumnName is case insensitive
              if ( referencedColumn.equalsIgnoreCase( col.getQuotedName() ) ) {
                //proper join column
                if ( joinCol.isNameDeferred() ) {
                  joinCol.linkValueUsingDefaultColumnNaming(
                      col, referencedEntity, value
                  );
                }
                else {
                  joinCol.linkWithValue( value );
                }
                joinCol.overrideFromReferencedColumnIfNecessary( col );
                match = true;
                break;
              }
            }
            if ( !match ) {
              throw new AnnotationException(
                  "Column name " + col.getName() + " of "
                      + referencedEntity.getEntityName() + " not found in JoinColumns.referencedColumnName"
              );
            }
          }
        }
      }
    }
    value.createForeignKey();
    if ( unique ) {
      createUniqueConstraint( value );
    }
  }

  public static void linkJoinColumnWithValueOverridingNameIfImplicit(
      PersistentClass referencedEntity,
      Iterator columnIterator,
      Ejb3JoinColumn[] columns,
      SimpleValue value) {
    for (Ejb3JoinColumn joinCol : columns) {
      Column synthCol = (Column) columnIterator.next();
      if ( joinCol.isNameDeferred() ) {
        //this has to be the default value
        joinCol.linkValueUsingDefaultColumnNaming( synthCol, referencedEntity, value );
      }
      else {
        joinCol.linkWithValue( value );
        joinCol.overrideFromReferencedColumnIfNecessary( synthCol );
      }
    }
  }

  public static void createUniqueConstraint(Value value) {
    Iterator iter = value.getColumnIterator();
    ArrayList cols = new ArrayList();
    while ( iter.hasNext() ) {
      cols.add( iter.next() );
    }
    value.getTable().createUniqueKey( cols );
  }

  public static void addIndexes(Table hibTable, Index[] indexes, Mappings mappings) {
    for (Index index : indexes) {
      //no need to handle inSecondPass here since it is only called from EntityBinder
      mappings.addSecondPass(
          new IndexOrUniqueKeySecondPass( hibTable, index.name(), index.columnNames(), mappings )
      );
    }
  }

  /**
   * @deprecated Use {@link #buildUniqueConstraintHolders} instead
   */
  @Deprecated
    @SuppressWarnings({ "JavaDoc" })
  public static List<String[]> buildUniqueConstraints(UniqueConstraint[] constraintsArray) {
    List<String[]> result = new ArrayList<String[]>();
    if ( constraintsArray.length != 0 ) {
      for (UniqueConstraint uc : constraintsArray) {
        result.add( uc.columnNames() );
      }
    }
    return result;
  }

  /**
   * Build a list of {@link org.hibernate.cfg.UniqueConstraintHolder} instances given a list of
   * {@link UniqueConstraint} annotations.
   *
   * @param annotations The {@link UniqueConstraint} annotations.
   *
   * @return The built {@link org.hibernate.cfg.UniqueConstraintHolder} instances.
   */
  public static List<UniqueConstraintHolder> buildUniqueConstraintHolders(UniqueConstraint[] annotations) {
    List<UniqueConstraintHolder> result;
    if ( annotations == null || annotations.length == 0 ) {
      result = java.util.Collections.emptyList();
    }
    else {
      result = new ArrayList<UniqueConstraintHolder>( CollectionHelper.determineProperSizing( annotations.length ) );
      for ( UniqueConstraint uc : annotations ) {
        result.add(
            new UniqueConstraintHolder()
                .setName( uc.name() )
                .setColumns( uc.columnNames() )
        );
      }
    }
    return result;
  }

  public void setDefaultName(
      String ownerEntity, String ownerEntityTable, String associatedEntity, String associatedEntityTable,
      String propertyName
  ) {
    this.ownerEntity = ownerEntity;
    this.ownerEntityTable = ownerEntityTable;
    this.associatedEntity = associatedEntity;
    this.associatedEntityTable = associatedEntityTable;
    this.propertyName = propertyName;
    this.name = null;
  }
}
TOP

Related Classes of org.hibernate.cfg.annotations.TableBinder$AssociationTableNameSource

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.