com.amalto.core.storage.hibernate.InstanceScrollOptimization.java Source code

Java tutorial

Introduction

Here is the source code for com.amalto.core.storage.hibernate.InstanceScrollOptimization.java

Source

/*
 * Copyright (C) 2006-2016 Talend Inc. - www.talend.com
 * 
 * This source code is available under agreement available at
 * %InstallDIR%\features\org.talend.rcp.branding.%PRODUCTNAME%\%PRODUCTNAME%license.txt
 * 
 * You should have received a copy of the agreement along with this program; if not, write to Talend SA 9 rue Pages
 * 92150 Suresnes, France
 */

package com.amalto.core.storage.hibernate;

import java.io.IOException;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

import com.amalto.core.storage.CloseableIterator;
import org.apache.commons.collections.IteratorUtils;
import org.apache.commons.collections.Predicate;
import org.hibernate.Criteria;
import org.hibernate.Session;
import org.talend.mdm.commmon.metadata.ComplexTypeMetadata;
import org.talend.mdm.commmon.metadata.FieldMetadata;

import com.amalto.core.query.user.*;
import com.amalto.core.storage.Storage;
import com.amalto.core.storage.StorageResults;
import com.amalto.core.storage.record.DataRecord;

public class InstanceScrollOptimization extends StandardQueryHandler {

    public InstanceScrollOptimization(Storage storage, MappingRepository mappings, TableResolver resolver,
            StorageClassLoader storageClassLoader, Session session, Select select,
            List<TypedExpression> selectedFields, Set<ResultsCallback> callbacks) {
        super(storage, mappings, resolver, storageClassLoader, session, select, selectedFields, callbacks);
    }

    @Override
    public StorageResults visit(Select select) {
        ComplexTypeMetadata mainType = select.getTypes().get(0);
        Paging paging = select.getPaging();
        int start = paging.getStart();
        if (start != 0) {
            throw new IllegalStateException(
                    "This optimization is only use for iterating over all instances (start is not supported).");
        }
        if (paging.getLimit() != Integer.MAX_VALUE) {
            // Optimization *could* work when page size is set... however it also means the analysis of the query is
            // redirecting to the wrong optimization, and this is an issue.
            throw new UnsupportedOperationException();
        }
        // Perform same query as input *but* adds an order by clause 'by id' that allows efficient filtering (iterator
        // should
        // only return unique results).
        Select copy = select.copy();
        Collection<FieldMetadata> keyFields = mainType.getKeyFields();
        for (FieldMetadata keyField : keyFields) {
            copy.addOrderBy(new OrderBy(new Field(keyField), OrderBy.Direction.ASC));
        }
        Criteria criteria = createCriteria(copy); // Perform the query with order by id.
        // Create the filtered result iterator
        CloseableIterator<DataRecord> nonFilteredIterator = new ScrollableIterator(mappings, storageClassLoader,
                criteria.scroll(), callbacks);
        Predicate isUniqueFilter = new UniquePredicate(); // Unique filter returns only different instances
        Iterator filteredIterator = IteratorUtils.filteredIterator(nonFilteredIterator, isUniqueFilter);
        FilteredIteratorWrapper uniqueIterator = new FilteredIteratorWrapper(nonFilteredIterator, filteredIterator,
                select);
        return new HibernateStorageResults(storage, select, uniqueIterator);
    }

    private static class UniquePredicate implements Predicate {

        public Object lastObject;

        @Override
        public boolean evaluate(Object object) {
            if (object.equals(lastObject)) {
                return false; // Provided object same as previous one: filter out.
            }
            lastObject = object;
            return true;
        }
    }

    // Internal class to provide a closeable iterator and filtered results.
    private static class FilteredIteratorWrapper implements CloseableIterator<DataRecord> {

        private final CloseableIterator<DataRecord> nonFilteredIterator;

        private final Iterator filteredIterator;

        private final Select select;

        private boolean isClosed;

        public FilteredIteratorWrapper(CloseableIterator<DataRecord> nonFilteredIterator, Iterator filteredIterator,
                Select select) {
            this.nonFilteredIterator = nonFilteredIterator;
            this.filteredIterator = filteredIterator;
            this.select = select;
        }

        @Override
        public void close() throws IOException {
            isClosed = true;
            nonFilteredIterator.close();
        }

        public boolean hasNext() {
            return !isClosed && filteredIterator.hasNext();
        }

        public DataRecord next() {
            if (isClosed) {
                throw new IllegalStateException("Can not move to next: iterator is closed.");
            }
            return (DataRecord) filteredIterator.next();
        }

        public void remove() {
            if (isClosed) {
                throw new IllegalStateException("Can not remove: iterator is closed.");
            }
            filteredIterator.remove();
        }

        @Override
        public String toString() {
            StringBuilder conditionToString = new StringBuilder();
            UserQueryDumpConsole.DumpPrinter dumpPrinter = new StringBuilderPrinter(conditionToString);
            Condition condition = select.getCondition();
            if (condition != null) {
                condition.accept(new UserQueryDumpConsole(dumpPrinter));
            }
            return "FilteredIteratorWrapper{" + "type=" + select.getTypes().get(0).getName() + ", condition="
                    + conditionToString.toString() + '}';
        }
    }
}