org.babyfish.hibernate.hql.XQueryPlan.java Source code

Java tutorial

Introduction

Here is the source code for org.babyfish.hibernate.hql.XQueryPlan.java

Source

/*
 * BabyFish, Object Model Framework for Java and JPA.
 * https://github.com/babyfish-ct/babyfish
 *
 * Copyright (c) 2008-2015, Tao Chen
 *
 * 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.
 *
 * Please visit "http://opensource.org/licenses/LGPL-3.0" to know more.
 *
 * 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.
 */
package org.babyfish.hibernate.hql;

import java.util.List;
import java.util.Map;
import java.util.Set;

import org.babyfish.collection.ArrayList;
import org.babyfish.collection.LinkedHashSet;
import org.babyfish.collection.ReferenceEqualityComparator;
import org.babyfish.hibernate.cfg.Configuration;
import org.babyfish.hibernate.cfg.SettingsFactory;
import org.babyfish.persistence.QueryType;
import org.babyfish.persistence.path.spi.PathPlanKey;
import org.babyfish.util.LazyResource;
import org.hibernate.Filter;
import org.hibernate.QueryException;
import org.hibernate.engine.query.spi.EntityGraphQueryHint;
import org.hibernate.engine.query.spi.HQLQueryPlan;
import org.hibernate.engine.spi.QueryParameters;
import org.hibernate.engine.spi.RowSelection;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.hql.spi.QueryTranslator;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * @author Tao Chen
 */
public class XQueryPlan extends HQLQueryPlan {

    private static final long serialVersionUID = 4858445245681674156L;

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

    private static final LazyResource<Resource> LAZY_RESOURCE = LazyResource.of(Resource.class);

    private static final ThreadLocal<Object> PATH_PLAN_KEY_TL = new ThreadLocal<Object>();

    private PathPlanKey pathPlanKey;

    static void registerPathPlanKey(PathPlanKey pathPlanKey) {
        PATH_PLAN_KEY_TL.set(pathPlanKey != null ? pathPlanKey : new Object());
    }

    public static PathPlanKey currentPathPlanKey() {
        Object o = PATH_PLAN_KEY_TL.get();
        if (o == null && !Configuration.isPathPlanKeyVlidationSuspended()) {
            throw new IllegalStateException(LAZY_RESOURCE.get().notDuringAnyInvocation(XQueryPlanCache.class,
                    "getHQLQueryPlan", new Class[] { String.class, boolean.class, Map.class },
                    new Class[] { String.class, PathPlanKey.class, boolean.class, Map.class }));
        }
        return o instanceof PathPlanKey ? (PathPlanKey) o : null;
    }

    protected XQueryPlan(String hql, boolean shallow, Map<String, Filter> enabledFilters,
            SessionFactoryImplementor factory) {
        super(hql, shallow, enabledFilters, factory);
        this.pathPlanKey = currentPathPlanKey();
        PATH_PLAN_KEY_TL.remove();
    }

    protected XQueryPlan(String hql, String collectionRole, boolean shallow, Map<String, Filter> enabledFilters,
            SessionFactoryImplementor factory, EntityGraphQueryHint entityGraphQueryHint) {
        super(hql, collectionRole, shallow, enabledFilters, factory, entityGraphQueryHint);
        this.pathPlanKey = currentPathPlanKey();
        PATH_PLAN_KEY_TL.remove();
    }

    public final PathPlanKey getPathPlanKey() {
        return this.pathPlanKey;
    }

    public <T> List<T> performList(SessionImplementor session, QueryParameters queryParameters,
            QueryType queryMode) {
        if (log.isTraceEnabled()) {
            log.trace("find: " + getSourceQuery());
            queryParameters.traceParameters(session.getFactory());
        }
        QueryTranslator[] translators = this.getTranslators();
        boolean hasLimit = queryParameters.getRowSelection() != null
                && queryParameters.getRowSelection().definesLimits();
        boolean needsMemoryLimit = hasLimit && translators.length > 1;
        QueryParameters queryParametersToUse;
        if (needsMemoryLimit) {
            if (!SettingsFactory.isLimitInMemoryEnabled(session.getFactory().getProperties())) {
                throw new QueryException(LAZY_RESOURCE.get().hibernateLimitInMemoryForPolymorphicQueryIsNotEnabled(
                        SettingsFactory.ENABLE_LIMIT_IN_MEMORY));
            }
            log.warn("firstResult/maxResults specified on polymorphic query; applying in memory!");
            RowSelection selection = new RowSelection();
            selection.setFetchSize(queryParameters.getRowSelection().getFetchSize());
            selection.setTimeout(queryParameters.getRowSelection().getTimeout());
            queryParametersToUse = queryParameters.createCopyUsing(selection);
        } else {
            queryParametersToUse = queryParameters;
        }

        List<T> combinedResults = new ArrayList<T>();
        Set<T> distinction = new LinkedHashSet<T>(ReferenceEqualityComparator.getInstance());
        int includedCount = -1;
        translator_loop: for (int i = 0; i < translators.length; i++) {
            List<T> tmp = ((XQueryTranslator) translators[i]).list(session, queryParametersToUse, queryMode);
            if (needsMemoryLimit) {
                // NOTE : firstRow is zero-based
                int first = queryParameters.getRowSelection().getFirstRow() == null ? 0
                        : queryParameters.getRowSelection().getFirstRow().intValue();
                int max = queryParameters.getRowSelection().getMaxRows() == null ? -1
                        : queryParameters.getRowSelection().getMaxRows().intValue();
                final int size = tmp.size();
                for (int x = 0; x < size; x++) {
                    final T result = tmp.get(x);
                    if (!distinction.add(result)) {
                        continue;
                    }
                    includedCount++;
                    if (includedCount < first) {
                        continue;
                    }
                    combinedResults.add(result);
                    if (max >= 0 && includedCount > max) {
                        break translator_loop; // break the outer loop !!!
                    }
                }
            } else {
                if (translators.length == 1) {
                    return tmp;
                } else {
                    combinedResults.addAll(tmp);
                }
            }
        }
        return combinedResults;
    }

    public long performUnlimitedCount(SessionImplementor session, QueryParameters queryParameters,
            QueryType queryType) {
        long count = 0;
        for (QueryTranslator translator : this.getTranslators()) {
            XQueryTranslator xTranslator = (XQueryTranslator) translator;
            count += xTranslator.unlimitedCount(session, queryParameters, queryType);
        }
        return count;
    }

    private interface Resource {

        String notDuringAnyInvocation(Class<XQueryPlanCache> ownerType, String methodName,
                Class<?>[] parameterTypes1, Class<?>[] parameterTypes2);

        String hibernateLimitInMemoryForPolymorphicQueryIsNotEnabled(String configurationPropertyName);
    }
}