com.google.gerrit.server.query.change.AndSource.java Source code

Java tutorial

Introduction

Here is the source code for com.google.gerrit.server.query.change.AndSource.java

Source

// Copyright (C) 2010 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package com.google.gerrit.server.query.change;

import com.google.common.base.Function;
import com.google.common.base.Throwables;
import com.google.common.collect.FluentIterable;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.gerrit.reviewdb.server.ReviewDb;
import com.google.gerrit.server.query.AndPredicate;
import com.google.gerrit.server.query.Predicate;
import com.google.gwtorm.server.ListResultSet;
import com.google.gwtorm.server.OrmException;
import com.google.gwtorm.server.OrmRuntimeException;
import com.google.gwtorm.server.ResultSet;
import com.google.inject.Provider;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

class AndSource extends AndPredicate<ChangeData> implements ChangeDataSource {
    private static final Comparator<Predicate<ChangeData>> CMP = new Comparator<Predicate<ChangeData>>() {
        @Override
        public int compare(Predicate<ChangeData> a, Predicate<ChangeData> b) {
            int ai = a instanceof ChangeDataSource ? 0 : 1;
            int bi = b instanceof ChangeDataSource ? 0 : 1;
            int cmp = ai - bi;

            if (cmp == 0) {
                cmp = a.getCost() - b.getCost();
            }

            if (cmp == 0 //
                    && a instanceof ChangeDataSource //
                    && b instanceof ChangeDataSource) {
                ChangeDataSource as = (ChangeDataSource) a;
                ChangeDataSource bs = (ChangeDataSource) b;
                cmp = as.getCardinality() - bs.getCardinality();

                if (cmp == 0) {
                    cmp = (as.hasChange() ? 0 : 1) - (bs.hasChange() ? 0 : 1);
                }
            }

            return cmp;
        }
    };

    private static List<Predicate<ChangeData>> sort(Collection<? extends Predicate<ChangeData>> that) {
        ArrayList<Predicate<ChangeData>> r = new ArrayList<Predicate<ChangeData>>(that);
        Collections.sort(r, CMP);
        return r;
    }

    private final Provider<ReviewDb> db;
    private int cardinality = -1;

    AndSource(Provider<ReviewDb> db, Collection<? extends Predicate<ChangeData>> that) {
        super(sort(that));
        this.db = db;
    }

    @Override
    public boolean hasChange() {
        ChangeDataSource source = source();
        return source != null && source.hasChange();
    }

    @Override
    public ResultSet<ChangeData> read() throws OrmException {
        try {
            return readImpl();
        } catch (OrmRuntimeException err) {
            Throwables.propagateIfInstanceOf(err.getCause(), OrmException.class);
            throw new OrmException(err);
        }
    }

    private ResultSet<ChangeData> readImpl() throws OrmException {
        ChangeDataSource source = source();
        if (source == null) {
            throw new OrmException("No ChangeDataSource: " + this);
        }

        List<ChangeData> r = Lists.newArrayList();
        ChangeData last = null;
        boolean skipped = false;
        for (ChangeData data : buffer(source, source.read())) {
            if (match(data)) {
                r.add(data);
            } else {
                skipped = true;
            }
            last = data;
        }

        if (skipped && last != null && source instanceof Paginated) {
            // If our source is a paginated source and we skipped at
            // least one of its results, we may not have filled the full
            // limit the caller wants.  Restart the source and continue.
            //
            Paginated p = (Paginated) source;
            while (skipped && r.size() < p.limit()) {
                ChangeData lastBeforeRestart = last;
                skipped = false;
                last = null;
                for (ChangeData data : buffer(source, p.restart(lastBeforeRestart))) {
                    if (match(data)) {
                        r.add(data);
                    } else {
                        skipped = true;
                    }
                    last = data;
                }
            }
        }

        return new ListResultSet<ChangeData>(r);
    }

    private Iterable<ChangeData> buffer(ChangeDataSource source, ResultSet<ChangeData> scanner) {
        final boolean loadChange = !source.hasChange();
        return FluentIterable.from(Iterables.partition(scanner, 50))
                .transformAndConcat(new Function<List<ChangeData>, List<ChangeData>>() {
                    @Override
                    public List<ChangeData> apply(List<ChangeData> buffer) {
                        if (loadChange) {
                            try {
                                ChangeData.ensureChangeLoaded(db, buffer);
                            } catch (OrmException e) {
                                throw new OrmRuntimeException(e);
                            }
                        }
                        return buffer;
                    }
                });
    }

    private ChangeDataSource source() {
        for (Predicate<ChangeData> p : getChildren()) {
            if (p instanceof ChangeDataSource) {
                return (ChangeDataSource) p;
            }
        }
        return null;
    }

    @Override
    public int getCardinality() {
        if (cardinality < 0) {
            cardinality = Integer.MAX_VALUE;
            for (Predicate<ChangeData> p : getChildren()) {
                if (p instanceof ChangeDataSource) {
                    int c = ((ChangeDataSource) p).getCardinality();
                    cardinality = Math.min(cardinality, c);
                }
            }
        }
        return cardinality;
    }
}