gov.nih.nci.cabig.ctms.tools.hibernate.MoreRestrictions.java Source code

Java tutorial

Introduction

Here is the source code for gov.nih.nci.cabig.ctms.tools.hibernate.MoreRestrictions.java

Source

/*
 * Copyright Northwestern University and SemanticBits, LLC
 * 
 * Distributed under the OSI-approved BSD 3-Clause License.
 * See http://ncip.github.com/ctms-commons/LICENSE.txt for details.
 */
package gov.nih.nci.cabig.ctms.tools.hibernate;

import org.hibernate.criterion.Criterion;
import org.hibernate.criterion.Disjunction;
import org.hibernate.criterion.Restrictions;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;

/**
 * Hibernate criteria builder whose "in" can automatically segment the value list for (e.g.) Oracle
 * compatibility.
 *
 * @author Rhett Sutphin
 * @see Restrictions
 */
public class MoreRestrictions {
    private static final Logger log = LoggerFactory.getLogger(MoreRestrictions.class);

    private static final int DEFAULT_MAX_LENGTH = 900;

    public static Criterion in(String propertyName, Collection<?> values) {
        return in(propertyName, values, DEFAULT_MAX_LENGTH);
    }

    public static Criterion in(String propertyName, Collection<?> values, int maxLength) {
        if (maxLength < 1)
            throw new IllegalArgumentException("maxLength must be positive");
        Disjunction result = Restrictions.disjunction();
        for (Collection<?> part : partitionCollection(values, maxLength)) {
            result.add(Restrictions.in(propertyName, part));
        }
        return result;
    }

    private static List<Collection<?>> partitionCollection(Collection<?> values, int maxLength) {
        int partitionCount = positiveIntegerCeiling(values.size(), maxLength);

        // A possibly premature optimization.
        // Seems worthwhile since most uses will not require segmentation.
        if (partitionCount < 2)
            return Arrays.<Collection<?>>asList(values);

        int balancedLength = positiveIntegerCeiling(values.size(), partitionCount);

        if (log.isDebugEnabled()) {
            log.debug(
                    "Partitioning list of {} values into {} list{} of at most {} in order to stay under {} values per clause",
                    new Object[] { values.size(), partitionCount, partitionCount == 1 ? "" : 's', balancedLength,
                            maxLength });
        }

        List<Collection<?>> partitioned = new ArrayList<Collection<?>>(partitionCount);
        Object[] valuesArray = values.toArray();
        while (partitioned.size() * balancedLength < values.size()) {
            int from = partitioned.size() * balancedLength;
            int to = Math.min(from + balancedLength, values.size());
            partitioned.add(Arrays.asList(valuesArray).subList(from, to));
        }
        return partitioned;
    }

    private static int positiveIntegerCeiling(int dividend, int divisor) {
        return dividend / divisor + (dividend % divisor == 0 ? 0 : 1);
    }
}