Open Source Repository

Home /hibernate/hibernate-3.2.4.ga | Repository Home



org/hibernate/type/ComponentType.java
//$Id: ComponentType.java 10119 2006-07-14 00:09:19Z [email protected] $
package org.hibernate.type;

import java.io.Serializable;
import java.lang.reflect.Method;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;

import org.dom4j.Element;
import org.dom4j.Node;
import org.hibernate.EntityMode;
import org.hibernate.FetchMode;
import org.hibernate.HibernateException;
import org.hibernate.MappingException;
import org.hibernate.engine.CascadeStyle;
import org.hibernate.engine.Mapping;
import org.hibernate.engine.SessionFactoryImplementor;
import org.hibernate.engine.SessionImplementor;
import org.hibernate.tuple.component.ComponentTuplizer;
import org.hibernate.tuple.component.ComponentMetamodel;
import org.hibernate.tuple.StandardProperty;
import org.hibernate.tuple.EntityModeToTuplizerMapping;
import org.hibernate.util.ArrayHelper;
import org.hibernate.util.StringHelper;

/**
 * Handles "component" mappings
 *
 @author Gavin King
 */
public class ComponentType extends AbstractType implements AbstractComponentType {

  private final String[] propertyNames;
  private final Type[] propertyTypes;
  private final boolean[] propertyNullability;
  protected final int propertySpan;
  private final CascadeStyle[] cascade;
  private final FetchMode[] joinedFetch;
  private final boolean isKey;

  protected final EntityModeToTuplizerMapping tuplizerMapping;

  public ComponentType(ComponentMetamodel metamodel) {
    // for now, just "re-flatten" the metamodel since this is temporary stuff anyway (HHH-1907)
    this.isKey = metamodel.isKey();
    this.propertySpan = metamodel.getPropertySpan();
    this.propertyNames = new StringpropertySpan ];
    this.propertyTypes = new TypepropertySpan ];
    this.propertyNullability = new booleanpropertySpan ];
    this.cascade = new CascadeStylepropertySpan ];
    this.joinedFetch = new FetchModepropertySpan ];

    for int i = 0; i < propertySpan; i++ ) {
      StandardProperty prop = metamodel.getProperty);
      this.propertyNames[i= prop.getName();
      this.propertyTypes[i= prop.getType();
      this.propertyNullability[i= prop.isNullable();
      this.cascade[i= prop.getCascadeStyle();
      this.joinedFetch[i= prop.getFetchMode();
    }

    this.tuplizerMapping = metamodel.getTuplizerMapping();
  }

  public int[] sqlTypes(Mapping mappingthrows MappingException {
    //Not called at runtime so doesn't matter if its slow :)
    int[] sqlTypes = new int[getColumnSpanmapping )];
    int n = 0;
    for int i = 0; i < propertySpan; i++ ) {
      int[] subtypes = propertyTypes[i].sqlTypesmapping );
      for int j = 0; j < subtypes.length; j++ ) {
        sqlTypes[n++= subtypes[j];
      }
    }
    return sqlTypes;
  }

  public int getColumnSpan(Mapping mappingthrows MappingException {
    int span = 0;
    for int i = 0; i < propertySpan; i++ ) {
      span += propertyTypes[i].getColumnSpanmapping );
    }
    return span;
  }

  public final boolean isComponentType() {
    return true;
  }

  public Class getReturnedClass() {
    return tuplizerMapping.getTuplizerEntityMode.POJO ).getMappedClass()//TODO
  }

  public boolean isSame(Object x, Object y, EntityMode entityModethrows HibernateException {
    if x == y ) {
      return true;
    }
    if x == null || y == null ) {
      return false;
    }
    Object[] xvalues = getPropertyValuesx, entityMode );
    Object[] yvalues = getPropertyValuesy, entityMode );
    for int i = 0; i < propertySpan; i++ ) {
      if !propertyTypes[i].isSamexvalues[i], yvalues[i], entityMode ) ) {
        return false;
      }
    }
    return true;
  }

  public boolean isEqual(Object x, Object y, EntityMode entityMode)
      throws HibernateException {
    if x == y ) {
      return true;
    }
    if x == null || y == null ) {
      return false;
    }
    Object[] xvalues = getPropertyValuesx, entityMode );
    Object[] yvalues = getPropertyValuesy, entityMode );
    for int i = 0; i < propertySpan; i++ ) {
      if !propertyTypes[i].isEqualxvalues[i], yvalues[i], entityMode ) ) {
        return false;
      }
    }
    return true;
  }

  public boolean isEqual(Object x, Object y, EntityMode entityMode, SessionFactoryImplementor factory)
      throws HibernateException {
    if x == y ) {
      return true;
    }
    if x == null || y == null ) {
      return false;
    }
    Object[] xvalues = getPropertyValuesx, entityMode );
    Object[] yvalues = getPropertyValuesy, entityMode );
    for int i = 0; i < propertySpan; i++ ) {
      if !propertyTypes[i].isEqualxvalues[i], yvalues[i], entityMode, factory ) ) {
        return false;
      }
    }
    return true;
  }

  public int compare(Object x, Object y, EntityMode entityMode) {
    if x == y ) {
      return 0;
    }
    Object[] xvalues = getPropertyValuesx, entityMode );
    Object[] yvalues = getPropertyValuesy, entityMode );
    for int i = 0; i < propertySpan; i++ ) {
      int propertyCompare = propertyTypes[i].comparexvalues[i], yvalues[i], entityMode );
      if propertyCompare != ) {
        return propertyCompare;
      }
    }
    return 0;
  }

  public boolean isMethodOf(Method method) {
    return false;
  }

  public int getHashCode(Object x, EntityMode entityMode) {
    int result = 17;
    Object[] values = getPropertyValuesx, entityMode );
    for int i = 0; i < propertySpan; i++ ) {
      Object y = values[i];
      result *= 37;
      if y != null ) {
        result += propertyTypes[i].getHashCodey, entityMode );
      }
    }
    return result;
  }

  public int getHashCode(Object x, EntityMode entityMode, SessionFactoryImplementor factory) {
    int result = 17;
    Object[] values = getPropertyValuesx, entityMode );
    for int i = 0; i < propertySpan; i++ ) {
      Object y = values[i];
      result *= 37;
      if y != null ) {
        result += propertyTypes[i].getHashCodey, entityMode, factory );
      }
    }
    return result;
  }

  public boolean isDirty(Object x, Object y, SessionImplementor session)
      throws HibernateException {
    if x == y ) {
      return false;
    }
    if x == null || y == null ) {
      return true;
    }
    EntityMode entityMode = session.getEntityMode();
    Object[] xvalues = getPropertyValuesx, entityMode );
    Object[] yvalues = getPropertyValuesy, entityMode );
    for int i = 0; i < xvalues.length; i++ ) {
      if propertyTypes[i].isDirtyxvalues[i], yvalues[i], session ) ) {
        return true;
      }
    }
    return false;
  }

  public boolean isDirty(Object x, Object y, boolean[] checkable, SessionImplementor session)
      throws HibernateException {
    if x == y ) {
      return false;
    }
    if x == null || y == null ) {
      return true;
    }
    EntityMode entityMode = session.getEntityMode();
    Object[] xvalues = getPropertyValuesx, entityMode );
    Object[] yvalues = getPropertyValuesy, entityMode );
    int loc = 0;
    for int i = 0; i < xvalues.length; i++ ) {
      int len = propertyTypes[i].getColumnSpansession.getFactory() );
      if len <= ) {
        final boolean dirty = len == || checkable[loc] ) &&
                              propertyTypes[i].isDirtyxvalues[i], yvalues[i], session );
        if dirty ) {
          return true;
        }
      }
      else {
        boolean[] subcheckable = new boolean[len];
        System.arraycopycheckable, loc, subcheckable, 0, len );
        final boolean dirty = propertyTypes[i].isDirtyxvalues[i], yvalues[i], subcheckable, session );
        if dirty ) {
          return true;
        }
      }
      loc += len;
    }
    return false;
  }

  public boolean isModified(Object old, Object current, boolean[] checkable, SessionImplementor session)
      throws HibernateException {

    if current == null ) {
      return old != null;
    }
    if old == null ) {
      return current != null;
    }
    Object[] currentValues = getPropertyValuescurrent, session );
    Object[] oldValues = Object[] ) old;
    int loc = 0;
    for int i = 0; i < currentValues.length; i++ ) {
      int len = propertyTypes[i].getColumnSpansession.getFactory() );
      boolean[] subcheckable = new boolean[len];
      System.arraycopycheckable, loc, subcheckable, 0, len );
      if propertyTypes[i].isModifiedoldValues[i], currentValues[i], subcheckable, session ) ) {
        return true;
      }
      loc += len;
    }
    return false;

  }

  public Object nullSafeGet(ResultSet rs, String[] names, SessionImplementor session, Object owner)
      throws HibernateException, SQLException {
    return resolvehydraters, names, session, owner ), session, owner );
  }

  public void nullSafeSet(PreparedStatement st, Object value, int begin, SessionImplementor session)
      throws HibernateException, SQLException {

    Object[] subvalues = nullSafeGetValuesvalue, session.getEntityMode() );

    for int i = 0; i < propertySpan; i++ ) {
      propertyTypes[i].nullSafeSetst, subvalues[i], begin, session );
      begin += propertyTypes[i].getColumnSpansession.getFactory() );
    }
  }

  public void nullSafeSet(
      PreparedStatement st,
      Object value,
      int begin,
      boolean[] settable,
      SessionImplementor session)
      throws HibernateException, SQLException {

    Object[] subvalues = nullSafeGetValuesvalue, session.getEntityMode() );

    int loc = 0;
    for int i = 0; i < propertySpan; i++ ) {
      int len = propertyTypes[i].getColumnSpansession.getFactory() );
      if len == ) {
        //noop
      }
      else if len == ) {
        if settable[loc] ) {
          propertyTypes[i].nullSafeSetst, subvalues[i], begin, session );
          begin++;
        }
      }
      else {
        boolean[] subsettable = new boolean[len];
        System.arraycopysettable, loc, subsettable, 0, len );
        propertyTypes[i].nullSafeSetst, subvalues[i], begin, subsettable, session );
        begin += ArrayHelper.countTruesubsettable );
      }
      loc += len;
    }
  }

  private Object[] nullSafeGetValues(Object value, EntityMode entityModethrows HibernateException {
    if value == null ) {
      return new Object[propertySpan];
    }
    else {
      return getPropertyValuesvalue, entityMode );
    }
  }

  public Object nullSafeGet(ResultSet rs, String name, SessionImplementor session, Object owner)
      throws HibernateException, SQLException {

    return nullSafeGetrs, new String[] {name}, session, owner );
  }

  public Object getPropertyValue(Object component, int i, SessionImplementor session)
      throws HibernateException {
    return getPropertyValuecomponent, i, session.getEntityMode() );
  }

  public Object getPropertyValue(Object component, int i, EntityMode entityMode)
      throws HibernateException {
    return tuplizerMapping.getTuplizerentityMode ).getPropertyValuecomponent, i );
  }

  public Object[] getPropertyValues(Object component, SessionImplementor session)
      throws HibernateException {
    return getPropertyValuescomponent, session.getEntityMode() );
  }

  public Object[] getPropertyValues(Object component, EntityMode entityMode)
      throws HibernateException {
    return tuplizerMapping.getTuplizerentityMode ).getPropertyValuescomponent );
  }

  public void setPropertyValues(Object component, Object[] values, EntityMode entityMode)
      throws HibernateException {
    tuplizerMapping.getTuplizerentityMode ).setPropertyValuescomponent, values );
  }

  public Type[] getSubtypes() {
    return propertyTypes;
  }

  public String getName() {
    return "component" + ArrayHelper.toStringpropertyNames );
  }

  public String toLoggableString(Object value, SessionFactoryImplementor factory)
      throws HibernateException {
    if value == null ) {
      return "null";
    }
    Map result = new HashMap();
    EntityMode entityMode = tuplizerMapping.guessEntityModevalue );
    if entityMode == null ) {
      throw new ClassCastExceptionvalue.getClass().getName() );
    }
    Object[] values = getPropertyValuesvalue, entityMode );
    for int i = 0; i < propertyTypes.length; i++ ) {
      result.putpropertyNames[i], propertyTypes[i].toLoggableStringvalues[i], factory ) );
    }
    return StringHelper.unqualifygetName() ) + result.toString();
  }

  public String[] getPropertyNames() {
    return propertyNames;
  }

  public Object deepCopy(Object component, EntityMode entityMode, SessionFactoryImplementor factory)
      throws HibernateException {
    if component == null ) {
      return null;
    }

    Object[] values = getPropertyValuescomponent, entityMode );
    for int i = 0; i < propertySpan; i++ ) {
      values[i= propertyTypes[i].deepCopyvalues[i], entityMode, factory );
    }

    Object result = instantiateentityMode );
    setPropertyValuesresult, values, entityMode );

    //not absolutely necessary, but helps for some
    //equals()/hashCode() implementations
    ComponentTuplizer ct = ComponentTuplizer tuplizerMapping.getTuplizerentityMode );
    if ct.hasParentProperty() ) {
      ct.setParentresult, ct.getParentcomponent ), factory );
    }

    return result;
  }

  public Object replace(
      Object original,
      Object target,
      SessionImplementor session,
      Object owner,
      Map copyCache)
      throws HibernateException {

    if original == null ) {
      return null;
    }
    //if ( original == target ) return target;

    final Object result = target == null
        ? instantiateowner, session )
        : target;

    final EntityMode entityMode = session.getEntityMode();
    Object[] values = TypeFactory.replace(
        getPropertyValuesoriginal, entityMode ),
        getPropertyValuesresult, entityMode ),
        propertyTypes,
        session,
        owner,
        copyCache
    );

    setPropertyValuesresult, values, entityMode );
    return result;
  }

  public Object replace(
      Object original,
      Object target,
      SessionImplementor session,
      Object owner,
      Map copyCache,
      ForeignKeyDirection foreignKeyDirection)
      throws HibernateException {

    if original == null ) {
      return null;
    }
    //if ( original == target ) return target;

    final Object result = target == null ?
        instantiateowner, session :
        target;

    final EntityMode entityMode = session.getEntityMode();
    Object[] values = TypeFactory.replace(
        getPropertyValuesoriginal, entityMode ),
        getPropertyValuesresult, entityMode ),
        propertyTypes,
        session,
        owner,
        copyCache,
        foreignKeyDirection
    );

    setPropertyValuesresult, values, entityMode );
    return result;
  }

  /**
   * This method does not populate the component parent
   */
  public Object instantiate(EntityMode entityModethrows HibernateException {
    return tuplizerMapping.getTuplizerentityMode ).instantiate();
  }

  public Object instantiate(Object parent, SessionImplementor session)
      throws HibernateException {

    Object result = instantiatesession.getEntityMode() );

    ComponentTuplizer ct = ComponentTuplizer tuplizerMapping.getTuplizersession.getEntityMode() );
    if ct.hasParentProperty() && parent != null ) {
      ct.setParent(
          result,
          session.getPersistenceContext().proxyForparent ),
          session.getFactory()
      );
    }

    return result;
  }

  public CascadeStyle getCascadeStyle(int i) {
    return cascade[i];
  }

  public boolean isMutable() {
    return true;
  }

  public Serializable disassemble(Object value, SessionImplementor session, Object owner)
      throws HibernateException {

    if value == null ) {
      return null;
    }
    else {
      Object[] values = getPropertyValuesvalue, session.getEntityMode() );
      for int i = 0; i < propertyTypes.length; i++ ) {
        values[i= propertyTypes[i].disassemblevalues[i], session, owner );
      }
      return values;
    }
  }

  public Object assemble(Serializable object, SessionImplementor session, Object owner)
      throws HibernateException {

    if object == null ) {
      return null;
    }
    else {
      Object[] values = Object[] ) object;
      Object[] assembled = new Object[values.length];
      for int i = 0; i < propertyTypes.length; i++ ) {
        assembled[i= propertyTypes[i].assemble( ( Serializable values[i], session, owner );
      }
      Object result = instantiateowner, session );
      setPropertyValuesresult, assembled, session.getEntityMode() );
      return result;
    }
  }

  public FetchMode getFetchMode(int i) {
    return joinedFetch[i];
  }

  public Object hydrate(
      final ResultSet rs,
      final String[] names,
      final SessionImplementor session,
      final Object owner)
      throws HibernateException, SQLException {

    int begin = 0;
    boolean notNull = false;
    Object[] values = new Object[propertySpan];
    for int i = 0; i < propertySpan; i++ ) {
      int length = propertyTypes[i].getColumnSpansession.getFactory() );
      String[] range = ArrayHelper.slicenames, begin, length )//cache this
      Object val = propertyTypes[i].hydraters, range, session, owner );
      if val == null ) {
        if isKey ) {
          return null//different nullability rules for pk/fk
        }
      }
      else {
        notNull = true;
      }
      values[i= val;
      begin += length;
    }

    return notNull ? values : null;
  }

  public Object resolve(Object value, SessionImplementor session, Object owner)
      throws HibernateException {

    if value != null ) {
      Object result = instantiateowner, session );
      Object[] values = Object[] ) value;
      Object[] resolvedValues = new Object[values.length]//only really need new array during semiresolve!
      for int i = 0; i < values.length; i++ ) {
        resolvedValues[i= propertyTypes[i].resolvevalues[i], session, owner );
      }
      setPropertyValuesresult, resolvedValues, session.getEntityMode() );
      return result;
    }
    else {
      return null;
    }
  }

  public Object semiResolve(Object value, SessionImplementor session, Object owner)
      throws HibernateException {
    //note that this implementation is kinda broken
    //for components with many-to-one associations
    return resolvevalue, session, owner );
  }

  public boolean[] getPropertyNullability() {
    return propertyNullability;
  }

  public boolean isXMLElement() {
    return true;
  }

  public Object fromXMLNode(Node xml, Mapping factorythrows HibernateException {
    return xml;
  }

  public void setToXMLNode(Node node, Object value, SessionFactoryImplementor factorythrows HibernateException {
    replaceNodenode, Element value );
  }

  public boolean[] toColumnNullness(Object value, Mapping mapping) {
    boolean[] result = new booleangetColumnSpanmapping ) ];
    if value == null ) {
      return result;
    }
    Object[] values = getPropertyValuesvalue, EntityMode.POJO )//TODO!!!!!!!
    int loc = 0;
    for int i = 0; i < propertyTypes.length; i++ ) {
      boolean[] propertyNullness = propertyTypes[i].toColumnNullnessvalues[i], mapping );
      System.arraycopypropertyNullness, 0, result, loc, propertyNullness.length );
      loc += propertyNullness.length;
    }
    return result;
  }

  public boolean isEmbedded() {
    return false;
  }

}