ingest.inspect.GeoJsonInspector.java Source code

Java tutorial

Introduction

Here is the source code for ingest.inspect.GeoJsonInspector.java

Source

/**
 * Copyright 2016, RadiantBlue Technologies, Inc.
 * 
 * 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 ingest.inspect;

import java.io.IOException;
import java.io.InputStream;

import org.apache.commons.io.IOUtils;
import org.geotools.data.FeatureSource;
import org.geotools.data.collection.CollectionFeatureSource;
import org.geotools.data.simple.SimpleFeatureCollection;
import org.geotools.geojson.feature.FeatureJSON;
import org.geotools.geometry.jts.ReferencedEnvelope;
import org.opengis.feature.simple.SimpleFeature;
import org.opengis.feature.simple.SimpleFeatureType;
import org.opengis.referencing.FactoryException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;

import com.amazonaws.AmazonClientException;

import exception.DataInspectException;
import exception.InvalidInputException;
import ingest.utility.IngestUtilities;
import model.data.DataResource;
import model.data.location.FileAccessFactory;
import model.data.type.GeoJsonDataType;
import model.job.metadata.SpatialMetadata;
import model.logger.AuditElement;
import model.logger.Severity;
import util.PiazzaLogger;

/**
 * Inspects GeoJSON. Will parse the GeoJSON input to ensure validity, and parse information such as spatial bounding
 * box.
 * 
 * Vectors for GeoJSON will be stored in Piazza PostGIS table.
 * 
 * @author Sonny.Saniev, Patrick Doody, Russell Orf
 * 
 */
@Component
public class GeoJsonInspector implements InspectorType {
    @Value("${vcap.services.pz-blobstore.credentials.access_key_id:}")
    private String AMAZONS3_ACCESS_KEY;
    @Value("${vcap.services.pz-blobstore.credentials.secret_access_key:}")
    private String AMAZONS3_PRIVATE_KEY;

    private static final Integer DEFAULT_GEOJSON_EPSG_CODE = 4326;

    @Autowired
    private IngestUtilities ingestUtilities;
    @Autowired
    private PiazzaLogger logger;

    private static final Logger LOG = LoggerFactory.getLogger(GeoJsonInspector.class);

    @Override
    public DataResource inspect(DataResource dataResource, boolean host) throws DataInspectException,
            AmazonClientException, InvalidInputException, IOException, FactoryException {
        SpatialMetadata spatialMetadata = new SpatialMetadata();

        // Persist GeoJSON Features into the Piazza PostGIS Database.
        if (host && dataResource.getDataType() instanceof GeoJsonDataType) {
            logger.log(
                    String.format("Extracting Feature Data from GeoJSON File for Data %s",
                            dataResource.getDataId()),
                    Severity.INFORMATIONAL,
                    new AuditElement("ingest", "beginParsingGeoJSON", dataResource.getDataId()));
            FeatureJSON featureJSON = new FeatureJSON();
            InputStream geoJsonInputStream1 = null;
            InputStream geoJsonInputStream2 = null;
            try {
                geoJsonInputStream1 = getGeoJsonInputStream(dataResource);
                geoJsonInputStream2 = getGeoJsonInputStream(dataResource);

                SimpleFeatureType featureSchema = featureJSON.readFeatureCollectionSchema(geoJsonInputStream1,
                        false);
                SimpleFeatureCollection featureCollection = (SimpleFeatureCollection) featureJSON
                        .readFeatureCollection(geoJsonInputStream2);
                FeatureSource<SimpleFeatureType, SimpleFeature> geojsonFeatureSource = new CollectionFeatureSource(
                        featureCollection);

                // Ensure we have features. If not, do not commit anything to PostGIS.
                if (geojsonFeatureSource.getFeatures().size() != 0) {
                    ingestUtilities.persistFeatures(geojsonFeatureSource, dataResource, featureSchema);
                }

                // Get the Bounding Box, set the Spatial Metadata
                ReferencedEnvelope envelope = geojsonFeatureSource.getBounds();
                spatialMetadata.setMinX(envelope.getMinX());
                spatialMetadata.setMinY(envelope.getMinY());
                spatialMetadata.setMaxX(envelope.getMaxX());
                spatialMetadata.setMaxY(envelope.getMaxY());
                spatialMetadata.setNumFeatures(geojsonFeatureSource.getFeatures().size());

                // Defaulting to 4326 since GeoTools has no FeatureSource available for GeoJSON files.
                spatialMetadata.setEpsgCode(DEFAULT_GEOJSON_EPSG_CODE);

                // Populate the projected EPSG:4326 spatial metadata
                try {
                    spatialMetadata.setProjectedSpatialMetadata(
                            ingestUtilities.getProjectedSpatialMetadata(spatialMetadata));
                } catch (Exception exception) {
                    String error = String.format(
                            "Could not project the spatial metadata for Data %s because of exception: %s",
                            dataResource.getDataId(), exception.getMessage());
                    LOG.error(error, exception);
                    logger.log(error, Severity.WARNING);
                }

                // Convert DataType to postgis from geojson
                ((GeoJsonDataType) dataResource.getDataType()).setDatabaseTableName(dataResource.getDataId());
                ((GeoJsonDataType) dataResource.getDataType()).setMimeType(MediaType.APPLICATION_JSON_VALUE);

                dataResource.spatialMetadata = spatialMetadata;

                // Clean up resources
                featureJSON = null;
                geojsonFeatureSource = null;
                featureCollection = null;
            } finally {
                try {
                    if (geoJsonInputStream1 != null) {
                        geoJsonInputStream1.close();
                    }
                } catch (Exception exception) {
                    LOG.warn("Error closing File Stream", exception);
                }
                try {
                    if (geoJsonInputStream2 != null) {
                        geoJsonInputStream2.close();
                    }
                } catch (Exception exception) {
                    LOG.warn("Error closing File Stream", exception);
                }
            }
        }

        logger.log(String.format("Completed Feature Data from GeoJSON File for Data %s", dataResource.getDataId()),
                Severity.INFORMATIONAL,
                new AuditElement("ingest", "completeParsingGeoJSON", dataResource.getDataId()));

        // Return DataResource
        return dataResource;
    }

    /**
     * Gets the Input Stream for a GeoJSON Resource
     * 
     * @param dataResource
     *            data resource to pull input stream from
     * @return File object
     */
    private InputStream getGeoJsonInputStream(DataResource dataResource)
            throws IOException, AmazonClientException, InvalidInputException {
        FileAccessFactory fileFactory = ingestUtilities.getFileFactoryForDataResource(dataResource);
        InputStream inputStream;

        if (((GeoJsonDataType) dataResource.getDataType()).getLocation() != null) {
            inputStream = fileFactory.getFile(((GeoJsonDataType) dataResource.getDataType()).getLocation());
        } else {
            String geoJsonContent = ((GeoJsonDataType) dataResource.getDataType()).getGeoJsonContent();
            inputStream = IOUtils.toInputStream(geoJsonContent, "UTF-8");
        }

        return inputStream;
    }
}