/*
* GeoTools - The Open Source Java GIS Toolkit
* http://geotools.org
*
* (C) 2013, 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.catalog;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileReader;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.apache.commons.io.IOUtils;
import org.geotools.data.DataUtilities;
import org.geotools.data.shapefile.ShapefileDataStore;
import org.geotools.data.simple.SimpleFeatureIterator;
import org.geotools.util.logging.Logging;
import org.opengis.feature.simple.SimpleFeature;
import com.vividsolutions.jts.geom.Geometry;
import com.vividsolutions.jts.io.InputStreamInStream;
import com.vividsolutions.jts.io.WKBReader;
import com.vividsolutions.jts.io.WKTReader;
/**
* A footprint provider looking for sidecar files (SHP, WKB, WKT)
*
* @author Andrea Aime - GeoSolutions
*/
public class SidecarFootprintProvider implements FootprintGeometryProvider {
static final Logger LOGGER = Logging.getLogger(SidecarFootprintProvider.class);
static final FootprintLoader[] LOADERS = new FootprintLoader[] { new ShapefileLoader(),
new WKBLoader(), new WKTLoader() };
private File mosaicFolder;
private volatile FootprintLoader lastLoader;
public SidecarFootprintProvider(File mosaicFolder) {
this.mosaicFolder = mosaicFolder;
}
@Override
public Geometry getFootprint(SimpleFeature feature) throws IOException {
Object value = feature.getAttribute("location");
if (value != null && value instanceof String) {
String strValue = (String) value;
String path = getFullPath(strValue);
String noExtension = getNoExtensionPath(path);
// Try to reuse over and over the last loader, to avoid checking the others
// The last loader is kept in a volatile variable and all the work is done via
// a local copy of it to avoid concurrency issues
FootprintLoader loader = lastLoader;
Geometry result = null;
try {
if (loader != null) {
result = loader.loadFootprint(noExtension);
}
if (result == null) {
for (FootprintLoader test : LOADERS) {
result = test.loadFootprint(noExtension);
if (result != null) {
lastLoader = test;
break;
}
}
}
} catch (Exception e) {
throw new IOException("Failed to load the footprint for granule " + strValue, e);
}
return result;
} else {
if (LOGGER.isLoggable(Level.FINE)) {
LOGGER.fine("Could not use the location attribute value to search for "
+ "a sidecar file, the value was: " + value);
}
return null;
}
}
private String getNoExtensionPath(String path) {
int idx = path.lastIndexOf(".");
String noExtension;
if (idx > 0) {
noExtension = path.substring(0, idx);
} else {
noExtension = path;
}
return noExtension;
}
private String getFullPath(String strValue) throws IOException {
File file = new File(strValue);
if (!file.isAbsolute()) {
file = new File(mosaicFolder, strValue);
}
String path = file.getCanonicalPath();
return path;
}
@Override
public void dispose() {
// nothing to do, in this providers we don't keep files open
}
/**
* Helper that loads a sidecar footprint file in a certain format
*/
private interface FootprintLoader {
/**
* Tries to load the sidecar geometry given the granule path without extension.
*
* @param pathNoExtension
* @return The footprint, or null if the file was not found
* @throws Exception In case the file was found, but there were issues loading the geometry
*/
Geometry loadFootprint(String pathNoExtension) throws Exception;
}
/**
* Loads WKB files
*/
private static class WKBLoader implements FootprintLoader {
WKBReader reader = new WKBReader();
@Override
public Geometry loadFootprint(String pathNoExtension) throws Exception {
File file = new File(pathNoExtension + ".wkb");
if (file.exists()) {
FileInputStream is = null;
try {
is = new FileInputStream(file);
return reader.read(new InputStreamInStream(is));
} finally {
IOUtils.closeQuietly(is);
}
}
return null;
}
}
/**
* Loads WKT files
*/
private static class WKTLoader implements FootprintLoader {
WKTReader reader = new WKTReader();
@Override
public Geometry loadFootprint(String pathNoExtension) throws Exception {
File file = new File(pathNoExtension + ".wkt");
if (file.exists()) {
FileReader fr = null;
try {
fr = new FileReader(file);
return reader.read(fr);
} finally {
IOUtils.closeQuietly(fr);
}
}
return null;
}
}
/**
* Loads footprints from a sidecar shepefile with a single record, will complain if more than
* one is found
*/
private static class ShapefileLoader implements FootprintLoader {
@Override
public Geometry loadFootprint(String pathNoExtension) throws Exception {
File file = new File(pathNoExtension + ".shp");
if (file.exists()) {
ShapefileDataStore ds = new ShapefileDataStore(DataUtilities.fileToURL(file));
SimpleFeatureIterator fi = null;
try {
fi = ds.getFeatureSource().getFeatures().features();
if (!fi.hasNext()) {
return null;
} else {
SimpleFeature sf = fi.next();
Geometry result = (Geometry) sf.getDefaultGeometry();
if (fi.hasNext()) {
throw new IOException(
"Found more than one footprint record in the shapefile "
+ file.getCanonicalPath());
}
return result;
}
} finally {
if (fi != null) {
fi.close();
}
ds.dispose();
}
}
return null;
}
}
}