All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.hibernate.metamodel.binding.EntityBinding Maven / Gradle / Ivy

There is a newer version: 7.0.0.Alpha1
Show newest version
/*
 * 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.binding;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.hibernate.AssertionFailure;
import org.hibernate.EntityMode;
import org.hibernate.engine.spi.FilterDefinition;
import org.hibernate.internal.util.ValueHolder;
import org.hibernate.internal.util.collections.JoinedIterable;
import org.hibernate.metamodel.domain.AttributeContainer;
import org.hibernate.metamodel.domain.Entity;
import org.hibernate.metamodel.domain.PluralAttribute;
import org.hibernate.metamodel.domain.PluralAttributeNature;
import org.hibernate.metamodel.domain.SingularAttribute;
import org.hibernate.metamodel.relational.TableSpecification;
import org.hibernate.metamodel.source.MetaAttributeContext;
import org.hibernate.metamodel.source.binder.JpaCallbackClass;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.tuple.entity.EntityTuplizer;

/**
 * Provides the link between the domain and the relational model for an entity.
 *
 * @author Steve Ebersole
 * @author Hardy Ferentschik
 * @author Gail Badner
 */
public class EntityBinding implements AttributeBindingContainer {
	private static final String NULL_DISCRIMINATOR_MATCH_VALUE = "null";
	private static final String NOT_NULL_DISCRIMINATOR_MATCH_VALUE = "not null";

	private final EntityBinding superEntityBinding;
	private final List subEntityBindings = new ArrayList();
	private final HierarchyDetails hierarchyDetails;

	private Entity entity;
	private TableSpecification primaryTable;
    private String primaryTableName;
	private Map secondaryTables = new HashMap();

	private ValueHolder> proxyInterfaceType;

	private String jpaEntityName;

	private Class customEntityPersisterClass;
	private Class customEntityTuplizerClass;

	private String discriminatorMatchValue;

	private Set filterDefinitions = new HashSet();
	private Set entityReferencingAttributeBindings = new HashSet();

	private MetaAttributeContext metaAttributeContext;

	private boolean lazy;
	private boolean mutable;
	private String whereFilter;
	private String rowId;

	private boolean dynamicUpdate;
	private boolean dynamicInsert;

	private int batchSize;
	private boolean selectBeforeUpdate;
	private boolean hasSubselectLoadableCollections;

	private Boolean isAbstract;

	private String customLoaderName;
	private CustomSQL customInsert;
	private CustomSQL customUpdate;
	private CustomSQL customDelete;

	private Set synchronizedTableNames = new HashSet();
	private Map attributeBindingMap = new HashMap();

    private List jpaCallbackClasses = new ArrayList();

	/**
	 * Used to instantiate the EntityBinding for an entity that is the root of an inheritance hierarchy
	 *
	 * @param inheritanceType The inheritance type for the hierarchy
	 * @param entityMode The entity mode used in this hierarchy.
	 */
	public EntityBinding(InheritanceType inheritanceType, EntityMode entityMode) {
		this.superEntityBinding = null;
		this.hierarchyDetails = new HierarchyDetails( this, inheritanceType, entityMode );
	}

	/**
	 * Used to instantiate the EntityBinding for an entity that is a subclass (sub-entity) in an inheritance hierarchy
	 *
	 * @param superEntityBinding The entity binding of this binding's super
	 */
	public EntityBinding(EntityBinding superEntityBinding) {
		this.superEntityBinding = superEntityBinding;
		this.superEntityBinding.subEntityBindings.add( this );
		this.hierarchyDetails = superEntityBinding.getHierarchyDetails();
	}

	public HierarchyDetails getHierarchyDetails() {
		return hierarchyDetails;
	}

	public EntityBinding getSuperEntityBinding() {
		return superEntityBinding;
	}

	public boolean isRoot() {
		return superEntityBinding == null;
	}

	public boolean isPolymorphic() {
		return  superEntityBinding != null ||
				hierarchyDetails.getEntityDiscriminator() != null ||
				! subEntityBindings.isEmpty();
	}

	public boolean hasSubEntityBindings() {
		return subEntityBindings.size() > 0;
	}

	public int getSubEntityBindingClosureSpan() {
		int n = subEntityBindings.size();
		for ( EntityBinding subEntityBinding : subEntityBindings ) {
			n += subEntityBinding.getSubEntityBindingClosureSpan();
		}
		return n;
	}

	/* used for testing */
	public Iterable getDirectSubEntityBindings() {
		return subEntityBindings;
	}

	/**
	 * Returns sub-EntityBinding objects in a special 'order', most derived subclasses
	 * first. Specifically, the sub-entity bindings follow a depth-first,
	 * post-order traversal
	 *
	 * Note that the returned value excludes this entity binding.
	 *
	 * @return sub-entity bindings ordered by those entity bindings that are most derived.
	 */
	public Iterable getPostOrderSubEntityBindingClosure() {
		// TODO: why this order?
		List> subclassIterables = new ArrayList>( subEntityBindings.size() + 1 );
		for ( EntityBinding subEntityBinding : subEntityBindings ) {
			Iterable subSubEntityBindings = subEntityBinding.getPostOrderSubEntityBindingClosure();
			if ( subSubEntityBindings.iterator().hasNext() ) {
				subclassIterables.add( subSubEntityBindings );
			}
		}
		if ( ! subEntityBindings.isEmpty() ) {
			subclassIterables.add( subEntityBindings );
		}
		return new JoinedIterable( subclassIterables );
	}

	/**
	 * Returns sub-EntityBinding ordered as a depth-first,
	 * pre-order traversal (a subclass precedes its own subclasses).
	 *
	 * Note that the returned value specifically excludes this entity binding.
	 *
	 * @return sub-entity bindings ordered as a depth-first,
	 * pre-order traversal
	 */
	public Iterable getPreOrderSubEntityBindingClosure() {
		return getPreOrderSubEntityBindingClosure( false );
	}

	private Iterable getPreOrderSubEntityBindingClosure(boolean includeThis) {
		List> iterables = new ArrayList>();
		if ( includeThis ) {
			iterables.add( java.util.Collections.singletonList( this ) );
		}
		for ( EntityBinding subEntityBinding : subEntityBindings ) {
			Iterable subSubEntityBindingClosure =  subEntityBinding.getPreOrderSubEntityBindingClosure( true );
			if ( subSubEntityBindingClosure.iterator().hasNext() ) {
				iterables.add( subSubEntityBindingClosure );
			}
		}
		return new JoinedIterable( iterables );
	}

	public Entity getEntity() {
		return entity;
	}

	public void setEntity(Entity entity) {
		this.entity = entity;
	}

	public TableSpecification getPrimaryTable() {
		return primaryTable;
	}

	public void setPrimaryTable(TableSpecification primaryTable) {
		this.primaryTable = primaryTable;
	}

    public TableSpecification locateTable(String tableName) {
        if ( tableName == null || tableName.equals( getPrimaryTableName() ) ) {
            return primaryTable;
        }
        TableSpecification tableSpec = secondaryTables.get( tableName );
        if ( tableSpec == null ) {
            throw new AssertionFailure(
                    String.format(
                            "Unable to find table %s amongst tables %s",
                            tableName,
                            secondaryTables.keySet()
                    )
            );
        }
        return tableSpec;
    }
    public String getPrimaryTableName() {
        return primaryTableName;
    }

    public void setPrimaryTableName(String primaryTableName) {
        this.primaryTableName = primaryTableName;
    }

	public void addSecondaryTable(String tableName, TableSpecification table) {
		secondaryTables.put( tableName, table );
	}

	public boolean isVersioned() {
		return getHierarchyDetails().getVersioningAttributeBinding() != null;
	}

	public boolean isDiscriminatorMatchValueNull() {
		return NULL_DISCRIMINATOR_MATCH_VALUE.equals( discriminatorMatchValue );
	}

	public boolean isDiscriminatorMatchValueNotNull() {
		return NOT_NULL_DISCRIMINATOR_MATCH_VALUE.equals( discriminatorMatchValue );
	}

	public String getDiscriminatorMatchValue() {
		return discriminatorMatchValue;
	}

	public void setDiscriminatorMatchValue(String discriminatorMatchValue) {
		this.discriminatorMatchValue = discriminatorMatchValue;
	}

	public Iterable getFilterDefinitions() {
		return filterDefinitions;
	}

	public void addFilterDefinition(FilterDefinition filterDefinition) {
		filterDefinitions.add( filterDefinition );
	}

	public Iterable getEntityReferencingAttributeBindings() {
		return entityReferencingAttributeBindings;
	}

	@Override
	public EntityBinding seekEntityBinding() {
		return this;
	}

	@Override
	public String getPathBase() {
		return getEntity().getName();
	}

	@Override
	public Class getClassReference() {
		return getEntity().getClassReference();
	}

	@Override
	public AttributeContainer getAttributeContainer() {
		return getEntity();
	}

	protected void registerAttributeBinding(String name, AttributeBinding attributeBinding) {
		if ( SingularAssociationAttributeBinding.class.isInstance( attributeBinding ) ) {
			entityReferencingAttributeBindings.add( (SingularAssociationAttributeBinding) attributeBinding );
		}
		attributeBindingMap.put( name, attributeBinding );
	}

	@Override
	public MetaAttributeContext getMetaAttributeContext() {
		return metaAttributeContext;
	}

	public void setMetaAttributeContext(MetaAttributeContext metaAttributeContext) {
		this.metaAttributeContext = metaAttributeContext;
	}

	public boolean isMutable() {
		return mutable;
	}

	public void setMutable(boolean mutable) {
		this.mutable = mutable;
	}

	public boolean isLazy() {
		return lazy;
	}

	public void setLazy(boolean lazy) {
		this.lazy = lazy;
	}

	public ValueHolder> getProxyInterfaceType() {
		return proxyInterfaceType;
	}

	public void setProxyInterfaceType(ValueHolder> proxyInterfaceType) {
		this.proxyInterfaceType = proxyInterfaceType;
	}

	public String getWhereFilter() {
		return whereFilter;
	}

	public void setWhereFilter(String whereFilter) {
		this.whereFilter = whereFilter;
	}

	public String getRowId() {
		return rowId;
	}

	public void setRowId(String rowId) {
		this.rowId = rowId;
	}

	public boolean isDynamicUpdate() {
		return dynamicUpdate;
	}

	public void setDynamicUpdate(boolean dynamicUpdate) {
		this.dynamicUpdate = dynamicUpdate;
	}

	public boolean isDynamicInsert() {
		return dynamicInsert;
	}

	public void setDynamicInsert(boolean dynamicInsert) {
		this.dynamicInsert = dynamicInsert;
	}

	public int getBatchSize() {
		return batchSize;
	}

	public void setBatchSize(int batchSize) {
		this.batchSize = batchSize;
	}

	public boolean isSelectBeforeUpdate() {
		return selectBeforeUpdate;
	}

	public void setSelectBeforeUpdate(boolean selectBeforeUpdate) {
		this.selectBeforeUpdate = selectBeforeUpdate;
	}

	public boolean hasSubselectLoadableCollections() {
		return hasSubselectLoadableCollections;
	}

	/* package-protected */
	void setSubselectLoadableCollections(boolean hasSubselectLoadableCollections) {
		this.hasSubselectLoadableCollections = hasSubselectLoadableCollections;
	}

	public Class getCustomEntityPersisterClass() {
		return customEntityPersisterClass;
	}

	public void setCustomEntityPersisterClass(Class customEntityPersisterClass) {
		this.customEntityPersisterClass = customEntityPersisterClass;
	}

	public Class getCustomEntityTuplizerClass() {
		return customEntityTuplizerClass;
	}

	public void setCustomEntityTuplizerClass(Class customEntityTuplizerClass) {
		this.customEntityTuplizerClass = customEntityTuplizerClass;
	}

	public Boolean isAbstract() {
		return isAbstract;
	}

	public void setAbstract(Boolean isAbstract) {
		this.isAbstract = isAbstract;
	}

	public Set getSynchronizedTableNames() {
		return synchronizedTableNames;
	}

	public void addSynchronizedTableNames(java.util.Collection synchronizedTableNames) {
		this.synchronizedTableNames.addAll( synchronizedTableNames );
	}

	public String getJpaEntityName() {
		return jpaEntityName;
	}

	public void setJpaEntityName(String jpaEntityName) {
		this.jpaEntityName = jpaEntityName;
	}

	public String getCustomLoaderName() {
		return customLoaderName;
	}

	public void setCustomLoaderName(String customLoaderName) {
		this.customLoaderName = customLoaderName;
	}

	public CustomSQL getCustomInsert() {
		return customInsert;
	}

	public void setCustomInsert(CustomSQL customInsert) {
		this.customInsert = customInsert;
	}

	public CustomSQL getCustomUpdate() {
		return customUpdate;
	}

	public void setCustomUpdate(CustomSQL customUpdate) {
		this.customUpdate = customUpdate;
	}

	public CustomSQL getCustomDelete() {
		return customDelete;
	}

	public void setCustomDelete(CustomSQL customDelete) {
		this.customDelete = customDelete;
	}

	@Override
	public String toString() {
		final StringBuilder sb = new StringBuilder();
		sb.append( "EntityBinding" );
		sb.append( "{entity=" ).append( entity != null ? entity.getName() : "not set" );
		sb.append( '}' );
		return sb.toString();
	}

	@Override
	public BasicAttributeBinding makeBasicAttributeBinding(SingularAttribute attribute) {
		return makeSimpleAttributeBinding( attribute, false, false );
	}

	private BasicAttributeBinding makeSimpleAttributeBinding(SingularAttribute attribute, boolean forceNonNullable, boolean forceUnique) {
		final BasicAttributeBinding binding = new BasicAttributeBinding(
				this,
				attribute,
				forceNonNullable,
				forceUnique
		);
		registerAttributeBinding( attribute.getName(), binding );
		return binding;
	}

	@Override
	public ComponentAttributeBinding makeComponentAttributeBinding(SingularAttribute attribute) {
		final ComponentAttributeBinding binding = new ComponentAttributeBinding( this, attribute );
		registerAttributeBinding( attribute.getName(), binding );
		return binding;
	}

	@Override
	public ManyToOneAttributeBinding makeManyToOneAttributeBinding(SingularAttribute attribute) {
		final ManyToOneAttributeBinding binding = new ManyToOneAttributeBinding( this, attribute );
		registerAttributeBinding( attribute.getName(), binding );
		return binding;
	}

	@Override
	public BagBinding makeBagAttributeBinding(PluralAttribute attribute, CollectionElementNature nature) {
		Helper.checkPluralAttributeNature( attribute, PluralAttributeNature.BAG );
		final BagBinding binding = new BagBinding( this, attribute, nature );
		registerAttributeBinding( attribute.getName(), binding );
		return binding;
	}

	@Override
	public SetBinding makeSetAttributeBinding(PluralAttribute attribute, CollectionElementNature nature) {
		Helper.checkPluralAttributeNature( attribute, PluralAttributeNature.SET );
		final SetBinding binding = new SetBinding( this, attribute, nature );
		registerAttributeBinding( attribute.getName(), binding );
		return binding;
	}

	@Override
	public AttributeBinding locateAttributeBinding(String name) {
		return attributeBindingMap.get( name );
	}

	@Override
	public Iterable attributeBindings() {
		return attributeBindingMap.values();
	}

	/**
	 * Gets the number of attribute bindings defined on this class, including the
	 * identifier attribute binding and attribute bindings defined
	 * as part of a join.
	 *
	 * @return The number of attribute bindings
	 */
	public int getAttributeBindingClosureSpan() {
		// TODO: update account for join attribute bindings
		return superEntityBinding != null ?
				superEntityBinding.getAttributeBindingClosureSpan() + attributeBindingMap.size() :
				attributeBindingMap.size();
	}

	/**
	 * Gets the attribute bindings defined on this class, including the
	 * identifier attribute binding and attribute bindings defined
	 * as part of a join.
	 *
	 * @return The attribute bindings.
	 */
	public Iterable getAttributeBindingClosure() {
		// TODO: update size to account for joins
		Iterable iterable;
		if ( superEntityBinding != null ) {
			List> iterables = new ArrayList>( 2 );
			iterables.add( superEntityBinding.getAttributeBindingClosure() );
			iterables.add( attributeBindings() );
			iterable = new JoinedIterable( iterables );
		}
		else {
			iterable = attributeBindings();
		}
		return iterable;
	}

	/**
	 * Gets the attribute bindings for this EntityBinding and all of its
	 * sub-EntityBinding, starting from the root of the hierarchy; includes
	 * the identifier and attribute bindings defined as part of a join.
	 * @return
	 */
	public Iterable getSubEntityAttributeBindingClosure() {
		List> iterables = new ArrayList>();
		iterables.add( getAttributeBindingClosure() );
		for ( EntityBinding subEntityBinding : getPreOrderSubEntityBindingClosure() ) {
			// only add attribute bindings declared for the subEntityBinding
			iterables.add( subEntityBinding.attributeBindings() );
			// TODO: if EntityBinding.attributeBindings() excludes joined attributes, then they need to be added here
		}
		return new JoinedIterable( iterables );
	}

	public void setJpaCallbackClasses( List jpaCallbackClasses ) {
	    this.jpaCallbackClasses = jpaCallbackClasses;
	}

    public Iterable getJpaCallbackClasses() {
        return jpaCallbackClasses;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy