/* Copyright (c) 2013-2014 Boundless and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Distribution License v1.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/org/documents/edl-v10.html
*
* Contributors:
* Victor Olaya (Boundless) - initial implementation
*/
package org.locationtech.geogig.osm.cli.commands;
import static com.google.common.io.Files.getNameWithoutExtension;
import java.io.File;
import java.io.IOException;
import java.io.Serializable;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.annotation.Nullable;
import org.geotools.data.DataStore;
import org.geotools.data.shapefile.ShapefileDataStoreFactory;
import org.geotools.data.simple.SimpleFeatureSource;
import org.geotools.data.simple.SimpleFeatureStore;
import org.locationtech.geogig.cli.CLICommand;
import org.locationtech.geogig.cli.CommandFailedException;
import org.locationtech.geogig.cli.GeogigCLI;
import org.locationtech.geogig.cli.annotation.ReadOnly;
import org.locationtech.geogig.geotools.cli.porcelain.AbstractShpCommand;
import org.locationtech.geogig.geotools.plumbing.ExportOp;
import org.locationtech.geogig.geotools.plumbing.GeoToolsOpException;
import org.locationtech.geogig.osm.internal.Mapping;
import org.locationtech.geogig.osm.internal.MappingRule;
import org.opengis.feature.Feature;
import org.opengis.feature.simple.SimpleFeatureType;
import org.opengis.feature.type.GeometryDescriptor;
import com.beust.jcommander.Parameter;
import com.beust.jcommander.Parameters;
import com.google.common.base.Function;
import com.google.common.base.Optional;
import com.google.common.base.Preconditions;
import com.vividsolutions.jts.geom.Point;
/**
* Exports OSM into a shapefile, using a data mapping
*
* @see ExportOp
*/
@ReadOnly
@Parameters(commandNames = "export-shp", commandDescription = "Export OSM data to shapefile, using a data mapping")
public class OSMExportShp extends AbstractShpCommand implements CLICommand {
@Parameter(description = "<shapefile>", arity = 2)
public List<String> args;
@Parameter(names = { "--overwrite", "-o" }, description = "Overwrite output file")
public boolean overwrite;
@Parameter(names = { "--mapping" }, description = "The file that contains the data mapping to use")
public String mappingFile;
/**
* Executes the export command using the provided options.
*/
@Override
protected void runInternal(GeogigCLI cli) throws IOException {
Preconditions.checkNotNull(mappingFile != null, "A data mapping file must be specified");
if (args == null || args.isEmpty() || args.size() != 1) {
printUsage(cli);
throw new CommandFailedException();
}
String shapefile = args.get(0);
final File file = new File(shapefile);
final Mapping mapping = Mapping.fromFile(mappingFile);
List<MappingRule> rules = mapping.getRules();
checkParameter(!rules.isEmpty(), "No rules are defined in the specified mapping");
for (MappingRule rule : rules) {
File targetFile = file;
if (rules.size() > 1) {
String name = getNameWithoutExtension(file.getName()) + "_" + rule.getName()
+ ".shp";
targetFile = new File(file.getParentFile(), name);
}
exportRule(rule, cli, targetFile);
}
}
private void exportRule(final MappingRule rule, final GeogigCLI cli, final File shapeFile)
throws IOException {
if (shapeFile.exists() && !overwrite) {
throw new CommandFailedException(
"The selected shapefile already exists. Use -o to overwrite");
}
Function<Feature, Optional<Feature>> function = new Function<Feature, Optional<Feature>>() {
@Override
@Nullable
public Optional<Feature> apply(@Nullable Feature feature) {
Optional<Feature> mapped = rule.apply(feature);
return mapped;
}
};
SimpleFeatureType outputFeatureType = rule.getFeatureType();
String path = getOriginTreesFromOutputFeatureType(outputFeatureType);
ShapefileDataStoreFactory dataStoreFactory = new ShapefileDataStoreFactory();
Map<String, Serializable> params = new HashMap<String, Serializable>();
params.put(ShapefileDataStoreFactory.URLP.key, shapeFile.toURI().toURL());
params.put(ShapefileDataStoreFactory.CREATE_SPATIAL_INDEX.key, Boolean.TRUE);
DataStore dataStore = dataStoreFactory.createNewDataStore(params);
try {
dataStore.createSchema(outputFeatureType);
final String typeName = dataStore.getTypeNames()[0];
final SimpleFeatureSource source = dataStore.getFeatureSource(typeName);
checkParameter(source instanceof SimpleFeatureStore,
"Could not create feature store. Shapefile may be read only");
final SimpleFeatureStore store = (SimpleFeatureStore) source;
ExportOp op = cli.getGeogig().command(ExportOp.class).setFeatureStore(store)
.setPath(path).setFeatureTypeConversionFunction(function);
try {
op.setProgressListener(cli.getProgressListener()).call();
cli.getConsole().println("OSM data exported successfully to " + shapeFile);
} catch (IllegalArgumentException iae) {
shapeFile.delete();
throw new org.locationtech.geogig.cli.InvalidParameterException(iae.getMessage(),
iae);
} catch (GeoToolsOpException e) {
shapeFile.delete();
throw new CommandFailedException("Could not export. Error:" + e.statusCode.name(),
e);
}
} finally {
dataStore.dispose();
}
}
private String getOriginTreesFromOutputFeatureType(SimpleFeatureType featureType) {
GeometryDescriptor descriptor = featureType.getGeometryDescriptor();
Class<?> clazz = descriptor.getType().getBinding();
if (clazz.equals(Point.class)) {
return "node";
} else {
return "way";
}
}
}