/* Copyright (c) 2001 - 2007 TOPP - www.openplans.org. All rights reserved.
* This code is licensed under the GPL 2.0 license, available at the root
* application directory.
*/
package org.geoserver.wfs.response;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.geotools.util.logging.Logging;
import org.opengis.referencing.crs.CoordinateReferenceSystem;
/**
* Helper used to invoke ogr2ogr
*
* @author Andrea Aime - OpenGeo
*
*/
public class OGRWrapper {
private static final Logger LOGGER = Logging.getLogger(OGRWrapper.class);
private String ogrExecutable;
private String gdalData;
public OGRWrapper(String ogrExecutable, String gdalData) {
this.ogrExecutable = ogrExecutable;
this.gdalData = gdalData;
}
/**
* Performs the conversion, returns the name of the (main) output file
*/
public File convert(File inputData, File outputDirectory, String typeName,
OgrFormat format, CoordinateReferenceSystem crs) throws IOException, InterruptedException {
// build the command line
List<String> cmd = new ArrayList<String>();
cmd.add(ogrExecutable);
cmd.add("-f");
cmd.add(format.ogrFormat);
File crsFile = null;
if (crs != null) {
// we don't use an EPSG code since there is no guarantee we'll be able to reverse
// engineer one. Using WKT also ensures the EPSG params such as the TOWGS84 ones are
// not lost in the conversion
// We also write to a file because some operating systems cannot take arguments with
// quotes and spaces inside (and/or ProcessBuilder is not good enough to escape them)
crsFile = File.createTempFile("gdal_srs", "wkt", inputData.getParentFile());
cmd.add("-a_srs");
String s = crs.toWKT();
s = s.replaceAll("\n\r", "").replaceAll(" ", "");
FileUtils.writeStringToFile(crsFile, s);
cmd.add(crsFile.getAbsolutePath());
}
if (format.options != null) {
for (String option : format.options) {
cmd.add(option);
}
}
String outFileName = typeName;
if (format.fileExtension != null)
outFileName += format.fileExtension;
cmd.add(new File(outputDirectory, outFileName).getAbsolutePath());
cmd.add(inputData.getAbsolutePath());
StringBuilder sb = new StringBuilder();
int exitCode = run(cmd, sb);
if(crsFile != null) {
crsFile.delete();
}
if (exitCode != 0)
throw new IOException("ogr2ogr did not terminate successfully, exit code " + exitCode
+ ". Was trying to run: " + cmd + "\nResulted in:\n" + sb);
// csv output is a directory, handle that case gracefully
File output = new File(outputDirectory, outFileName);
if(output.isDirectory()) {
output = new File(output, outFileName);
}
return output;
}
/**
* Returns a list of the ogr2ogr supported formats
*
* @return
*/
public Set<String> getSupportedFormats() {
try {
// this one works up to ogr2ogr 1.7
List<String> commands = new ArrayList<String>();
commands.add(ogrExecutable);
commands.add("--help");
Set<String> formats = new HashSet<String>();
addFormats(commands, formats);
// this one is required starting with ogr2ogr 1.8
commands = new ArrayList<String>();
commands.add(ogrExecutable);
commands.add("--long-usage");
addFormats(commands, formats);
return formats;
} catch (Exception e) {
LOGGER.log(Level.SEVERE,
"Could not get the list of output formats supported by ogr2ogr", e);
return Collections.emptySet();
}
}
private void addFormats(List<String> commands, Set<String> formats) throws IOException,
InterruptedException {
StringBuilder sb = new StringBuilder();
// can't trust the exit code, --help exits with -1 on my pc
run(commands, sb);
String[] lines = sb.toString().split("\n");
for (String line : lines) {
if (line.matches("\\s*-f \".*")) {
String format = line.substring(line.indexOf('"') + 1, line.lastIndexOf('"'));
formats.add(format);
}
}
}
/**
* Returns true if ogr2ogr is available, that is, if executing
* "ogr2ogr --version" returns 0 as the exit code
*
* @return
*/
public boolean isAvailable() {
List<String> commands = new ArrayList<String>();
commands.add(ogrExecutable);
commands.add("--version");
try {
return run(commands, null) == 0;
} catch(Exception e) {
LOGGER.log(Level.SEVERE, "Ogr2Ogr is not available", e);
return false;
}
}
/**
* Runs the specified command appending the output to the string builder and
* returning the exit code
*
* @param cmd
* @param sb
* @return
* @throws IOException
* @throws InterruptedException
*/
int run(List<String> cmd, StringBuilder sb) throws IOException, InterruptedException {
// run the process and grab the output for error reporting purposes
ProcessBuilder builder = new ProcessBuilder(cmd);
if(gdalData != null)
builder.environment().put("GDAL_DATA", gdalData);
builder.redirectErrorStream(true);
Process p = builder.start();
BufferedReader reader = new BufferedReader(new InputStreamReader(p.getInputStream()));
String line = null;
while ((line = reader.readLine()) != null) {
if (sb != null) {
sb.append("\n");
sb.append(line);
}
}
return p.waitFor();
}
}