/* * Geotoolkit - An Open Source Java GIS Toolkit * http://www.geotoolkit.org * * (C) 2014, Geomatys * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. */ package org.geotoolkit.data.geojson.binding; import com.fasterxml.jackson.core.JsonLocation; import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.core.JsonToken; import org.geotoolkit.data.FeatureStoreRuntimeException; import org.geotoolkit.data.geojson.utils.*; import java.io.IOException; import java.io.InputStream; import java.nio.file.Files; import java.nio.file.Path; import java.util.ArrayList; import java.util.List; /** * @author Quentin Boileau (Geomatys) */ public class GeoJSONFeatureCollection extends GeoJSONObject implements GeoJSONFeatureIterator<GeoJSONFeature> { private List<GeoJSONFeature> features = new ArrayList<>(); transient JsonLocation currentPos = null; transient GeoJSONFeature current = null; transient int currentIdx = 0; transient InputStream readStream; transient JsonParser parser; /** * If current GeoJSONFeatureCollection is in lazy parsing mode, * sourceInput should be not {@code null} and used to create {@link JsonParser object} */ transient Path sourceInput = null; transient LiteJsonLocation startPos = null; transient LiteJsonLocation endPos = null; transient Boolean lazyMode; public GeoJSONFeatureCollection(Boolean lazyMode) { setType(GeoJSONTypes.FEATURE_COLLECTION); this.lazyMode = lazyMode; } public List<GeoJSONFeature> getFeatures() { return features; } public void setFeatures(List<GeoJSONFeature> features) { this.features = features; } public void setStartPosition(JsonLocation startPos) { this.startPos = new LiteJsonLocation(startPos); } public void setEndPosition(JsonLocation endPos) { this.endPos = new LiteJsonLocation(endPos); } public void setSourceInput(Path input) { this.sourceInput = input; } public Boolean isLazyMode() { return lazyMode; } @Override public boolean hasNext() { try { findNext(); return current != null; } catch (IOException e) { throw new FeatureStoreRuntimeException(e.getMessage(), e); } } @Override public GeoJSONFeature next() { try { findNext(); final GeoJSONFeature ob = current; current = null; if (ob == null) { throw new FeatureStoreRuntimeException("No more feature."); } return ob; } catch (IOException e) { throw new FeatureStoreRuntimeException(e.getMessage(), e); } } /** * Find next Feature from features list or as lazy parsing. * @throws IOException */ private void findNext() throws IOException { if (current != null) return; if (lazyMode) { if (sourceInput == null || startPos == null || endPos == null) return; if (parser == null) { readStream = Files.newInputStream(sourceInput); parser = GeoJSONParser.FACTORY.createParser(readStream); } //loop to FeatureCollection start if (currentPos == null) { while (!startPos.equals(currentPos)) { parser.nextToken(); currentPos = parser.getCurrentLocation(); } } current = null; // set parser to feature object start while (parser.getCurrentToken() != JsonToken.START_OBJECT && !endPos.equals(currentPos)) { if (parser.getCurrentToken() != JsonToken.START_OBJECT && endPos.isBefore(currentPos)) { //cannot find collection end token and no more start object token //break loop to avoid infinite search break; } parser.nextToken(); currentPos = parser.getCurrentLocation(); } if (!endPos.equals(currentPos)) { GeoJSONObject obj = GeoJSONParser.parseGeoJSONObject(parser); if (obj instanceof GeoJSONFeature) { current = (GeoJSONFeature) obj; } currentPos = parser.getCurrentLocation(); } } else { if (currentIdx < features.size()) { current = features.get(currentIdx++); } else { current = null; } } } @Override public void remove() { //do nothing } @Override public void close() { //close read stream if (readStream != null) { try { readStream.close(); } catch (IOException e) { throw new FeatureStoreRuntimeException(e.getMessage(), e); } } //close parser if (parser != null && !parser.isClosed()) { try { parser.close(); } catch (IOException e) { throw new FeatureStoreRuntimeException(e.getMessage(), e); } } } }