org.hibernate.loader.criteria.CriteriaLoader.java Source code

Java tutorial

Introduction

Here is the source code for org.hibernate.loader.criteria.CriteriaLoader.java

Source

/*
 * 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.criteria;

import java.io.Serializable;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.hibernate.HibernateException;
import org.hibernate.LockMode;
import org.hibernate.LockOptions;
import org.hibernate.QueryException;
import org.hibernate.ScrollMode;
import org.hibernate.Session;
import org.hibernate.dialect.Dialect;
import org.hibernate.engine.spi.LoadQueryInfluencers;
import org.hibernate.engine.spi.QueryParameters;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.internal.CriteriaImpl;
import org.hibernate.internal.util.collections.ArrayHelper;
import org.hibernate.loader.OuterJoinLoader;
import org.hibernate.loader.spi.AfterLoadAction;
import org.hibernate.persister.entity.Loadable;
import org.hibernate.persister.entity.Lockable;
import org.hibernate.persister.entity.OuterJoinLoadable;
import org.hibernate.query.spi.ScrollableResultsImplementor;
import org.hibernate.transform.ResultTransformer;
import org.hibernate.type.Type;

/**
 * A <tt>Loader</tt> for <tt>Criteria</tt> queries. Note that criteria queries are
 * more like multi-object <tt>load()</tt>s than like HQL queries.
 *
 * @author Gavin King
 */
public class CriteriaLoader extends OuterJoinLoader {

    //TODO: this class depends directly upon CriteriaImpl,
    //      in the impl package ... add a CriteriaImplementor
    //      interface

    //NOTE: unlike all other Loaders, this one is NOT
    //      multithreaded, or cacheable!!

    private final CriteriaQueryTranslator translator;
    private final Set<Serializable> querySpaces;
    private final Type[] resultTypes;
    //the user visible aliases, which are unknown to the superclass,
    //these are not the actual "physical" SQL aliases
    private final String[] userAliases;
    private final boolean[] includeInResultRow;
    private final int resultRowLength;

    public CriteriaLoader(final OuterJoinLoadable persister, final SessionFactoryImplementor factory,
            final CriteriaImpl criteria, final String rootEntityName,
            final LoadQueryInfluencers loadQueryInfluencers) throws HibernateException {
        super(factory, loadQueryInfluencers);

        translator = new CriteriaQueryTranslator(factory, criteria, rootEntityName,
                CriteriaQueryTranslator.ROOT_SQL_ALIAS);

        querySpaces = translator.getQuerySpaces();

        CriteriaJoinWalker walker = new CriteriaJoinWalker(persister, translator, factory, criteria, rootEntityName,
                loadQueryInfluencers);

        initFromWalker(walker);

        userAliases = walker.getUserAliases();
        resultTypes = walker.getResultTypes();
        includeInResultRow = walker.includeInResultRow();
        resultRowLength = ArrayHelper.countTrue(includeInResultRow);

        postInstantiate();

    }

    public ScrollableResultsImplementor scroll(SharedSessionContractImplementor session, ScrollMode scrollMode)
            throws HibernateException {
        QueryParameters qp = translator.getQueryParameters();
        qp.setScrollMode(scrollMode);
        return scroll(qp, resultTypes, null, session);
    }

    public List list(SharedSessionContractImplementor session) throws HibernateException {
        return list(session, translator.getQueryParameters(), querySpaces, resultTypes);

    }

    @Override
    protected String[] getResultRowAliases() {
        return userAliases;
    }

    @Override
    protected ResultTransformer resolveResultTransformer(ResultTransformer resultTransformer) {
        return translator.getRootCriteria().getResultTransformer();
    }

    @Override
    protected boolean areResultSetRowsTransformedImmediately() {
        return true;
    }

    @Override
    protected boolean[] includeInResultRow() {
        return includeInResultRow;
    }

    @Override
    protected Object getResultColumnOrRow(Object[] row, ResultTransformer transformer, ResultSet rs,
            SharedSessionContractImplementor session) throws SQLException, HibernateException {
        return resolveResultTransformer(transformer).transformTuple(getResultRow(row, rs, session),
                getResultRowAliases());
    }

    @Override
    protected Object[] getResultRow(Object[] row, ResultSet rs, SharedSessionContractImplementor session)
            throws SQLException, HibernateException {
        final Object[] result;
        if (translator.hasProjection()) {
            Type[] types = translator.getProjectedTypes();
            result = new Object[types.length];
            String[] columnAliases = translator.getProjectedColumnAliases();
            for (int i = 0, pos = 0; i < result.length; i++) {
                int numColumns = types[i].getColumnSpan(session.getFactory());
                if (numColumns > 1) {
                    String[] typeColumnAliases = ArrayHelper.slice(columnAliases, pos, numColumns);
                    result[i] = types[i].nullSafeGet(rs, typeColumnAliases, session, null);
                } else {
                    result[i] = types[i].nullSafeGet(rs, columnAliases[pos], session, null);
                }
                pos += numColumns;
            }
        } else {
            result = toResultRow(row);
        }
        return result;
    }

    private Object[] toResultRow(Object[] row) {
        if (resultRowLength == row.length) {
            return row;
        } else {
            Object[] result = new Object[resultRowLength];
            int j = 0;
            for (int i = 0; i < row.length; i++) {
                if (includeInResultRow[i]) {
                    result[j++] = row[i];
                }
            }
            return result;
        }
    }

    public Set getQuerySpaces() {
        return querySpaces;
    }

    @Override
    protected String applyLocks(String sql, QueryParameters parameters, Dialect dialect,
            List<AfterLoadAction> afterLoadActions) throws QueryException {
        final LockOptions lockOptions = parameters.getLockOptions();

        if (lockOptions == null || (lockOptions.getLockMode() == LockMode.NONE
                && (lockOptions.getAliasLockCount() == 0 || (lockOptions.getAliasLockCount() == 1
                        && lockOptions.getAliasSpecificLockMode("this_") == LockMode.NONE)))) {
            return sql;
        }

        if ((parameters.getLockOptions().getFollowOnLocking() == null && dialect.useFollowOnLocking(parameters))
                || (parameters.getLockOptions().getFollowOnLocking() != null
                        && parameters.getLockOptions().getFollowOnLocking())) {
            final LockMode lockMode = determineFollowOnLockMode(lockOptions);
            if (lockMode != LockMode.UPGRADE_SKIPLOCKED) {
                // Dialect prefers to perform locking in a separate step
                LOG.usingFollowOnLocking();

                final LockOptions lockOptionsToUse = new LockOptions(lockMode);
                lockOptionsToUse.setTimeOut(lockOptions.getTimeOut());
                lockOptionsToUse.setScope(lockOptions.getScope());

                afterLoadActions.add(new AfterLoadAction() {
                    @Override
                    public void afterLoad(SharedSessionContractImplementor session, Object entity,
                            Loadable persister) {
                        ((Session) session).buildLockRequest(lockOptionsToUse).lock(persister.getEntityName(),
                                entity);
                    }
                });
                parameters.setLockOptions(new LockOptions());
                return sql;
            }
        }
        final LockOptions locks = new LockOptions(lockOptions.getLockMode());
        locks.setScope(lockOptions.getScope());
        locks.setTimeOut(lockOptions.getTimeOut());

        final Map<String, String[]> keyColumnNames = dialect.forUpdateOfColumns() ? new HashMap() : null;
        final String[] drivingSqlAliases = getAliases();
        for (int i = 0; i < drivingSqlAliases.length; i++) {
            final LockMode lockMode = lockOptions.getAliasSpecificLockMode(drivingSqlAliases[i]);
            if (lockMode != null) {
                final Lockable drivingPersister = (Lockable) getEntityPersisters()[i];
                final String rootSqlAlias = drivingPersister.getRootTableAlias(drivingSqlAliases[i]);
                locks.setAliasSpecificLockMode(rootSqlAlias, lockMode);
                if (keyColumnNames != null) {
                    keyColumnNames.put(rootSqlAlias, drivingPersister.getRootTableIdentifierColumnNames());
                }
            }
        }
        return dialect.applyLocksToSql(sql, locks, keyColumnNames);
    }

    @Override
    protected LockMode determineFollowOnLockMode(LockOptions lockOptions) {
        final LockMode lockModeToUse = lockOptions.findGreatestLockMode();

        if (lockOptions.getAliasLockCount() > 1) {
            // > 1 here because criteria always uses alias map for the root lock mode (under 'this_')
            LOG.aliasSpecificLockingWithFollowOnLocking(lockModeToUse);
        }

        return lockModeToUse;
    }

    @Override
    protected LockMode[] getLockModes(LockOptions lockOptions) {
        final String[] entityAliases = getAliases();
        if (entityAliases == null) {
            return null;
        }
        final int size = entityAliases.length;
        LockMode[] lockModesArray = new LockMode[size];
        for (int i = 0; i < size; i++) {
            LockMode lockMode = lockOptions.getAliasSpecificLockMode(entityAliases[i]);
            lockModesArray[i] = lockMode == null ? lockOptions.getLockMode() : lockMode;
        }
        return lockModesArray;
    }

    @Override
    protected boolean isSubselectLoadingEnabled() {
        return hasSubselectLoadableCollections();
    }

    @Override
    protected List getResultList(List results, ResultTransformer resultTransformer) {
        return resolveResultTransformer(resultTransformer).transformList(results);
    }

    @Override
    protected String getQueryIdentifier() {
        return "[CRITERIA] " + getSQLString();
    }

}