org.geotools.gce.imagemosaic.FootprintUtils.java Source code

Java tutorial

Introduction

Here is the source code for org.geotools.gce.imagemosaic.FootprintUtils.java

Source

/*
 *    GeoTools - The Open Source Java GIS Toolkit
 *    http://geotools.org
 *
 *    (C) 2010, Open Source Geospatial Foundation (OSGeo)
 *
 *    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.geotools.gce.imagemosaic;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.net.MalformedURLException;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;

import org.apache.commons.io.IOUtils;
import org.geotools.data.FeatureSource;
import org.geotools.data.shapefile.ShapefileDataStore;
import org.geotools.feature.FeatureCollection;
import org.geotools.feature.FeatureIterator;
import org.geotools.gce.imagemosaic.Utils.Prop;
import org.geotools.util.Utilities;
import org.opengis.feature.simple.SimpleFeature;
import org.opengis.feature.simple.SimpleFeatureType;

import com.vividsolutions.jts.geom.Geometry;
import com.vividsolutions.jts.io.ParseException;
import com.vividsolutions.jts.io.WKTReader;
import com.vividsolutions.jts.io.WKTWriter;

/**
 * Utility class to manage mosaic's footprint
 * @author Daniele Romagnoli, GeoSolutions S.A.S.
 *
 */
class FootprintUtils {

    /**
     * A set of properties to be ignored when parsing the properties file. It is
     * used to get only the FootprintManagement property, avoiding by this way to load
     * and compute useless elements.
     */
    final static Set<String> IGNORE_PROPS = new HashSet<String>();
    static {
        IGNORE_PROPS.add(Prop.ENVELOPE2D);
        IGNORE_PROPS.add(Prop.ABSOLUTE_PATH);
        IGNORE_PROPS.add(Prop.SUGGESTED_SPI);
        IGNORE_PROPS.add(Prop.EXP_RGB);
        IGNORE_PROPS.add(Prop.LEVELS);
        IGNORE_PROPS.add(Prop.LOCATION_ATTRIBUTE);
        IGNORE_PROPS.add(Prop.NAME);
    }

    final static String FOOTPRINT_EXT = ".fpt";

    final static String FOOTPRINT_PREFIX = "footprint";

    final static String FOOTPRINT = FOOTPRINT_PREFIX + ".shp";

    private FootprintUtils() {

    }

    private final static Logger LOGGER = org.geotools.util.logging.Logging.getLogger(FootprintUtils.class);

    /**
     * Given a footprint summary file (.fpt), populate the provided
     * footprints <ID-Geometry> pairs Map
     * 
     * @param footprintSummaryFile
     *            the footprint summary file.
     * @param footprintsIDGeometryMap
     *            the Map to be populated
     */
    static void initFootprintsGranuleIDGeometryMap(final File footprintSummaryFile,
            final Map<String, Geometry> footprintsIDGeometryMap) {
        Utilities.ensureNonNull("footprintSummaryFile", footprintSummaryFile);
        if (!footprintSummaryFile.exists() || !footprintSummaryFile.canRead()) {
            throw new IllegalArgumentException(
                    "Unable to access to the provided footprint file " + footprintSummaryFile.getAbsolutePath());
        }
        Utilities.ensureNonNull("footprintsID_GeometryMap", footprintsIDGeometryMap);

        FileReader reader = null;
        try {
            reader = new FileReader(footprintSummaryFile);
            BufferedReader bReader = new BufferedReader(reader);
            String footprint;

            final WKTReader geometryReader = new WKTReader();
            while ((footprint = bReader.readLine()) != null) {
                String fpt[] = footprint.split("=");
                if (fpt.length == 2) {
                    // parse the geometry
                    footprintsIDGeometryMap.put(fpt[0], geometryReader.read(fpt[1]));
                }
            }
            bReader.close();
        } catch (IOException e) {
            if (LOGGER.isLoggable(Level.FINE)) {
                LOGGER.log(Level.FINE, e.getLocalizedMessage(), e);
            }
        } catch (ParseException e) {

            if (LOGGER.isLoggable(Level.FINE)) {
                LOGGER.log(Level.FINE, e.getLocalizedMessage(), e);
            }
        } finally {
            try {
                if (reader != null) {
                    reader.close();
                }
            } catch (Throwable e) {
                if (LOGGER.isLoggable(Level.FINE)) {
                    LOGGER.log(Level.FINE, e.getLocalizedMessage(), e);
                }
                IOUtils.closeQuietly(reader);
            }
        }
    }

    /**
     * Look for a footprint geometry for the provided featureID.
     * 
     * @param featureID
     *            the ID of a feature for which the footprint should be searched
     * @param footprintsMap
     *            the map containing <.ID,Geometry> pairs
     * @return the related {@link Geometry} if found, or null otherwise.
     */
    static Geometry lookupFootprintGeometry(final String featureID, final Map<String, Geometry> footprintsMap) {
        Utilities.ensureNonNull("featureID", featureID);
        Utilities.ensureNonNull("footprintsMap", footprintsMap);

        if (footprintsMap != null && !footprintsMap.isEmpty()) {
            final String id = featureID.substring(featureID.lastIndexOf(".") + 1, featureID.length());
            return footprintsMap.containsKey(id) ? footprintsMap.get(id) : null;
        }
        return null;
    }

    /**
     * Init the provided footprint map containing <String(location), Geometry(footprint)> pairs.
     * 
     * @throws IOException
     */
    static void initFootprintsLocationGeometryMap(final ShapefileDataStore footprintStore,
            final Map<String, Geometry> footprintsMap) throws IOException {
        Utilities.ensureNonNull("footprintStore", footprintStore);
        Utilities.ensureNonNull("footprintsMap", footprintsMap);

        final String[] typeNames = footprintStore.getTypeNames();
        if (typeNames.length <= 0)
            throw new IllegalArgumentException(
                    "Problems when opening the footprint, no typenames for the schema are defined");

        final String typeName = typeNames[0];
        final FeatureSource<SimpleFeatureType, SimpleFeature> featureSource = footprintStore
                .getFeatureSource(typeName);
        final FeatureCollection<SimpleFeatureType, SimpleFeature> features = featureSource.getFeatures();
        if (features == null) {
            if (LOGGER.isLoggable(Level.FINE)) {
                LOGGER.fine("No features found in the footprint");
            }
            return;
        }

        FeatureIterator<SimpleFeature> it = null;
        try {
            // load the feature from the footprint shapefile store
            it = features.features();
            if (!it.hasNext()) {
                throw new IllegalArgumentException(
                        "The provided FeatureCollection<SimpleFeatureType, SimpleFeature>  or empty, it's impossible to create an index!");
            }

            // now add the footprint to the Map
            while (it.hasNext()) {
                final SimpleFeature feature = it.next();
                final Geometry g = (Geometry) feature.getDefaultGeometry();
                final String location = (String) feature.getAttribute("location");
                footprintsMap.put(location, g);
            }

        } finally {

            try {
                if (it != null) {
                    it.close();
                }
            } catch (Throwable e) {
            }

            try {
                it.close();
            } catch (Throwable e) {
            }
        }
    }

    /**
     * Build a "ID=Geometry" pair for the provided feature ID, by
     * looking for a geometry in the provided footprintsMap for the specified
     * locationKey
     * 
     * @param footprintGeometryMap
     * @param featureID
     * @param locationKey
     * @param writer 
     * @return
     */
    private static String buildIDGeometryPair(final Map<String, Geometry> footprintGeometryMap,
            final String featureID, final String locationKey, final WKTWriter writer) {
        String idGeometryPair = "";
        Utilities.ensureNonNull("featureID", featureID);
        Utilities.ensureNonNull("writer", writer);
        Utilities.ensureNonNull("locationKey", locationKey);
        Utilities.ensureNonNull("footprintGeometryMap", footprintGeometryMap);

        if (!footprintGeometryMap.isEmpty() && footprintGeometryMap.containsKey(locationKey)) {
            final Geometry polygon = (Geometry) footprintGeometryMap.get(locationKey);
            if (polygon != null) {
                final String s = writer.write(polygon);
                String id = featureID;
                id = id.substring(id.lastIndexOf(".") + 1, id.length());
                idGeometryPair = new StringBuilder(id).append("=").append(s).append("\n").toString();
            }
        }
        return idGeometryPair;
    }

    /**
     * Write a footprint summary file (".fpt") given an input <String,Geometry>
     * map containing granule location and related geometry, and the index
     * shapefile store to associate footprints to granules.
     * 
     * @param footprintSummaryFile
     *            the output footprint summary file
     * @param footprintsLocationGeometryMap
     *            the map containing <granuleLocation,footprintGeometry> pairs
     * @throws MalformedURLException In case the url we create internally for the mosaic index is wrong (should never happen)
     */
    static void writeFootprintSummary(final File footprintSummaryFile, final File indexFile,
            final Map<String, Geometry> footprintsLocationGeometryMap) throws MalformedURLException {
        Utilities.ensureNonNull("footprintSummaryFile", footprintSummaryFile);
        Utilities.ensureNonNull("indexFile", indexFile);
        Utilities.ensureNonNull("footprintsLocationGeometryMap", footprintsLocationGeometryMap);
        if (footprintsLocationGeometryMap.isEmpty())
            return;
        final ShapefileDataStore store = new ShapefileDataStore(indexFile.toURI().toURL());

        if (footprintsLocationGeometryMap.isEmpty())
            return;

        final String[] typeNames = store.getTypeNames();
        if (typeNames.length <= 0) {
            throw new IllegalArgumentException(
                    "Problems when opening the shapefile, no typenames for the schema are defined");
        }
        final String typeName = typeNames[0];
        FileWriter footprintWriter = null;
        FeatureIterator<SimpleFeature> it = null;
        try {
            final FeatureSource<SimpleFeatureType, SimpleFeature> featureSource = store.getFeatureSource(typeName);
            final FeatureCollection<SimpleFeatureType, SimpleFeature> features = featureSource.getFeatures();

            if (features == null) {
                if (LOGGER.isLoggable(Level.FINE)) {
                    LOGGER.fine("No features found in the shapefile");
                }
                return;
            }

            // load the feature from the shapefile
            it = features.features();
            if (!it.hasNext())
                throw new IllegalArgumentException(
                        "The provided FeatureCollection<SimpleFeatureType, SimpleFeature>  or empty, it's impossible to create an index!");

            footprintWriter = new FileWriter(footprintSummaryFile);
            final BufferedWriter writer = new BufferedWriter(footprintWriter);
            final WKTWriter geometryWriter = new WKTWriter();

            // Scan the index shapefile to get granules location
            while (it.hasNext()) {
                final SimpleFeature feature = it.next();
                final String location = (String) feature.getAttribute("location");
                if (location != null && location.trim().length() > 0) {
                    final String locationKey = location;

                    // Check if a footprint exist in the map for this granule
                    if (footprintsLocationGeometryMap.containsKey(locationKey)) {

                        // Build a featureID=Geometry pair and write it in
                        // the Footprint summary file
                        final String idGeometryPair = FootprintUtils.buildIDGeometryPair(
                                footprintsLocationGeometryMap, feature.getID(), locationKey, geometryWriter);
                        writer.write(idGeometryPair);
                    }
                }
            }
            writer.flush();
            writer.close();
        } catch (Throwable e) {
            // ignore exception
            if (LOGGER.isLoggable(Level.FINEST))
                LOGGER.log(Level.FINEST, e.getLocalizedMessage(), e);
        } finally {
            try {
                if (it != null) {
                    it.close();
                }
            } catch (Throwable e) {
                if (LOGGER.isLoggable(Level.FINEST))
                    LOGGER.log(Level.FINEST, e.getLocalizedMessage(), e);
            }

            try {
                if (footprintWriter != null) {
                    footprintWriter.flush();

                    footprintWriter.close();
                }
            } catch (Throwable e) {
                if (LOGGER.isLoggable(Level.FINEST))
                    LOGGER.log(Level.FINEST, e.getLocalizedMessage(), e);
                IOUtils.closeQuietly(footprintWriter);
            }
            footprintWriter = null;

            try {
                store.dispose();
            } catch (Throwable e) {
                if (LOGGER.isLoggable(Level.FINEST))
                    LOGGER.log(Level.FINEST, e.getLocalizedMessage(), e);
            }
        }
    }

    /**
     * Search the footprint shape file in the specified directory.
     * 
     * @param indexingDirectory
     * @return
     */
    static File searchFootprint(final String indexingDirectory) {
        File footprintFile = null;
        if (indexingDirectory != null && indexingDirectory.trim().length() > 0) {
            final File file = new File(indexingDirectory, FootprintUtils.FOOTPRINT);
            if (file != null && file.exists()) {
                footprintFile = file;
            }
        }
        return footprintFile;
    }
}