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

org.hibernate.graph.internal.AttributeNodeImpl Maven / Gradle / Ivy

There is a newer version: 7.0.0.Alpha1
Show newest version
/*
 * Hibernate, Relational Persistence for Idiomatic Java
 *
 * License: GNU Lesser General Public License (LGPL), version 2.1 or later
 * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
 */
package org.hibernate.graph.internal;

import java.util.Collections;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;

import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.graph.CannotContainSubGraphException;
import org.hibernate.graph.SubGraph;
import org.hibernate.graph.spi.AttributeNodeImplementor;
import org.hibernate.graph.spi.SubGraphImplementor;
import org.hibernate.internal.util.collections.CollectionHelper;
import org.hibernate.metamodel.model.domain.spi.PersistentAttributeDescriptor;
import org.hibernate.metamodel.model.domain.spi.ManagedTypeDescriptor;
import org.hibernate.metamodel.model.domain.spi.SimpleTypeDescriptor;

import org.jboss.logging.Logger;

/**
 * Hibernate implementation of the JPA AttributeNode contract
 *
 * @author Steve Ebersole
 */
public class AttributeNodeImpl
		extends AbstractGraphNode
		implements AttributeNodeImplementor {
	private final PersistentAttributeDescriptor attribute;

	private Map, SubGraphImplementor> subGraphMap;
	private Map, SubGraphImplementor> keySubGraphMap;

	@SuppressWarnings("WeakerAccess")
	public  AttributeNodeImpl(
			boolean mutable,
			PersistentAttributeDescriptor attribute,
			SessionFactoryImplementor sessionFactory) {
		this( mutable, attribute, null, null, sessionFactory );
	}

	/**
	 * Intended only for use from making a copy
	 */
	private AttributeNodeImpl(
			boolean mutable,
			PersistentAttributeDescriptor attribute,
			Map, SubGraphImplementor> subGraphMap,
			Map, SubGraphImplementor> keySubGraphMap,
			SessionFactoryImplementor sessionFactory) {
		super( mutable, sessionFactory );
		this.attribute = attribute;
		this.subGraphMap = subGraphMap;
		this.keySubGraphMap = keySubGraphMap;
	}

	@Override
	public String getAttributeName() {
		return getAttributeDescriptor().getName();
	}

	@Override
	public PersistentAttributeDescriptor getAttributeDescriptor() {
		return attribute;
	}

	@Override
	@SuppressWarnings("unchecked")
	public Map, SubGraphImplementor> getSubGraphMap() {
		if ( subGraphMap == null ) {
			return Collections.emptyMap();
		}
		else {
			return (Map) subGraphMap;
		}
	}

	@Override
	@SuppressWarnings("unchecked")
	public Map, SubGraphImplementor> getKeySubGraphMap() {
		if ( keySubGraphMap == null ) {
			return Collections.emptyMap();
		}
		else {
			return keySubGraphMap;
		}
	}

	@Override
	public SubGraphImplementor makeSubGraph() {
		return internalMakeSubgraph( (Class) null );
	}

	@Override
	public  SubGraphImplementor makeSubGraph(Class subtype) {
		return internalMakeSubgraph( subtype );
	}

	@Override
	public  SubGraphImplementor makeSubGraph(ManagedTypeDescriptor subtype) {
		return internalMakeSubgraph( subtype );
	}

	private  SubGraphImplementor internalMakeSubgraph(ManagedTypeDescriptor type) {
		assert type != null;

		log.debugf( "Making sub-graph : ( (%s) %s )", type.getName(), getAttributeName() );

		final SubGraphImplementor subGraph = type.makeSubGraph();
		internalAddSubGraph( type.getJavaType(), subGraph );

		return subGraph;
	}

	@SuppressWarnings("unchecked")
	private  ManagedTypeDescriptor valueGraphTypeAsManaged() {
		final SimpleTypeDescriptor valueGraphType = (SimpleTypeDescriptor) getAttributeDescriptor().getValueGraphType();

		if ( valueGraphType instanceof ManagedTypeDescriptor ) {
			return (ManagedTypeDescriptor) valueGraphType;
		}

		throw new CannotContainSubGraphException(
				String.format(
						Locale.ROOT,
						"Attribute [%s] (%s) cannot contain value sub-graphs",
						getAttributeName(),
						getAttributeDescriptor().getPersistentAttributeType().name()
				)
		);
	}

	private static final Logger log = Logger.getLogger( AttributeNodeImpl.class );

	@SuppressWarnings("unchecked")
	private  SubGraphImplementor internalMakeSubgraph(Class subType) {
		verifyMutability();

		final ManagedTypeDescriptor managedType = valueGraphTypeAsManaged();

		if ( subType == null ) {
			subType = managedType.getJavaType();
		}

		return internalMakeSubgraph( managedType.findSubType( subType ) );
	}

	@SuppressWarnings({"WeakerAccess", "unchecked"})
	protected  void internalAddSubGraph(Class subType, SubGraphImplementor subGraph) {
		log.tracef( "Adding sub-graph : ( (%s) %s )", subGraph.getGraphedType().getName(), getAttributeName() );

		if ( subGraphMap == null ) {
			subGraphMap = new HashMap<>();
		}

		final SubGraphImplementor previous = subGraphMap.put( subType, (SubGraphImplementor) subGraph );
		if ( previous != null ) {
			log.debugf( "Adding sub-graph [%s] over-wrote existing [%s]", subGraph, previous );
		}
	}

	@Override
	@SuppressWarnings("unchecked")
	public  void addSubGraph(Class subType, SubGraph subGraph) {
		verifyMutability();

		internalAddSubGraph( subType, (SubGraphImplementor) subGraph );
	}

	@Override
	public SubGraphImplementor makeKeySubGraph() {
		return internalMakeKeySubgraph( (Class) null );
	}

	@Override
	public  SubGraphImplementor makeKeySubGraph(Class subtype) {
		return internalMakeKeySubgraph( subtype );
	}

	@Override
	public  SubGraphImplementor makeKeySubGraph(ManagedTypeDescriptor subtype) {
		return internalMakeKeySubgraph( subtype );
	}

	private  SubGraphImplementor internalMakeKeySubgraph(ManagedTypeDescriptor type) {

		log.debugf( "Making key sub-graph : ( (%s) %s )", type.getName(), getAttributeName() );

		final SubGraphImplementor subGraph = type.makeSubGraph();
		internalAddKeySubGraph( type.getJavaType(), subGraph );

		return subGraph;
	}

	@SuppressWarnings("unchecked")
	private  SubGraphImplementor internalMakeKeySubgraph(Class type) {
		verifyMutability();

		final ManagedTypeDescriptor managedType = keyGraphTypeAsManaged();

		final ManagedTypeDescriptor subType;

		if ( type == null ) {
			subType = managedType;
		}
		else {
			subType = managedType.findSubType( type );
		}

		subType.getJavaType();

		return internalMakeKeySubgraph( subType );
	}

	@SuppressWarnings({"WeakerAccess", "unchecked"})
	protected  void internalAddKeySubGraph(Class subType, SubGraph subGraph) {
		log.tracef( "Adding key sub-graph : ( (%s) %s )", subType.getName(), getAttributeName() );

		if ( keySubGraphMap == null ) {
			keySubGraphMap = new HashMap<>();
		}

		final SubGraphImplementor previous = keySubGraphMap.put( subType, (SubGraphImplementor) subGraph );
		if ( previous != null ) {
			log.debugf( "Adding key sub-graph [%s] over-wrote existing [%]", subGraph, previous );
		}
	}

	@SuppressWarnings("unchecked")
	private  ManagedTypeDescriptor keyGraphTypeAsManaged() {
		final SimpleTypeDescriptor keyGraphType = (SimpleTypeDescriptor) getAttributeDescriptor().getKeyGraphType();

		if ( keyGraphType instanceof ManagedTypeDescriptor ) {
			return (ManagedTypeDescriptor) keyGraphType;
		}

		throw new CannotContainSubGraphException(
				String.format(
						Locale.ROOT,
						"Attribute [%s#%s] (%s) cannot contain key sub-graphs - %s",
						getAttributeDescriptor().getDeclaringType().getName(),
						getAttributeName(),
						getAttributeDescriptor().getPersistentAttributeType().name(),
						keyGraphType
				)
		);
	}

	@Override
	@SuppressWarnings("unchecked")
	public  void addKeySubGraph(Class subType, SubGraph subGraph) {
		internalAddKeySubGraph( subType, subGraph );
	}

	@Override
	@SuppressWarnings("unchecked")
	public AttributeNodeImplementor makeCopy(boolean mutable) {
		return new AttributeNodeImpl<>(
				mutable,
				this.attribute,
				makeMapCopy( mutable, (Map) subGraphMap ),
				makeMapCopy( mutable, (Map) keySubGraphMap ),
				sessionFactory()
		);
	}

	private  Map, SubGraphImplementor> makeMapCopy(
			boolean mutable,
			Map, SubGraphImplementor> nodeMap) {
		if ( nodeMap == null ) {
			return null;
		}

		return CollectionHelper.makeCopy(
				nodeMap,
				type -> type,
				subGraph -> subGraph.makeCopy( mutable )
		);
	}

	@Override
	@SuppressWarnings("unchecked")
	public void merge(AttributeNodeImplementor attributeNode) {
		attributeNode.visitSubGraphs(
				(incomingSubType, incomingGraph) -> {
					SubGraphImplementor existing = null;
					if ( subGraphMap == null ) {
						subGraphMap = new HashMap<>();
					}
					else {
						existing = subGraphMap.get( incomingSubType );
					}

					if ( existing != null ) {
						existing.merge( incomingGraph );
					}
					else {
						internalAddSubGraph( (Class) incomingSubType, (SubGraphImplementor) incomingGraph.makeCopy( true ) );
					}
				}
		);

		attributeNode.visitKeySubGraphs(
				(incomingSubType, incomingGraph) -> {
					SubGraphImplementor existing = null;
					if ( keySubGraphMap == null ) {
						keySubGraphMap = new HashMap<>();
					}
					else {
						existing = keySubGraphMap.get( incomingSubType );
					}

					if ( existing != null ) {
						existing.merge( incomingGraph );
					}
					else {
						internalAddKeySubGraph( (Class) incomingSubType, (SubGraphImplementor) incomingGraph.makeCopy( true ) );
					}
				}
		);
	}
}