com.frank.search.solr.core.query.result.DelegatingCursor.java Source code

Java tutorial

Introduction

Here is the source code for com.frank.search.solr.core.query.result.DelegatingCursor.java

Source

/*
 * Copyright 2014 the original author or authors.
 *
 * 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.frank.search.solr.core.query.result;

import org.apache.solr.client.solrj.SolrQuery;
import org.apache.solr.common.params.CursorMarkParams;
import org.springframework.dao.InvalidDataAccessApiUsageException;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.io.IOException;
import java.util.*;

/**
 * {@link DelegatingCursor} is a base {@link Cursor} implementation that temporarily holds data fetched in one run and
 * delegates iteration.
 *
 * @author Christoph Strobl
 * @param <T>
 */
public abstract class DelegatingCursor<T> implements Cursor<T> {

    private State state;
    private String cursorMark;
    private long position;
    private Iterator<T> delegate;
    private final SolrQuery referenceQuery;

    protected DelegatingCursor(SolrQuery query) {
        this(query, CursorMarkParams.CURSOR_MARK_START);
    }

    protected DelegatingCursor(SolrQuery query, String initalCursorMark) {

        this.referenceQuery = query;
        this.cursorMark = StringUtils.hasText(initalCursorMark) ? initalCursorMark
                : CursorMarkParams.CURSOR_MARK_START;
        this.state = State.REDAY;
        this.delegate = Collections.<T>emptyList().iterator();
    }

    /*
     * (non-Javadoc)
     * @see java.util.Iterator#hasNext()
     */
    @Override
    public boolean hasNext() {

        validateState();

        if (!delegate.hasNext() && !isFinished()) {
            load(getCursorMark());
        }

        if (delegate.hasNext()) {
            return true;
        }

        return false;
    }

    /*
     * (non-Javadoc)
     * @see java.util.Iterator#next()
     */
    @Override
    public T next() {

        validateState();

        if (!hasNext()) {
            throw new NoSuchElementException("No more elements available for cursor " + getCursorMark() + ".");
        }

        T next = moveNext(delegate);
        position++;
        return next;
    }

    /**
     * Move one position next in given source.
     *
     * @param source
     * @return
     */
    protected T moveNext(Iterator<T> source) {
        return source.next();
    }

    private void load(String cursorMark) {

        SolrQuery query = referenceQuery.getCopy();
        query.set(CursorMarkParams.CURSOR_MARK_PARAM, this.getCursorMark());

        PartialResult<T> result = doLoad(query);
        process(result);
    }

    /**
     * Read data from Solr.
     *
     * @param nativeQuery The query to execute already positioned at the next cursor mark.
     * @return
     */
    protected abstract PartialResult<T> doLoad(SolrQuery nativeQuery);

    private void process(PartialResult<T> result) {

        if (result == null) {
            this.delegate = Collections.<T>emptyList().iterator();
            this.state = State.FINISHED;
            return;
        }

        if (getCursorMark().equals(result.getNextCursorMark())) {
            this.state = State.FINISHED;
        }

        this.cursorMark = result.getNextCursorMark();

        if (!CollectionUtils.isEmpty(result.getItems())) {
            delegate = result.iterator();
        } else {
            Collections.<T>emptyList().iterator();
        }
    }

    /*
     * (non-Javadoc)
     * @see org.springframework.data.solr.core.query.result.Cursor#open()
     */
    @Override
    public DelegatingCursor<T> open() {

        if (!isReady()) {
            throw new InvalidDataAccessApiUsageException("Cursor already " + state + ". Cannot (re)open it.");
        }

        this.state = State.OPEN;
        doOpen(this.getCursorMark());
        return this;
    }

    /**
     * Customization hook for {@link #open()}.
     *
     * @param cursorMark
     */
    protected void doOpen(String cursorMark) {
        load(cursorMark);
    }

    /*
     * (non-Javadoc)
     * @see java.io.Closeable#close()
     */
    @Override
    public void close() throws IOException {

        try {
            doClose();
        } finally {
            this.state = State.CLOSED;
        }

    }

    /**
     * Customization hook for clean up operations
     */
    protected void doClose() {
        this.delegate = Collections.<T>emptyList().iterator();
        this.referenceQuery.clear();
        this.position = -1;
        this.cursorMark = null;
    }

    /*
     * (non-Javadoc)
     * @see java.util.Iterator#remove()
     */
    @Override
    public void remove() {
        throw new UnsupportedOperationException("Removing elements from cursor is not supported");
    }

    /*
     * (non-Javadoc)
     * @see org.springframework.data.solr.core.query.result.Cursor#getPosition()
     */
    @Override
    public long getPosition() {
        return this.position;
    }

    /*
     * (non-Javadoc)
     * @see org.springframework.data.solr.core.query.result.Cursor#getCursorMark()
     */
    @Override
    public String getCursorMark() {
        return this.cursorMark;
    }

    /**
     * @return true if {@link Cursor.State#REDAY}
     */
    public boolean isReady() {
        return State.REDAY.equals(state);
    }

    /*
     * (non-Javadoc)
     * @see org.springframework.data.solr.core.query.result.Cursor#isOpen()
     */
    public boolean isOpen() {
        return State.OPEN.equals(state);
    }

    /**
     * @return true if {@link Cursor.State#FINISHED}
     */
    public boolean isFinished() {
        return State.FINISHED.equals(state);
    }

    /*
     * (non-Javadoc)
     * @see org.springframework.data.solr.core.query.result.Cursor#isClosed()
     */
    @Override
    public boolean isClosed() {
        return State.CLOSED.equals(state);
    }

    private void validateState() {
        if (isReady() || isClosed()) {
            throw new InvalidDataAccessApiUsageException(
                    "Cannot access closed cursor. Did you forget to call open()?");
        }
    }

    /**
     * {@link DelegatingCursor.PartialResult} provided by a round trip to SolrClient loading data for an iteration. Also holds the cursor
     * mark to use next.
     * 
     * @author Christoph Strobl
     * @param <T>
     */
    public static class PartialResult<T> implements Iterable<T> {

        private String nextCursorMark;
        private Collection<T> items;

        public PartialResult(String nextCursorMark, Collection<T> items) {
            this.nextCursorMark = nextCursorMark;
            this.items = (items != null ? new ArrayList<T>(items) : Collections.<T>emptyList());
        }

        /**
         * Get the next cursor mark to use.
         * 
         * @return
         */
        public String getNextCursorMark() {
            return nextCursorMark;
        }

        /**
         * Get items returned from server. <br/>
         * 
         * @return never {@literal null}
         */
        public Collection<T> getItems() {
            return items;
        }

        /*
         * (non-Javadoc)
         * @see java.lang.Iterable#iterator()
         */
        @Override
        public Iterator<T> iterator() {
            return items.iterator();
        }
    }

}