org.hibernate.engine.spi.SubselectFetch.java Source code

Java tutorial

Introduction

Here is the source code for org.hibernate.engine.spi.SubselectFetch.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.engine.spi;

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

import org.jboss.logging.Logger;

import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.internal.util.StringHelper;
import org.hibernate.persister.entity.Loadable;
import org.hibernate.persister.entity.PropertyMapping;

/**
 * @author Gavin King
 */
public class SubselectFetch {
    private static final CoreMessageLogger LOG = Logger.getMessageLogger(CoreMessageLogger.class,
            SubselectFetch.class.getName());

    private static final String FROM_STRING = " from ";

    private final Set resultingEntityKeys;
    private final String queryString;
    private final String alias;
    private final Loadable loadable;
    private final QueryParameters queryParameters;
    private final Map namedParameterLocMap;

    /**
     * Construct a SubselectFetch instance. The subselect fetch query fragment is generated by
     * {@link #createSubselectFetchQueryFragment}.
     *
     * If the same value for {@code queryParameters} is to be used when constructing multiple
     * SubselectFetch objects, then it is preferable to generate the subselect fetch query
     * fragment using {@link #createSubselectFetchQueryFragment}, and pass the result as an
     * argument to constructor {@link #SubselectFetch(String, String, Loadable, QueryParameters, Set, Map)}.
     *
     * @param alias - the table alias used in the subselect fetch query fragment
     * (to be generated by {@link #createSubselectFetchQueryFragment(QueryParameters)} that
     * corresponds to {@code loadable};
     * @param loadable - the {@link Loadable} for the associated entities to be subselect fetched;
     * @param queryParameters - the query parameters;
     * @param resultingEntityKeys - the {@link EntityKey} objects for the entities to be subselect fetched;
     * @param namedParameterLocMap - mapping from named parameter to the parameter index located in the
     * subselect fetch query fragment.
     *
     * @see #SubselectFetch(String, String, Loadable, QueryParameters, Set, Map)
     */
    public SubselectFetch(final String alias, final Loadable loadable, final QueryParameters queryParameters,
            final Set resultingEntityKeys, final Map namedParameterLocMap) {
        this(createSubselectFetchQueryFragment(queryParameters), alias, loadable, queryParameters,
                resultingEntityKeys, namedParameterLocMap);
    }

    /**
     * Construct a SubselectFetch instance using the provided subselect fetch query fragment,
     * {@code subselectFetchQueryFragment}. It is assumed that {@code subselectFetchQueryFragment}
     * is the result of calling {@link #createSubselectFetchQueryFragment} with the same value
     * provided for {@code queryParameters}.
     *
     * @param subselectFetchQueryFragment - the subselect fetch query fragment;
     * @param alias - the table alias used in {@code subselectFetchQueryFragment} that
     * corresponds to {@code loadable};
     * @param loadable - the {@link Loadable} for the associated entities to be subselect fetched;
     * @param queryParameters - the query parameters;
     * @param resultingEntityKeys - the {@link EntityKey} objects for the entities to be subselect fetched;
     * @param namedParameterLocMap - mapping from named parameter to the parameter index located in the
     * subselect fetch query fragment.
     */
    public SubselectFetch(final String subselectFetchQueryFragment, final String alias, final Loadable loadable,
            final QueryParameters queryParameters, final Set resultingEntityKeys, final Map namedParameterLocMap) {
        this.resultingEntityKeys = resultingEntityKeys;
        this.queryParameters = queryParameters;
        this.namedParameterLocMap = namedParameterLocMap;
        this.loadable = loadable;
        this.alias = alias;

        this.queryString = subselectFetchQueryFragment;
    }

    /**
     * Create the subselect fetch query fragment for the provided {@link QueryParameters}
     * with SELECT and ORDER BY clauses removed.
     *
     * @param queryParameters -the query parameters.
     * @return the subselect fetch query fragment.
     */
    public static String createSubselectFetchQueryFragment(QueryParameters queryParameters) {
        //TODO: ugly here:
        final String queryString = queryParameters.getFilteredSQL();
        final int fromIndex = getFromIndex(queryString);
        final int orderByIndex = queryString.lastIndexOf("order by");
        final String subselectQueryFragment = orderByIndex > 0 ? queryString.substring(fromIndex, orderByIndex)
                : queryString.substring(fromIndex);
        if (LOG.isTraceEnabled()) {
            LOG.tracef("SubselectFetch query fragment: %s", subselectQueryFragment);
        }
        return subselectQueryFragment;
    }

    private static int getFromIndex(String queryString) {
        int index = queryString.indexOf(FROM_STRING);

        if (index < 0) {
            return index;
        }

        while (!parenthesesMatch(queryString.substring(0, index))) {
            String subString = queryString.substring(index + FROM_STRING.length());

            int subIndex = subString.indexOf(FROM_STRING);

            if (subIndex < 0) {
                return subIndex;
            }

            index += FROM_STRING.length() + subIndex;
        }

        return index;
    }

    private static boolean parenthesesMatch(String string) {
        int parenCount = 0;

        for (int i = 0; i < string.length(); i++) {
            char character = string.charAt(i);

            if (character == '(') {
                parenCount++;
            } else if (character == ')') {
                parenCount--;
            }
        }

        return parenCount == 0;
    }

    public QueryParameters getQueryParameters() {
        return queryParameters;
    }

    /**
     * Get the Set of EntityKeys
     */
    public Set getResult() {
        return resultingEntityKeys;
    }

    public String toSubselectString(String ukname) {
        String[] joinColumns = ukname == null ? StringHelper.qualify(alias, loadable.getIdentifierColumnNames())
                : ((PropertyMapping) loadable).toColumns(alias, ukname);

        return "select " + String.join(", ", joinColumns) + queryString;
    }

    @Override
    public String toString() {
        return "SubselectFetch(" + queryString + ')';
    }

    public Map getNamedParameterLocMap() {
        return namedParameterLocMap;
    }

}