/* * 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.loader.plan.build.internal.spaces; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.internal.CoreLogging; import org.hibernate.loader.plan.build.spi.ExpandingCollectionQuerySpace; import org.hibernate.loader.plan.build.spi.ExpandingCompositeQuerySpace; import org.hibernate.loader.plan.build.spi.ExpandingEntityQuerySpace; import org.hibernate.loader.plan.build.spi.ExpandingQuerySpaces; import org.hibernate.loader.plan.spi.QuerySpace; import org.hibernate.loader.plan.spi.QuerySpaceUidNotRegisteredException; import org.hibernate.persister.collection.CollectionPersister; import org.hibernate.persister.entity.EntityPersister; import org.jboss.logging.Logger; /** * @author Steve Ebersole */ public class QuerySpacesImpl implements ExpandingQuerySpaces { private static final Logger log = CoreLogging.logger( QuerySpacesImpl.class ); private final SessionFactoryImplementor sessionFactory; private final List<QuerySpace> roots = new ArrayList<QuerySpace>(); private final Map<String,QuerySpace> querySpaceByUid = new ConcurrentHashMap<String, QuerySpace>(); public QuerySpacesImpl(SessionFactoryImplementor sessionFactory) { this.sessionFactory = sessionFactory; } // QuerySpaces impl ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @Override public List<QuerySpace> getRootQuerySpaces() { return roots; } @Override public QuerySpace findQuerySpaceByUid(String uid) { return querySpaceByUid.get( uid ); } @Override public QuerySpace getQuerySpaceByUid(String uid) { final QuerySpace space = findQuerySpaceByUid( uid ); if ( space == null ) { throw new QuerySpaceUidNotRegisteredException( uid ); } return space; } // ExpandingQuerySpaces impl ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ private int implicitUidBase; @Override public String generateImplicitUid() { return "<gen:" + implicitUidBase++ + ">"; } @Override public ExpandingEntityQuerySpace makeRootEntityQuerySpace(String uid, EntityPersister entityPersister) { final ExpandingEntityQuerySpace space = makeEntityQuerySpace( uid, entityPersister, true ); roots.add( space ); return space; } @Override public ExpandingEntityQuerySpace makeEntityQuerySpace( String uid, EntityPersister entityPersister, boolean canJoinsBeRequired) { checkQuerySpaceDoesNotExist( uid ); // as a temporary fix for HHH-8980 and HHH-8830 we circumvent allowing // inner joins (canJoinsBeRequired) when the persister is part of an // entity inheritance. // // hasSubclasses() is the closest we can come to even knowing if the // entity is part of a hierarchy. But its enough, since if there are no // subclasses we cannot have the case where the attribute to join comes from // a subclass :) // // a better long term fix is to expose whether a joined association attribute // is defined on the class/superClass(es) or on the subClass(es). Attributes // from the subClass(es) should not be inner joined; it is ok to inner join // attributes from the class/superClass(es). final EntityQuerySpaceImpl space = new EntityQuerySpaceImpl( entityPersister, uid, this, canJoinsBeRequired && !entityPersister.getEntityMetamodel().hasSubclasses() ); registerQuerySpace( space ); return space; } @Override public ExpandingCollectionQuerySpace makeRootCollectionQuerySpace(String uid, CollectionPersister collectionPersister) { final ExpandingCollectionQuerySpace space = makeCollectionQuerySpace( uid, collectionPersister, true ); roots.add( space ); return space; } @Override public ExpandingCollectionQuerySpace makeCollectionQuerySpace( String uid, CollectionPersister collectionPersister, boolean canJoinsBeRequired) { checkQuerySpaceDoesNotExist( uid ); final ExpandingCollectionQuerySpace space = new CollectionQuerySpaceImpl( collectionPersister, uid, this, canJoinsBeRequired ); registerQuerySpace( space ); return space; } @Override public ExpandingCompositeQuerySpace makeCompositeQuerySpace( String uid, CompositePropertyMapping compositePropertyMapping, boolean canJoinsBeRequired) { checkQuerySpaceDoesNotExist( uid ); final ExpandingCompositeQuerySpace space = new CompositeQuerySpaceImpl( compositePropertyMapping, uid, this, canJoinsBeRequired ); registerQuerySpace( space ); return space; } @Override public SessionFactoryImplementor getSessionFactory() { return sessionFactory; } private void checkQuerySpaceDoesNotExist(String uid) { if ( querySpaceByUid.containsKey( uid ) ) { throw new IllegalStateException( "Encountered duplicate QuerySpace uid : " + uid ); } } /** * Feeds a QuerySpace into this spaces group. * * @param querySpace The space */ private void registerQuerySpace(QuerySpace querySpace) { log.debugf( "Adding QuerySpace : uid = %s -> %s]", querySpace.getUid(), querySpace ); final QuerySpace previous = querySpaceByUid.put( querySpace.getUid(), querySpace ); if ( previous != null ) { throw new IllegalStateException( "Encountered duplicate QuerySpace uid : " + querySpace.getUid() ); } } }