ingo@1115: /* ingo@1115: * Copyright (c) 2010 by Intevation GmbH ingo@1115: * ingo@1115: * This program is free software under the LGPL (>=v2.1) ingo@1115: * Read the file LGPL.txt coming with the software for details ingo@1115: * or visit http://www.gnu.org/licenses/ if it does not exist. ingo@1115: */ ingo@1115: sascha@465: package de.intevation.gnv.utils; sascha@465: sascha@465: import java.io.File; sascha@465: import java.io.IOException; sascha@498: import java.io.Serializable; sascha@465: import java.net.MalformedURLException; ingo@760: import java.text.NumberFormat; tim@649: import java.util.Collection; sascha@498: import java.util.Date; sascha@498: import java.util.HashMap; sascha@498: import java.util.List; sascha@498: import java.util.Map; sascha@465: sascha@498: import org.apache.log4j.Logger; sascha@498: import org.geotools.data.DataStoreFactorySpi; sascha@465: import org.geotools.data.DataUtilities; sascha@465: import org.geotools.data.DefaultTransaction; sascha@498: import org.geotools.data.FeatureStore; sascha@498: import org.geotools.data.Transaction; sascha@465: import org.geotools.data.shapefile.ShapefileDataStore; sascha@465: import org.geotools.data.shapefile.ShapefileDataStoreFactory; sascha@498: import org.geotools.feature.FeatureCollection; sascha@498: import org.geotools.feature.FeatureCollections; sascha@498: import org.geotools.feature.SchemaException; sascha@498: import org.geotools.feature.simple.SimpleFeatureBuilder; sascha@498: import org.geotools.referencing.crs.DefaultGeographicCRS; sascha@498: import org.opengis.feature.simple.SimpleFeature; sascha@498: import org.opengis.feature.simple.SimpleFeatureType; sascha@465: tim@799: import com.vividsolutions.jts.geom.Geometry; tim@799: import com.vividsolutions.jts.geom.MultiLineString; tim@799: import com.vividsolutions.jts.geom.MultiPolygon; tim@799: import com.vividsolutions.jts.io.ParseException; tim@799: import com.vividsolutions.jts.io.WKTReader; tim@799: tim@799: import de.intevation.gnv.geobackend.base.Result; tim@799: import de.intevation.gnv.geobackend.base.ResultDescriptor; tim@799: sascha@465: /** sascha@780: * @author Sascha L. Teichmann sascha@465: */ sascha@465: public final class ShapeFileWriter sascha@465: { sascha@465: private static Logger log = Logger.getLogger( sascha@465: ShapeFileWriter.class); sascha@465: ingo@760: private static NumberFormat format = NumberFormat.getInstance(); ingo@760: ingo@806: /** ingo@806: * Precision used to format double values. ingo@806: */ ingo@760: public static final int DOUBLE_PRECISION = 3; ingo@760: ingo@761: static { ingo@761: format.setMaximumFractionDigits(DOUBLE_PRECISION); ingo@761: } ingo@761: sascha@465: private ShapeFileWriter() { sascha@465: } sascha@465: ingo@806: ingo@806: /** ingo@806: * Write multilinestrings to shapefile. ingo@806: * ingo@806: * @param shapeFile Shapefile. ingo@806: * @param parameterId The parameter id. ingo@806: * @param layer The layer. ingo@806: * @param date The date. ingo@806: * @param multiLineStrings The multilinestring. ingo@806: * @return true, if shapefile writing was successful - otherwise false. ingo@806: */ sascha@465: public static boolean writeMultiLineStringsToFile( sascha@465: File shapeFile, sascha@498: Integer parameterId, sascha@498: Integer layer, sascha@498: Date date, sascha@465: List> multiLineStrings sascha@465: ) { sascha@498: return writeMultiLineStringsToFile( sascha@498: shapeFile, sascha@498: parameterId, sascha@498: layer, sascha@498: date, sascha@778: multiLineStrings, sascha@498: "isolines"); sascha@465: } sascha@465: ingo@806: ingo@806: /** ingo@806: * Write multilinestrings to shapefile. ingo@806: * ingo@806: * @param shapeFile Shapefile. ingo@806: * @param parameterId The parameter id. ingo@806: * @param layer The layer. ingo@806: * @param date The date. ingo@806: * @param multiLineStrings The multilinestring. ingo@806: * @param name A name. ingo@806: * @return true, if shapefile writing was successful - otherwise false. ingo@806: */ sascha@465: public static boolean writeMultiLineStringsToFile( sascha@465: File shapeFile, sascha@498: Integer parameterId, sascha@498: Integer layer, sascha@498: Date date, sascha@465: List> multiLineStrings, sascha@498: String name sascha@465: ) { sascha@498: Map params = new HashMap(); sascha@465: sascha@465: try { sascha@498: params.put("url", shapeFile.toURI().toURL()); sascha@465: } sascha@465: catch (MalformedURLException mue) { sascha@465: log.error(mue.getLocalizedMessage(), mue); sascha@465: return false; sascha@465: } sascha@465: sascha@498: params.put("create spatial index", Boolean.TRUE); sascha@465: sascha@465: sascha@498: if (name == null) { sascha@498: name = shapeFile.getName(); sascha@498: } sascha@465: sascha@498: SimpleFeatureType TYPE; sascha@778: sascha@778: try { sascha@498: TYPE = DataUtilities.createType( sascha@498: name, sascha@498: "geom:MultiLineString:srid=4326," + sascha@778: "PARAMETER:Integer," + sascha@498: "LAYER:Integer," + sascha@498: "DATE:Date," + ingo@760: "VALUE:Double," + ingo@760: "DESC:String"); sascha@465: } sascha@465: catch (SchemaException se) { sascha@465: log.error(se.getLocalizedMessage(), se); sascha@498: return false; sascha@465: } sascha@498: sascha@498: SimpleFeatureBuilder featureBuilder = sascha@498: new SimpleFeatureBuilder(TYPE); sascha@498: sascha@778: FeatureCollection collection = sascha@498: FeatureCollections.newCollection(); sascha@498: sascha@498: for (Pair pair: multiLineStrings) { sascha@498: featureBuilder.add(pair.getB()); sascha@498: featureBuilder.add(parameterId); sascha@498: featureBuilder.add(layer); sascha@498: featureBuilder.add(date); sascha@498: featureBuilder.add(pair.getA()); ingo@760: featureBuilder.add(value2description(asDouble(pair.getA()))); sascha@498: SimpleFeature feature = featureBuilder.buildFeature(null); sascha@498: collection.add(feature); sascha@498: } sascha@498: sascha@498: DataStoreFactorySpi dataStoreFactory = new ShapefileDataStoreFactory(); sascha@498: sascha@498: Transaction transaction = null; sascha@498: sascha@498: boolean success = false; sascha@498: try { sascha@498: ShapefileDataStore newDataStore = sascha@498: (ShapefileDataStore)dataStoreFactory.createNewDataStore(params); sascha@498: sascha@498: newDataStore.createSchema(TYPE); sascha@498: newDataStore.forceSchemaCRS(DefaultGeographicCRS.WGS84); sascha@498: sascha@498: transaction = new DefaultTransaction("create"); sascha@498: sascha@498: String typeName = newDataStore.getTypeNames()[0]; sascha@498: sascha@498: FeatureStore featureStore = sascha@498: (FeatureStore) sascha@498: newDataStore.getFeatureSource(typeName); sascha@498: sascha@498: featureStore.setTransaction(transaction); sascha@498: sascha@498: featureStore.addFeatures(collection); sascha@498: transaction.commit(); sascha@498: success = true; sascha@778: } sascha@465: catch (IOException ioe) { sascha@465: log.error(ioe.getLocalizedMessage(), ioe); sascha@465: } sascha@465: finally { sascha@498: if (transaction != null) { sascha@498: if (!success) { sascha@498: try { transaction.rollback(); } sascha@498: catch (IOException ioe) {} sascha@498: } sascha@498: try { transaction.close(); } sascha@465: catch (IOException ioe) {} sascha@465: } sascha@465: } sascha@465: sascha@465: return success; sascha@465: } sascha@465: ingo@806: ingo@806: /** ingo@806: * Write multipolygon to file. ingo@806: * ingo@806: * @param shapeFile The shapefile. ingo@806: * @param parameterId The parameter id. ingo@806: * @param layer The layer. ingo@806: * @param date The date. ingo@806: * @param multiPolygons Multipolygons. ingo@806: * @return true, if shapefile writing was successful - otherwise false. ingo@806: */ sascha@465: public static boolean writeMultiPolygonsToFile( sascha@465: File shapeFile, sascha@498: Integer parameterId, sascha@498: Integer layer, sascha@498: Date date, sascha@465: Map multiPolygons sascha@465: ) { sascha@498: return writeMultiPolygonsToFile( sascha@778: shapeFile, sascha@498: parameterId, sascha@498: layer, sascha@498: date, sascha@778: multiPolygons, sascha@498: "polygons"); sascha@465: } sascha@465: sascha@778: ingo@806: /** ingo@806: * Write data to shapefile. ingo@806: * ingo@806: * @param shapeFile The shapefile. ingo@806: * @param name The name. ingo@806: * @param data The data. ingo@806: * @param geometryType The geometry type. ingo@806: * @return true, if shapefile writing was successful - otherwise false. ingo@806: */ tim@799: public static boolean writeDataToFile(File shapeFile, tim@649: String name, tim@799: Collection data, tim@799: String geometryType){ sascha@778: tim@649: WKTReader wktReader = new WKTReader(); sascha@778: tim@649: Map params = new HashMap(); tim@649: tim@649: try { tim@649: params.put("url", shapeFile.toURI().toURL()); tim@649: } tim@649: catch (MalformedURLException mue) { tim@649: log.error(mue.getLocalizedMessage(), mue); tim@799: return false; tim@649: } tim@649: tim@649: params.put("create spatial index", Boolean.TRUE); tim@649: tim@649: tim@649: if (name == null) { tim@649: name = shapeFile.getName(); tim@649: } tim@649: tim@649: SimpleFeatureType type = null; tim@649: SimpleFeatureBuilder featureBuilder = null; sascha@778: FeatureCollection collection = tim@649: FeatureCollections.newCollection(); tim@727: int j = 0; tim@649: for (Result result: data) { tim@727: j++; tim@649: try { tim@649: Geometry g = wktReader.read(result.getString(0)); tim@727: ResultDescriptor rd = result.getResultDescriptor(); tim@727: int columns = rd.getColumnCount(); tim@649: if (type == null){ sascha@778: try { tim@799: String schema = "geom:"+geometryType+":srid=4326"; tim@727: for (int i = 1; i < columns; i++){ tim@727: schema+=","+rd.getColumnName(i)+ tim@727: ":"+rd.getColumnClassName(i); tim@727: } tim@727: type = DataUtilities.createType(name, schema); tim@649: } tim@649: catch (SchemaException se) { tim@649: log.error(se.getLocalizedMessage(), se); tim@799: return false; tim@649: } tim@649: featureBuilder = new SimpleFeatureBuilder(type); tim@649: } tim@649: featureBuilder.add(g); tim@727: for (int i = 1; i < columns; i++){ tim@727: featureBuilder.add(result.getObject(i)); tim@727: } tim@649: SimpleFeature feature = featureBuilder.buildFeature(null); tim@649: collection.add(feature); tim@649: } catch (ParseException e) { tim@727: log.error("cannot create geometry "+j+" for "+result.getString(0)); tim@649: } catch (java.lang.IllegalArgumentException e){ tim@649: log.error("cannot create geometry for "+result.getString(0)); tim@649: } tim@649: } tim@649: tim@649: DataStoreFactorySpi dataStoreFactory = new ShapefileDataStoreFactory(); tim@649: tim@649: Transaction transaction = null; tim@649: tim@649: boolean success = false; tim@649: try { tim@649: ShapefileDataStore newDataStore = tim@649: (ShapefileDataStore)dataStoreFactory.createNewDataStore(params); tim@649: tim@649: newDataStore.createSchema(type); tim@649: newDataStore.forceSchemaCRS(DefaultGeographicCRS.WGS84); tim@649: tim@649: transaction = new DefaultTransaction("create"); tim@649: tim@649: String typeName = newDataStore.getTypeNames()[0]; tim@649: tim@649: FeatureStore featureStore = tim@649: (FeatureStore) tim@649: newDataStore.getFeatureSource(typeName); tim@649: tim@649: featureStore.setTransaction(transaction); tim@649: tim@649: featureStore.addFeatures(collection); tim@649: transaction.commit(); tim@649: success = true; sascha@778: } tim@649: catch (IOException ioe) { tim@649: log.error(ioe.getLocalizedMessage(), ioe); tim@649: } tim@649: finally { tim@649: if (transaction != null) { tim@649: if (!success) { tim@649: try { transaction.rollback(); } tim@649: catch (IOException ioe) {} tim@649: } tim@649: try { transaction.close(); } tim@649: catch (IOException ioe) {} tim@649: } tim@649: } tim@649: tim@799: return true; tim@649: } sascha@778: ingo@806: ingo@806: /** ingo@806: * Write multipolygons to file. ingo@806: * ingo@806: * @param shapeFile The shapefile. ingo@806: * @param parameterId The parameter id. ingo@806: * @param layer The layer. ingo@806: * @param date The date. ingo@806: * @param multiPolygons Multipolygons. ingo@806: * @param name A name. ingo@806: * @return true, if shapefile writing was successful - otherwise false. ingo@806: */ sascha@465: public static boolean writeMultiPolygonsToFile( sascha@465: File shapeFile, sascha@498: Integer parameterId, sascha@498: Integer layer, sascha@498: Date date, sascha@465: Map multiPolygons, sascha@498: String name sascha@465: ) { sascha@498: Map params = new HashMap(); sascha@465: sascha@465: try { sascha@498: params.put("url", shapeFile.toURI().toURL()); sascha@465: } sascha@465: catch (MalformedURLException mue) { sascha@465: log.error(mue.getLocalizedMessage(), mue); sascha@465: return false; sascha@465: } sascha@465: sascha@498: params.put("create spatial index", Boolean.TRUE); sascha@465: sascha@465: sascha@498: if (name == null) { sascha@498: name = shapeFile.getName(); sascha@498: } sascha@465: sascha@498: SimpleFeatureType TYPE; sascha@778: sascha@778: try { sascha@498: TYPE = DataUtilities.createType( sascha@498: name, sascha@498: "geom:MultiPolygon:srid=4326," + sascha@778: "PARAMETER:Integer," + sascha@498: "LAYER:Integer," + sascha@498: "DATE:Date," + sascha@498: "CLASS:Integer"); sascha@465: } sascha@465: catch (SchemaException se) { sascha@465: log.error(se.getLocalizedMessage(), se); sascha@498: return false; sascha@465: } sascha@498: sascha@498: SimpleFeatureBuilder featureBuilder = sascha@498: new SimpleFeatureBuilder(TYPE); sascha@498: sascha@778: FeatureCollection collection = sascha@498: FeatureCollections.newCollection(); sascha@498: sascha@498: for (Map.Entry entry: sascha@498: multiPolygons.entrySet() sascha@498: ) { sascha@498: featureBuilder.add(entry.getValue()); sascha@498: featureBuilder.add(parameterId); sascha@498: featureBuilder.add(layer); sascha@498: featureBuilder.add(date); sascha@498: featureBuilder.add(entry.getKey()); sascha@498: SimpleFeature feature = featureBuilder.buildFeature(null); sascha@498: collection.add(feature); sascha@498: } sascha@498: sascha@498: DataStoreFactorySpi dataStoreFactory = new ShapefileDataStoreFactory(); sascha@498: sascha@498: Transaction transaction = null; sascha@498: sascha@498: boolean success = false; sascha@498: try { sascha@498: ShapefileDataStore newDataStore = sascha@498: (ShapefileDataStore)dataStoreFactory.createNewDataStore(params); sascha@498: sascha@498: newDataStore.createSchema(TYPE); sascha@498: newDataStore.forceSchemaCRS(DefaultGeographicCRS.WGS84); sascha@498: sascha@498: transaction = new DefaultTransaction("create"); sascha@498: sascha@498: String typeName = newDataStore.getTypeNames()[0]; sascha@498: sascha@498: FeatureStore featureStore = sascha@498: (FeatureStore) sascha@498: newDataStore.getFeatureSource(typeName); sascha@498: sascha@498: featureStore.setTransaction(transaction); sascha@498: sascha@498: featureStore.addFeatures(collection); sascha@498: transaction.commit(); sascha@498: success = true; sascha@778: } sascha@465: catch (IOException ioe) { sascha@465: log.error(ioe.getLocalizedMessage(), ioe); sascha@465: } sascha@465: finally { sascha@498: if (transaction != null) { sascha@498: if (!success) { sascha@498: try { transaction.rollback(); } sascha@498: catch (IOException ioe) {} sascha@498: } sascha@498: try { transaction.close(); } sascha@465: catch (IOException ioe) {} sascha@465: } sascha@465: } sascha@465: sascha@465: return success; sascha@465: } sascha@465: ingo@806: /** ingo@806: * Returns an object as Double. ingo@806: * ingo@806: * @param a An object. ingo@806: * @return Object a as Double. If a is not a double and no ingo@806: * number, 0d is returned. ingo@806: */ sascha@465: private static final Double asDouble(Object a) { sascha@498: if (a instanceof Double) { sascha@465: return (Double)a; sascha@498: } sascha@498: if (a instanceof Number) { sascha@465: return Double.valueOf(((Number)a).doubleValue()); sascha@498: } sascha@465: return 0d; sascha@465: } ingo@760: ingo@806: /** ingo@806: * Turns a double value into a string representation taking account of the ingo@806: * locale. ingo@806: * ingo@806: * @param value A double value. ingo@806: * @return The double value formatted as string. ingo@806: */ ingo@760: private static final String value2description(Double value) { ingo@760: return format.format(value); ingo@760: } sascha@465: } sascha@465: // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :