Package org.hibernate.type

Source Code of org.hibernate.type.AnyType$ObjectTypeCacheEntry

/*
* 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.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.Arrays;
import java.util.Map;
import java.util.Set;

import org.hibernate.EntityMode;
import org.hibernate.EntityNameResolver;
import org.hibernate.FetchMode;
import org.hibernate.HibernateException;
import org.hibernate.MappingException;
import org.hibernate.TransientObjectException;
import org.hibernate.engine.internal.ForeignKeys;
import org.hibernate.engine.spi.CascadeStyle;
import org.hibernate.engine.spi.CascadeStyles;
import org.hibernate.engine.spi.Mapping;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.internal.util.collections.ArrayHelper;
import org.hibernate.metamodel.relational.Size;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.persister.entity.Joinable;
import org.hibernate.proxy.HibernateProxy;
import org.hibernate.proxy.HibernateProxyHelper;
import org.hibernate.proxy.LazyInitializer;

import org.dom4j.Node;

/**
* Handles "any" mappings
*
* @author Gavin King
*/
public class AnyType extends AbstractType implements CompositeType, AssociationType {
  private final TypeFactory.TypeScope scope;
  private final Type identifierType;
  private final Type discriminatorType;

  /**
   * Intended for use only from legacy {@link ObjectType} type definition
   *
   * @param discriminatorType
   * @param identifierType
   */
  protected AnyType(Type discriminatorType, Type identifierType) {
    this( null, discriminatorType, identifierType );
  }

  public AnyType(TypeFactory.TypeScope scope, Type discriminatorType, Type identifierType) {
    this.scope = scope;
    this.discriminatorType = discriminatorType;
    this.identifierType = identifierType;
  }

  public Type getIdentifierType() {
    return identifierType;
  }

  public Type getDiscriminatorType() {
    return discriminatorType;
  }


  // general Type metadata ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

  @Override
  public String getName() {
    return "object";
  }

  @Override
  public Class getReturnedClass() {
    return Object.class;
  }

  @Override
  public int[] sqlTypes(Mapping mapping) throws MappingException {
    return ArrayHelper.join( discriminatorType.sqlTypes( mapping ), identifierType.sqlTypes( mapping ) );
  }

  @Override
  public Size[] dictatedSizes(Mapping mapping) throws MappingException {
    return ArrayHelper.join( discriminatorType.dictatedSizes( mapping ), identifierType.dictatedSizes( mapping ) );
  }

  @Override
  public Size[] defaultSizes(Mapping mapping) throws MappingException {
    return ArrayHelper.join( discriminatorType.defaultSizes( mapping ), identifierType.defaultSizes( mapping ) );
  }

  @Override
  public Object[] getPropertyValues(Object component, EntityMode entityMode) {
    throw new UnsupportedOperationException();
  }

  @Override
  public boolean isAnyType() {
    return true;
  }

  @Override
  public boolean isAssociationType() {
    return true;
  }

  @Override
  public boolean isComponentType() {
    return true;
  }

  @Override
  public boolean isEmbedded() {
    return false;
  }

  @Override
  public boolean isMutable() {
    return false;
  }

  @Override
  public Object deepCopy(Object value, SessionFactoryImplementor factory) {
    return value;
  }


  // general Type functionality ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

  @Override
  public int compare(Object x, Object y) {
    if ( x == null ) {
      // if y is also null, return that they are the same (no option for "UNKNOWN")
      // if y is not null, return that y is "greater" (-1 because the result is from the perspective of
      //     the first arg: x)
      return y == null ? 0 : -1;
    }
    else if ( y == null ) {
      // x is not null, but y is.  return that x is "greater"
      return 1;
    }

    // At this point we know both are non-null.
    final Object xId = extractIdentifier( x );
    final Object yId = extractIdentifier( y );

    return getIdentifierType().compare( xId, yId );
  }

  private Object extractIdentifier(Object entity) {
    final EntityPersister concretePersister = guessEntityPersister( entity );
    return concretePersister == null
        ? null
        : concretePersister.getEntityTuplizer().getIdentifier( entity, null );
  }

  private EntityPersister guessEntityPersister(Object object) {
    if ( scope == null ) {
      return null;
    }

    String entityName = null;

    // this code is largely copied from Session's bestGuessEntityName
    Object entity = object;
    if ( entity instanceof HibernateProxy ) {
      final LazyInitializer initializer = ( (HibernateProxy) entity ).getHibernateLazyInitializer();
      if ( initializer.isUninitialized() ) {
        entityName = initializer.getEntityName();
      }
      entity = initializer.getImplementation();
    }

    if ( entityName == null ) {
      for ( EntityNameResolver resolver : scope.resolveFactory().iterateEntityNameResolvers() ) {
        entityName = resolver.resolveEntityName( entity );
        if ( entityName != null ) {
          break;
        }
      }
    }

    if ( entityName == null ) {
      // the old-time stand-by...
      entityName = object.getClass().getName();
    }

    return scope.resolveFactory().getEntityPersister( entityName );
  }

  @Override
  public boolean isSame(Object x, Object y) throws HibernateException {
    return x == y;
  }

  @Override
  public boolean isModified(Object old, Object current, boolean[] checkable, SessionImplementor session)
      throws HibernateException {
    if ( current == null ) {
      return old != null;
    }
    else if ( old == null ) {
      return true;
    }

    final ObjectTypeCacheEntry holder = (ObjectTypeCacheEntry) old;
    final boolean[] idCheckable = new boolean[checkable.length-1];
    System.arraycopy( checkable, 1, idCheckable, 0, idCheckable.length );
    return ( checkable[0] && !holder.entityName.equals( session.bestGuessEntityName( current ) ) )
        || identifierType.isModified( holder.id, getIdentifier( current, session ), idCheckable, session );
  }

  @Override
  public boolean[] toColumnNullness(Object value, Mapping mapping) {
    final boolean[] result = new boolean[ getColumnSpan( mapping ) ];
    if ( value != null ) {
      Arrays.fill( result, true );
    }
    return result;
  }

  @Override
  public boolean isDirty(Object old, Object current, boolean[] checkable, SessionImplementor session)
      throws HibernateException {
    return isDirty( old, current, session );
  }

  @Override
  public int getColumnSpan(Mapping session) {
    return 2;
  }

  @Override
  public Object nullSafeGet(ResultSet rs,  String[] names,  SessionImplementor session,  Object owner)
      throws HibernateException, SQLException {
    return resolveAny(
        (String) discriminatorType.nullSafeGet( rs, names[0], session, owner ),
        (Serializable) identifierType.nullSafeGet( rs, names[1], session, owner ),
        session
    );
  }

  @Override
  public Object hydrate(ResultSet rs,  String[] names,  SessionImplementor session,  Object owner)
      throws HibernateException, SQLException {
    final String entityName = (String) discriminatorType.nullSafeGet( rs, names[0], session, owner );
    final Serializable id = (Serializable) identifierType.nullSafeGet( rs, names[1], session, owner );
    return new ObjectTypeCacheEntry( entityName, id );
  }

  @Override
  public Object resolve(Object value, SessionImplementor session, Object owner) throws HibernateException {
    final ObjectTypeCacheEntry holder = (ObjectTypeCacheEntry) value;
    return resolveAny( holder.entityName, holder.id, session );
  }

  private Object resolveAny(String entityName, Serializable id, SessionImplementor session)
      throws HibernateException {
    return entityName==null || id==null
        ? null
        : session.internalLoad( entityName, id, false, false );
  }

  @Override
  public void nullSafeSet(PreparedStatement st, Object value,  int index, SessionImplementor session)
      throws HibernateException, SQLException {
    nullSafeSet( st, value, index, null, session );
  }

  @Override
  public void nullSafeSet(PreparedStatement st, Object value,  int index, boolean[] settable, SessionImplementor session)
      throws HibernateException, SQLException {
    Serializable id;
    String entityName;
    if ( value == null ) {
      id = null;
      entityName = null;
    }
    else {
      entityName = session.bestGuessEntityName( value );
      id = ForeignKeys.getEntityIdentifierIfNotUnsaved( entityName, value, session );
    }

    // discriminatorType is assumed to be single-column type
    if ( settable == null || settable[0] ) {
      discriminatorType.nullSafeSet( st, entityName, index, session );
    }
    if ( settable == null ) {
      identifierType.nullSafeSet( st, id, index+1, session );
    }
    else {
      final boolean[] idSettable = new boolean[ settable.length-1 ];
      System.arraycopy( settable, 1, idSettable, 0, idSettable.length );
      identifierType.nullSafeSet( st, id, index+1, idSettable, session );
    }
  }

  @Override
  public String toLoggableString(Object value, SessionFactoryImplementor factory) throws HibernateException {
    //TODO: terrible implementation!
    return value == null
        ? "null"
        : factory.getTypeHelper()
        .entity( HibernateProxyHelper.getClassWithoutInitializingProxy( value ) )
        .toLoggableString( value, factory );
  }

  @Override
  public Object assemble(Serializable cached, SessionImplementor session, Object owner) throws HibernateException {
    final ObjectTypeCacheEntry e = (ObjectTypeCacheEntry) cached;
    return e == null ? null : session.internalLoad( e.entityName, e.id, false, false );
  }

  @Override
  public Serializable disassemble(Object value, SessionImplementor session, Object owner) throws HibernateException {
    if ( value == null ) {
      return null;
    }
    else {
      return new ObjectTypeCacheEntry(
          session.bestGuessEntityName( value ),
          ForeignKeys.getEntityIdentifierIfNotUnsaved(
              session.bestGuessEntityName( value ),
              value,
              session
          )
      );
    }
  }

  @Override
  public Object replace(Object original, Object target, SessionImplementor session, Object owner, Map copyCache)
      throws HibernateException {
    if ( original == null ) {
      return null;
    }
    else {
      final String entityName = session.bestGuessEntityName( original );
      final Serializable id = ForeignKeys.getEntityIdentifierIfNotUnsaved( entityName, original, session );
      return session.internalLoad( entityName, id, false, false );
    }
  }

  @Override
  public Object nullSafeGet(ResultSet rs,  String name, SessionImplementor session, Object owner) {
    throw new UnsupportedOperationException( "object is a multicolumn type" );
  }

  @Override
  public Object semiResolve(Object value, SessionImplementor session, Object owner) {
    throw new UnsupportedOperationException( "any mappings may not form part of a property-ref" );
  }

  @Override
  public void setToXMLNode(Node xml, Object value, SessionFactoryImplementor factory) {
    throw new UnsupportedOperationException("any types cannot be stringified");
  }

  @Override
  public Object fromXMLNode(Node xml, Mapping factory) throws HibernateException {
    throw new UnsupportedOperationException();
  }



  // CompositeType implementation ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

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

  private static final String[] PROPERTY_NAMES = new String[] { "class", "id" };

  @Override
  public String[] getPropertyNames() {
    return PROPERTY_NAMES;
  }

  @Override
  public Object getPropertyValue(Object component, int i, SessionImplementor session) throws HibernateException {
    return i==0
        ? session.bestGuessEntityName( component )
        : getIdentifier( component, session );
  }

  @Override
  public Object[] getPropertyValues(Object component, SessionImplementor session) throws HibernateException {
    return new Object[] {
        session.bestGuessEntityName( component ),
        getIdentifier( component, session )
    };
  }

  private Serializable getIdentifier(Object value, SessionImplementor session) throws HibernateException {
    try {
      return ForeignKeys.getEntityIdentifierIfNotUnsaved(
          session.bestGuessEntityName( value ),
          value,
          session
      );
    }
    catch (TransientObjectException toe) {
      return null;
    }
  }

  @Override
  public void setPropertyValues(Object component, Object[] values, EntityMode entityMode) {
    throw new UnsupportedOperationException();
  }

  private static final boolean[] NULLABILITY = new boolean[] { false, false };

  @Override
  public boolean[] getPropertyNullability() {
    return NULLABILITY;
  }

  @Override
  public Type[] getSubtypes() {
    return new Type[] {discriminatorType, identifierType };
  }

  @Override
  public CascadeStyle getCascadeStyle(int i) {
    return CascadeStyles.NONE;
  }

  @Override
  public FetchMode getFetchMode(int i) {
    return FetchMode.SELECT;
  }


  // AssociationType implementation ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

  @Override
  public ForeignKeyDirection getForeignKeyDirection() {
    return ForeignKeyDirection.FOREIGN_KEY_FROM_PARENT;
  }

  @Override
  public boolean useLHSPrimaryKey() {
    return false;
  }

  @Override
  public String getLHSPropertyName() {
    return null;
  }

  public boolean isReferenceToPrimaryKey() {
    return true;
  }

  @Override
  public String getRHSUniqueKeyPropertyName() {
    return null;
  }

  @Override
  public boolean isAlwaysDirtyChecked() {
    return false;
  }

  @Override
  public boolean isEmbeddedInXML() {
    return false;
  }

  @Override
  public Joinable getAssociatedJoinable(SessionFactoryImplementor factory) {
    throw new UnsupportedOperationException("any types do not have a unique referenced persister");
  }

  @Override
  public String getAssociatedEntityName(SessionFactoryImplementor factory) {
    throw new UnsupportedOperationException("any types do not have a unique referenced persister");
  }

  @Override
  public String getOnCondition(String alias, SessionFactoryImplementor factory, Map enabledFilters) {
    throw new UnsupportedOperationException();
  }

  @Override
  public String getOnCondition(
      String alias,
      SessionFactoryImplementor factory,
      Map enabledFilters,
      Set<String> treatAsDeclarations) {
    throw new UnsupportedOperationException();
  }

  /**
   * Used to externalize discrimination per a given identifier.  For example, when writing to
   * second level cache we write the discrimination resolved concrete type for each entity written.
   */
  public static final class ObjectTypeCacheEntry implements Serializable {
    final String entityName;
    final Serializable id;

    ObjectTypeCacheEntry(String entityName, Serializable id) {
      this.entityName = entityName;
      this.id = id;
    }
  }
}
TOP

Related Classes of org.hibernate.type.AnyType$ObjectTypeCacheEntry

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.