Open Source Repository

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



org/hibernate/tuple/entity/AbstractEntityTuplizer.java
// $Id: AbstractEntityTuplizer.java 7516 2005-07-16 22:20:48Z oneovthafew $
package org.hibernate.tuple.entity;

import java.io.Serializable;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

import org.hibernate.EntityMode;
import org.hibernate.HibernateException;
import org.hibernate.MappingException;
import org.hibernate.tuple.Instantiator;
import org.hibernate.tuple.VersionProperty;
import org.hibernate.tuple.StandardProperty;
import org.hibernate.engine.SessionFactoryImplementor;
import org.hibernate.engine.SessionImplementor;
import org.hibernate.id.Assigned;
import org.hibernate.intercept.LazyPropertyInitializer;
import org.hibernate.mapping.Component;
import org.hibernate.mapping.PersistentClass;
import org.hibernate.mapping.Property;
import org.hibernate.property.Getter;
import org.hibernate.property.Setter;
import org.hibernate.proxy.ProxyFactory;
import org.hibernate.type.AbstractComponentType;
import org.hibernate.type.ComponentType;


/**
 * Support for tuplizers relating to entities.
 *
 @author Steve Ebersole
 @author Gavin King
 */
public abstract class AbstractEntityTuplizer implements EntityTuplizer {

  //TODO: currently keeps Getters and Setters (instead of PropertyAccessors) because of the way getGetter() and getSetter() are implemented currently; yuck!

  private final EntityMetamodel entityMetamodel;

  private final Getter idGetter;
  private final Setter idSetter;

  protected final Getter[] getters;
  protected final Setter[] setters;
  protected final int propertySpan;
  protected final boolean hasCustomAccessors;
  private final Instantiator instantiator;
  private final ProxyFactory proxyFactory;
  private final AbstractComponentType identifierMapperType;


  /**
   * Return the entity-mode handled by this tuplizer instance.
   *
   @return The entity-mode
   */
  protected abstract EntityMode getEntityMode();

  /**
   * Build an appropriate Getter for the given property.
   *
   @param mappedProperty The property to be accessed via the built Getter.
   @param mappedEntity The entity information regarding the mapped entity owning this property.
   @return An appropriate Getter instance.
   */
  protected abstract Getter buildPropertyGetter(Property mappedProperty, PersistentClass mappedEntity);

  /**
   * Build an appropriate Setter for the given property.
   *
   @param mappedProperty The property to be accessed via the built Setter.
   @param mappedEntity The entity information regarding the mapped entity owning this property.
   @return An appropriate Setter instance.
   */
  protected abstract Setter buildPropertySetter(Property mappedProperty, PersistentClass mappedEntity);

  /**
   * Build an appropriate Instantiator for the given mapped entity.
   *
   @param mappingInfo The mapping information regarding the mapped entity.
   @return An appropriate Instantiator instance.
   */
  protected abstract Instantiator buildInstantiator(PersistentClass mappingInfo);

  /**
   * Build an appropriate ProxyFactory for the given mapped entity.
   *
   @param mappingInfo The mapping information regarding the mapped entity.
   @param idGetter The constructed Getter relating to the entity's id property.
   @param idSetter The constructed Setter relating to the entity's id property.
   @return An appropriate ProxyFactory instance.
   */
  protected abstract ProxyFactory buildProxyFactory(PersistentClass mappingInfo, Getter idGetter, Setter idSetter);

  /**
   * Constructs a new AbstractEntityTuplizer instance.
   *
   @param entityMetamodel The "interpreted" information relating to the mapped entity.
   @param mappingInfo The parsed "raw" mapping data relating to the given entity.
   */
  public AbstractEntityTuplizer(EntityMetamodel entityMetamodel, PersistentClass mappingInfo) {
    this.entityMetamodel = entityMetamodel;

    if !entityMetamodel.getIdentifierProperty().isVirtual() ) {
      idGetter = buildPropertyGettermappingInfo.getIdentifierProperty(), mappingInfo );
      idSetter = buildPropertySettermappingInfo.getIdentifierProperty(), mappingInfo );
    }
    else {
      idGetter = null;
      idSetter = null;
    }

    propertySpan = entityMetamodel.getPropertySpan();

        getters = new Getter[propertySpan];
    setters = new Setter[propertySpan];

    Iterator iter = mappingInfo.getPropertyClosureIterator();
    boolean foundCustomAccessor=false;
    int i=0;
    while iter.hasNext() ) {
      //TODO: redesign how PropertyAccessors are acquired...
      Property property = (Propertyiter.next();
      getters[i= buildPropertyGetter(property, mappingInfo);
      setters[i= buildPropertySetter(property, mappingInfo);
      if !property.isBasicPropertyAccessor() ) foundCustomAccessor = true;
      i++;
    }
    hasCustomAccessors = foundCustomAccessor;

        instantiator = buildInstantiatormappingInfo );

    if entityMetamodel.isLazy() ) {
      proxyFactory = buildProxyFactorymappingInfo, idGetter, idSetter );
      if (proxyFactory == null) {
        entityMetamodel.setLazyfalse );
      }
    }
    else {
      proxyFactory = null;
    }
    
    Component mapper = mappingInfo.getIdentifierMapper();
    identifierMapperType = mapper==null null (AbstractComponentTypemapper.getType();
  }

  /** Retreives the defined entity-name for the tuplized entity.
   *
   @return The entity-name.
   */
  protected String getEntityName() {
    return entityMetamodel.getName();
  }

  /**
   * Retreives the defined entity-names for any subclasses defined for this
   * entity.
   *
   @return Any subclass entity-names.
   */
  protected Set getSubclassEntityNames() {
    return entityMetamodel.getSubclassEntityNames();
  }

  public Serializable getIdentifier(Object entitythrows HibernateException {
    final Object id;
    if entityMetamodel.getIdentifierProperty().isEmbedded() ) {
      id = entity;
    }
    else {
      if idGetter == null ) {
        if (identifierMapperType==null) {
          throw new HibernateException"The class has no identifier property: " + getEntityName() );
        }
        else {
          ComponentType copier = (ComponentTypeentityMetamodel.getIdentifierProperty().getType();
          id = copier.instantiategetEntityMode() );
          copier.setPropertyValuesid, identifierMapperType.getPropertyValuesentity, getEntityMode() ), getEntityMode() );
        }
      }
      else {
        id = idGetter.getentity );
      }
    }

    try {
      return (Serializableid;
    }
    catch ClassCastException cce ) {
      StringBuffer msg = new StringBuffer"Identifier classes must be serializable. " );
      if id != null ) {
        msg.appendid.getClass().getName() " is not serializable. " );
      }
      if cce.getMessage() != null ) {
        msg.appendcce.getMessage() );
      }
      throw new ClassCastExceptionmsg.toString() );
    }
  }


  public void setIdentifier(Object entity, Serializable idthrows HibernateException {
    if entityMetamodel.getIdentifierProperty().isEmbedded() ) {
      if entity != id ) {
        AbstractComponentType copier = (AbstractComponentTypeentityMetamodel.getIdentifierProperty().getType();
        copier.setPropertyValuesentity, copier.getPropertyValuesid, getEntityMode() ), getEntityMode() );
      }
    }
    else if idSetter != null ) {
      idSetter.setentity, id, getFactory() );
    }
  }

  public void resetIdentifier(Object entity, Serializable currentId, Object currentVersion) {
    if entityMetamodel.getIdentifierProperty().getIdentifierGenerator() instanceof Assigned ) {
      //return currentId;
    }
    else {
      //reset the id
      Serializable result = entityMetamodel.getIdentifierProperty()
          .getUnsavedValue()
          .getDefaultValuecurrentId );
      setIdentifierentity, result );
      //reset the version
      VersionProperty versionProperty = entityMetamodel.getVersionProperty();
      if entityMetamodel.isVersioned() ) {
        setPropertyValue(
                entity,
                entityMetamodel.getVersionPropertyIndex(),
            versionProperty.getUnsavedValue().getDefaultValuecurrentVersion )
          );
      }
      //return the id, so we can use it to reset the proxy id
      //return result;
    }
  }

  public Object getVersion(Object entitythrows HibernateException {
    if !entityMetamodel.isVersioned() ) return null;
    return gettersentityMetamodel.getVersionPropertyIndex() ].getentity );
  }

  protected boolean shouldGetAllProperties(Object entity) {
    return !hasUninitializedLazyPropertiesentity );
  }

  public Object[] getPropertyValues(Object entitythrows HibernateException {
    boolean getAll = shouldGetAllPropertiesentity );
    final int span = entityMetamodel.getPropertySpan();
    final Object[] result = new Object[span];

    for int j = 0; j < span; j++ ) {
      StandardProperty property = entityMetamodel.getProperties()[j];
      if getAll || !property.isLazy() ) {
        result[j= getters[j].getentity );
      }
      else {
        result[j= LazyPropertyInitializer.UNFETCHED_PROPERTY;
      }
    }
    return result;
  }

  public Object[] getPropertyValuesToInsert(Object entity, Map mergeMap, SessionImplementor session
  throws HibernateException {
    final int span = entityMetamodel.getPropertySpan();
    final Object[] result = new Object[span];

    for int j = 0; j < span; j++ ) {
      result[j= getters[j].getForInsertentity, mergeMap, session );
    }
    return result;
  }

  public Object getPropertyValue(Object entity, int ithrows HibernateException {
    return getters[i].getentity );
  }

  public Object getPropertyValue(Object entity, String propertyPaththrows HibernateException {
    
    int loc = propertyPath.indexOf('.');
    String basePropertyName = loc>?
      propertyPath.substring(0, loc: propertyPath;
      
    int index = entityMetamodel.getPropertyIndexbasePropertyName );
    Object baseValue = getPropertyValueentity, index );
    if loc>) {
      ComponentType type = (ComponentTypeentityMetamodel.getPropertyTypes()[index];
      return getComponentValuetype, baseValue, propertyPath.substring(loc+1) );
    }
    else {
      return baseValue;
    }
  }

  /**
   * Extract a component property value.
   *
   @param type The component property types.
   @param component The component instance itself.
   @param propertyPath The property path for the property to be extracted.
   @return The property value extracted.
   */
  protected Object getComponentValue(ComponentType type, Object component, String propertyPath) {
    
    int loc = propertyPath.indexOf('.');
    String basePropertyName = loc>?
      propertyPath.substring(0, loc: propertyPath;
    
    String[] propertyNames = type.getPropertyNames();
    int index=0;
    for ; index<propertyNames.length; index++ ) {
      if basePropertyName.equalspropertyNames[index] ) ) break;
    }
    if (index==propertyNames.length) {
      throw new MappingException"component property not found: " + basePropertyName );
    }
    
    Object baseValue = type.getPropertyValuecomponent, index, getEntityMode() );
    
    if loc>) {
      ComponentType subtype = (ComponentTypetype.getSubtypes()[index];
      return getComponentValuesubtype, baseValue, propertyPath.substring(loc+1) );
    }
    else {
      return baseValue;
    }
    
  }

  public void setPropertyValues(Object entity, Object[] valuesthrows HibernateException {
    boolean setAll = !entityMetamodel.hasLazyProperties();

    for int j = 0; j < entityMetamodel.getPropertySpan(); j++ ) {
      if setAll || values[j!= LazyPropertyInitializer.UNFETCHED_PROPERTY ) {
        setters[j].setentity, values[j], getFactory() );
      }
    }
  }

  public void setPropertyValue(Object entity, int i, Object valuethrows HibernateException {
    setters[i].setentity, value, getFactory() );
  }

  public void setPropertyValue(Object entity, String propertyName, Object valuethrows HibernateException {
    settersentityMetamodel.getPropertyIndexpropertyName ) ].setentity, value, getFactory() );
  }

  public final Object instantiate(Serializable idthrows HibernateException {
    Object result = getInstantiator().instantiateid );
    if id != null ) {
      setIdentifierresult, id );
    }
    return result;
  }

  public final Object instantiate() throws HibernateException {
    return instantiatenull );
  }

  public void afterInitialize(Object entity, boolean lazyPropertiesAreUnfetched, SessionImplementor session) {}

  public boolean hasUninitializedLazyProperties(Object entity) {
    // the default is to simply not lazy fetch properties for now...
    return false;
  }

  public final boolean isInstance(Object object) {
        return getInstantiator().isInstanceobject );
  }

  public boolean hasProxy() {
    return entityMetamodel.isLazy();
  }

  public final Object createProxy(Serializable id, SessionImplementor session)
  throws HibernateException {
    return getProxyFactory().getProxyid, session );
  }

  public boolean isLifecycleImplementor() {
    return false;
  }

  public boolean isValidatableImplementor() {
    return false;
  }
  
  protected final EntityMetamodel getEntityMetamodel() {
    return entityMetamodel;
  }

  protected final SessionFactoryImplementor getFactory() {
    return entityMetamodel.getSessionFactory();
  }

  protected final Instantiator getInstantiator() {
    return instantiator;
  }

  protected final ProxyFactory getProxyFactory() {
    return proxyFactory;
  }
  
  public String toString() {
    return getClass().getName() '(' + getEntityMetamodel().getName() ')';
  }

}