001/*
002 * (C) Copyright 2014-2015 Nuxeo SA (http://nuxeo.com/) and others.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *     http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 *
016 * Contributors:
017 *     Benoit Delbosc
018 *     Florent Guillaume
019 */
020package org.nuxeo.elasticsearch.core;
021
022import java.io.Serializable;
023import java.util.Iterator;
024import java.util.List;
025import java.util.Map;
026import java.util.NoSuchElementException;
027
028import org.elasticsearch.action.search.SearchResponse;
029import org.nuxeo.ecm.core.api.IterableQueryResult;
030import org.nuxeo.ecm.core.schema.types.Type;
031
032/**
033 * Iterable query result of the results of an Elasticsearch query.
034 * <p>
035 * Loads all results in memory.
036 *
037 * @since 7.2
038 */
039public class EsResultSetImpl implements IterableQueryResult, Iterator<Map<String, Serializable>> {
040
041    private final SearchResponse response;
042
043    private final Map<String, Type> selectFieldsAndTypes;
044
045    boolean closed;
046
047    protected List<Map<String, Serializable>> maps;
048
049    protected long size;
050
051    private long pos;
052
053    public EsResultSetImpl(SearchResponse response, Map<String, Type> selectFieldsAndTypes) {
054        this.response = response;
055        this.selectFieldsAndTypes = selectFieldsAndTypes;
056        maps = buildMaps();
057        size = maps.size();
058    }
059
060    protected List<Map<String, Serializable>> buildMaps() {
061        return new EsSearchHitConverter(selectFieldsAndTypes).convert(response.getHits().getHits());
062    }
063
064    @Override
065    public void close() {
066        closed = true;
067        pos = -1;
068    }
069
070    @Override
071    public boolean isLife() {
072        return !closed;
073    }
074
075    @Override
076    public boolean mustBeClosed() {
077        return false; // holds no resources
078    }
079
080    @Override
081    public long size() {
082        return response.getHits().getTotalHits();
083    }
084
085    @Override
086    public long pos() {
087        return pos;
088    }
089
090    @Override
091    public void skipTo(long pos) {
092        if (pos < 0) {
093            pos = 0;
094        } else if (pos > size) {
095            pos = size;
096        }
097        this.pos = pos;
098    }
099
100    @Override
101    public Iterator<Map<String, Serializable>> iterator() {
102        return this;
103    }
104
105    @Override
106    public boolean hasNext() {
107        return pos < size;
108    }
109
110    @Override
111    public Map<String, Serializable> next() {
112        if (closed || pos == size) {
113            throw new NoSuchElementException();
114        }
115        Map<String, Serializable> map = maps.get((int) pos);
116        pos++;
117        return map;
118    }
119
120}