package org.ianturton.cookbook.output; import java.io.File; import java.io.IOException; import java.io.Serializable; import java.net.MalformedURLException; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import org.geotools.data.DataUtilities; import org.geotools.data.DefaultTransaction; import org.geotools.data.Transaction; import org.geotools.data.collection.ListFeatureCollection; import org.geotools.data.shapefile.ShapefileDataStore; import org.geotools.data.shapefile.ShapefileDataStoreFactory; import org.geotools.data.simple.SimpleFeatureCollection; import org.geotools.data.simple.SimpleFeatureSource; import org.geotools.data.simple.SimpleFeatureStore; import org.geotools.feature.FeatureCollection; import org.geotools.feature.FeatureIterator; import org.geotools.feature.NameImpl; import org.geotools.feature.SchemaException; import org.geotools.feature.simple.SimpleFeatureBuilder; import org.geotools.feature.simple.SimpleFeatureTypeImpl; import org.geotools.feature.type.GeometryDescriptorImpl; import org.geotools.feature.type.GeometryTypeImpl; import org.opengis.feature.simple.SimpleFeature; import org.opengis.feature.simple.SimpleFeatureType; import org.opengis.feature.type.AttributeDescriptor; import org.opengis.feature.type.AttributeType; import org.opengis.feature.type.GeometryDescriptor; import org.opengis.feature.type.GeometryType; import org.opengis.filter.identity.FeatureId; import com.vividsolutions.jts.geom.Coordinate; import com.vividsolutions.jts.geom.GeometryFactory; public class WriteShapefile { File outfile; private ShapefileDataStore shpDataStore; public WriteShapefile(File f) { outfile = f; ShapefileDataStoreFactory dataStoreFactory = new ShapefileDataStoreFactory(); Map<String, Serializable> params = new HashMap<String, Serializable>(); try { params.put("url", outfile.toURI().toURL()); } catch (MalformedURLException e) { // TODO Auto-generated catch block e.printStackTrace(); } params.put("create spatial index", Boolean.TRUE); try { shpDataStore = (ShapefileDataStore) dataStoreFactory .createNewDataStore(params); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } public boolean writeFeatures( FeatureCollection<SimpleFeatureType, SimpleFeature> features) { if (shpDataStore == null) { throw new IllegalStateException("Datastore can not be null when writing"); } SimpleFeatureType schema = features.getSchema(); GeometryDescriptor geom = schema.getGeometryDescriptor(); try { /* * Write the features to the shapefile */ Transaction transaction = new DefaultTransaction("create"); String typeName = shpDataStore.getTypeNames()[0]; SimpleFeatureSource featureSource = shpDataStore .getFeatureSource(typeName); /* * The Shapefile format has a couple limitations: - "the_geom" is always * first, and used for the geometry attribute name - "the_geom" must be of * type Point, MultiPoint, MuiltiLineString, MultiPolygon - Attribute * names are limited in length - Not all data types are supported (example * Timestamp represented as Date) * * Because of this we have to rename the geometry element and then rebuild * the features to make sure that it is the first attribute. */ List<AttributeDescriptor> attributes = schema.getAttributeDescriptors(); GeometryType geomType = null; List<AttributeDescriptor> attribs = new ArrayList<AttributeDescriptor>(); for (AttributeDescriptor attrib : attributes) { AttributeType type = attrib.getType(); if (type instanceof GeometryType) { geomType = (GeometryType) type; } else { attribs.add(attrib); } } GeometryTypeImpl gt = new GeometryTypeImpl(new NameImpl("the_geom"), geomType.getBinding(), geomType.getCoordinateReferenceSystem(), geomType.isIdentified(), geomType.isAbstract(), geomType.getRestrictions(), geomType.getSuper(), geomType.getDescription()); GeometryDescriptor geomDesc = new GeometryDescriptorImpl(gt, new NameImpl("the_geom"), geom.getMinOccurs(), geom.getMaxOccurs(), geom.isNillable(), geom.getDefaultValue()); attribs.add(0, geomDesc); SimpleFeatureType shpType = new SimpleFeatureTypeImpl(schema.getName(), attribs, geomDesc, schema.isAbstract(), schema.getRestrictions(), schema.getSuper(), schema.getDescription()); shpDataStore.createSchema(shpType); if (featureSource instanceof SimpleFeatureStore) { SimpleFeatureStore featureStore = (SimpleFeatureStore) featureSource; List<SimpleFeature> feats = new ArrayList<SimpleFeature>(); FeatureIterator<SimpleFeature> features2 = features.features(); while (features2.hasNext()) { SimpleFeature f = features2.next(); SimpleFeature reType = SimpleFeatureBuilder.build(shpType, f.getAttributes(), ""); feats.add(reType); } features2.close(); SimpleFeatureCollection collection = new ListFeatureCollection(shpType, feats); featureStore.setTransaction(transaction); try { List<FeatureId> ids = featureStore.addFeatures(collection); transaction.commit(); } catch (Exception problem) { problem.printStackTrace(); transaction.rollback(); } finally { transaction.close(); } shpDataStore.dispose(); return true; } else { shpDataStore.dispose(); System.err.println("ShapefileStore not writable"); return false; } } catch (IOException e) { e.printStackTrace(); } return false; } public static void main(String[] args) { File file; if (args.length > 0) { file = new File(args[0]); } else { file = new File("ian.shp"); } // create some random features and write them out; List<SimpleFeature> feats = new ArrayList<SimpleFeature>(); SimpleFeatureType schema = null; try { schema = DataUtilities.createType("", "Location", "locations:Point:srid=4326," + // <- the geometry attribute: // Point type "name:String," + // <- a String attribute "number:Integer" // a number attribute ); } catch (SchemaException e) { // TODO Auto-generated catch block e.printStackTrace(); return; } for (int i = 0; i < 10; i++) { SimpleFeature f = createSimpleFeature(schema); feats.add(f); } WriteShapefile writer = new WriteShapefile(file); FeatureCollection<SimpleFeatureType, SimpleFeature> features = new ListFeatureCollection( schema, feats); writer.writeFeatures(features); } private static SimpleFeature createSimpleFeature(SimpleFeatureType schema) { SimpleFeatureBuilder featureBuilder = new SimpleFeatureBuilder(schema); double latitude = (Math.random() * 180.0) - 90.0; double longitude = (Math.random() * 360.0) - 180.0; String name = "thing" + Math.random(); int number = (int) Math.round(Math.random() * 10.0); GeometryFactory geometryFactory = new GeometryFactory(); /* Longitude (= x coord) first ! */ com.vividsolutions.jts.geom.Point point = geometryFactory .createPoint(new Coordinate(longitude, latitude)); featureBuilder.add(point); featureBuilder.add(name); featureBuilder.add(number); SimpleFeature feature = featureBuilder.buildFeature(null); return feature; } }