Mercurial > dive4elements > gnv-client
changeset 649:4fc97074eb90
Added Support for writing Shapefiles and Export them as an Zipfile for the Product Layer.
gnv-artifacts/trunk@738 c6561f87-3c4e-4783-a992-168aeb5c3f6f
author | Tim Englich <tim.englich@intevation.de> |
---|---|
date | Fri, 05 Mar 2010 12:35:24 +0000 |
parents | 7c67ff162e87 |
children | 1946c4e9a878 |
files | gnv-artifacts/ChangeLog gnv-artifacts/doc/conf/conf.xml gnv-artifacts/doc/conf/products/layer/conf.xml gnv-artifacts/doc/conf/queries.properties gnv-artifacts/src/main/java/de/intevation/gnv/state/layer/LayerOutputState.java gnv-artifacts/src/main/java/de/intevation/gnv/utils/ShapeFileWriter.java gnv-artifacts/src/main/resources/lang/artifactMessages.properties gnv-artifacts/src/main/resources/lang/artifactMessages_de.properties gnv-artifacts/src/main/resources/lang/artifactMessages_de_DE.properties gnv-artifacts/src/main/resources/lang/artifactMessages_en.properties |
diffstat | 10 files changed, 431 insertions(+), 27 deletions(-) [+] |
line wrap: on
line diff
--- a/gnv-artifacts/ChangeLog Fri Mar 05 09:13:17 2010 +0000 +++ b/gnv-artifacts/ChangeLog Fri Mar 05 12:35:24 2010 +0000 @@ -1,5 +1,31 @@ 2010-03-05 Tim Englich <tim.englich@intevation.de> + * doc/conf/queries.properties: + Added some more Queries which are required to serve the Requests of the + Product Layer. + + * doc/conf/conf.xml: + Changed the Sourceid of the FIS Contis because of Changes in the Database. + + * doc/conf/products/layer/conf.xml: + Completed the Configuration for the Product Layer. + Added more Configurationdetails to the OutputStates. + * src/main/resources/lang/artifactMessages*.properties: + Added the required ressources for the Product Layer and the FIS Contis and + Nauthis into the Propertiesfiles. + + * src/main/java/de/intevation/gnv/utils/ShapeFileWriter.java (writeDataToFile): + Added an Method for writing g an Shapefile using an Collection of Results. + this Method must be extended that it could use the Result-object in an + generic Way. + At this Moment it is only be Possible to write the Geometry into the + Shapefile if it is given at the first Position of an Result. + All other Attributevalues will be ignored and not written into the Shapefile. + + * src/main/java/de/intevation/gnv/state/layer/LayerOutputState.java: + Added Support for writing Shapefiles and Export them as an Zipfile. + +2010-03-05 Tim Englich <tim.englich@intevation.de> * doc/conf/products/verticalprofile/conf_instantaneouspoint.xml: ISSUE 191: Pdf, svg and png are now available.
--- a/gnv-artifacts/doc/conf/conf.xml Fri Mar 05 09:13:17 2010 +0000 +++ b/gnv-artifacts/doc/conf/conf.xml Fri Mar 05 12:35:24 2010 +0000 @@ -381,7 +381,7 @@ <artifact-factory name="layer" description="Artiefactfactory for Instantiating the Artifact for the Product Layer" ttl="300000" artifact="de.intevation.gnv.layer.LayerArtifact">de.intevation.gnv.artifacts.GNVArtifactFactory</artifact-factory> <parameters> - <parameter name="sourceid" value="Contis%"/> + <parameter name="sourceid" value="contis%"/> <parameter name="fisname" value="fis_contis"/> </parameters> </product>
--- a/gnv-artifacts/doc/conf/products/layer/conf.xml Fri Mar 05 09:13:17 2010 +0000 +++ b/gnv-artifacts/doc/conf/products/layer/conf.xml Fri Mar 05 12:35:24 2010 +0000 @@ -54,8 +54,21 @@ <transition transition="de.intevation.gnv.transition.DefaultTransition"> <from state="layer_without_geom"/> - <to state="layer_calculate_results"/> + <to state="layer_calculate_results_without_geom"/> </transition> + + <state id="layer_calculate_results_without_geom" description="layer_calculate_results" state="de.intevation.gnv.state.layer.LayerOutputState"> + <queryID>layer_request_data</queryID> + <queryID-layerdata>layer_data</queryID-layerdata> + <inputvalues> + <inputvalue name="sourceid" type="String" multiselect="false" usedinquery="0"/> + <inputvalue name="layerid" type="Integer" multiselect="false" usedinquery="1"/> + </inputvalues> + <outputsModes> + <outputsMode name="zip" description="Export als ZIP-Archiv" mime-type="application/zip"/> + <outputsMode name="wms" description="WMS-Layer bereitstellen" mime-type="text/url"/> + </outputsModes> + </state> <state id="layer" description="layer" state="de.intevation.gnv.state.DefaultState"> <queryID>layer</queryID> @@ -76,10 +89,13 @@ <state id="layer_calculate_results" description="layer_calculate_results" state="de.intevation.gnv.state.layer.LayerOutputState"> <queryID>layer_request_data</queryID> - <queryID-layerdata>layer_data</queryID-layerdata> + <queryID-layerdata>layer_data_with_geom</queryID-layerdata> + <queryID-geometry>geometry_for_subareafilter</queryID-geometry> + <inputvalue-geometry>subareaid</inputvalue-geometry> <inputvalues> <inputvalue name="sourceid" type="String" multiselect="false" usedinquery="0"/> - <inputvalue name="layerid" type="Integer" multiselect="false" usedinquery="0"/> + <inputvalue name="layerid" type="Integer" multiselect="false" usedinquery="1"/> + <inputvalue name="subareaid" type="Integer" multiselect="false" usedinquery="0"/> </inputvalues> <outputsModes> <outputsMode name="zip" description="Export als ZIP-Archiv" mime-type="application/zip"/>
--- a/gnv-artifacts/doc/conf/queries.properties Fri Mar 05 09:13:17 2010 +0000 +++ b/gnv-artifacts/doc/conf/queries.properties Fri Mar 05 12:35:24 2010 +0000 @@ -1221,7 +1221,7 @@ ############################################# ############################################# -layer = SELECT ID_LAYER KEY, \ +layer = SELECT ROW_ID KEY, \ TITLE || '-' || LAYER_NAME VALUE \ FROM MEDIAN.LAYER_HAS_SUBTYPES \ WHERE ID_FEATURECLASS LIKE ? \ @@ -1230,10 +1230,20 @@ layer_request_data = SELECT ID_FEATURECLASS, \ QUERY_STRING, \ TITLE, \ - LAYERNAME \ + LAYER_NAME \ FROM MEDIAN.LAYER_HAS_SUBTYPES \ - WHERE ID_LAYER = ? + WHERE ROW_ID = ? layer_data = SELECT ST_ASTEXT(SHAPE) \ FROM ? \ WHERE ? + +layer_data_with_geom = SELECT ST_ASTEXT(SHAPE) \ + FROM ? \ + WHERE ? AND \ + INTERSECTS(SHAPE,"?") + +geometry_for_subareafilter=SELECT st_astext(SHAPE) \ + FROM MEDIAN.FEATUREAREA \ + WHERE (FEATURETYPE = 7 OR FEATURETYPE = 8) AND \ + FEATURECODE = ?
--- a/gnv-artifacts/src/main/java/de/intevation/gnv/state/layer/LayerOutputState.java Fri Mar 05 09:13:17 2010 +0000 +++ b/gnv-artifacts/src/main/java/de/intevation/gnv/state/layer/LayerOutputState.java Fri Mar 05 12:35:24 2010 +0000 @@ -3,6 +3,8 @@ */ package de.intevation.gnv.state.layer; +import java.io.File; +import java.io.IOException; import java.io.OutputStream; import java.util.Collection; import java.util.Iterator; @@ -11,14 +13,25 @@ import org.w3c.dom.Document; import org.w3c.dom.Node; +import com.vividsolutions.jts.geom.Geometry; +import com.vividsolutions.jts.io.ParseException; +import com.vividsolutions.jts.io.WKTReader; + import de.intevation.artifactdatabase.Config; import de.intevation.artifactdatabase.XMLUtils; import de.intevation.artifacts.ArtifactNamespaceContext; import de.intevation.artifacts.CallContext; +import de.intevation.gnv.artifacts.context.GNVArtifactContext; import de.intevation.gnv.geobackend.base.Result; +import de.intevation.gnv.geobackend.base.query.QueryExecutor; +import de.intevation.gnv.geobackend.base.query.QueryExecutorFactory; +import de.intevation.gnv.geobackend.base.query.exception.QueryException; import de.intevation.gnv.state.InputData; import de.intevation.gnv.state.OutputStateBase; import de.intevation.gnv.state.exception.StateException; +import de.intevation.gnv.utils.FileUtils; +import de.intevation.gnv.utils.MapfileGenerator; +import de.intevation.gnv.utils.ShapeFileWriter; /** * @author Tim Englich <tim.englich@intevation.de> @@ -40,6 +53,24 @@ * The ID for the Query fetching the Layer from the DB */ private String dataQueryID = null; + + /** + * The ID for the Query fetching the Geometry from the DB + * which should be used to Clip the Layerdata + */ + private String geometryQueryID = null; + + /** + * The ID for the Value which will hold the Geometrie-Value + */ + private String geometryID = null; + + private Boolean shapeFileLock = new Boolean(true); + + private String shapeFilePath; + + public static final String SHAPEFILE_NAME = "data.shp"; + /** * Constructor */ @@ -64,29 +95,94 @@ // TODO USE ME }else if (outputMode.equalsIgnoreCase("zip")){ Collection<Result> data = this.fetchData(); - // TODO USE ME + this.writeZip(uuid, callContext, outputStream, data); } } + /** + * Fetches the Data from the Databasebackend + * @return + */ protected Collection<Result> fetchData(){ log.debug("LayerOutputState.fetchData"); // TODO PUT ALL in CACHE Collection<Result> result = this.getData(this.queryID); Collection<Result> data = null; + String geometryWKT = null; if (result != null){ + QueryExecutor queryExecutor = QueryExecutorFactory.getInstance() + .getQueryExecutor(); Iterator<Result> it = result.iterator(); - String table = null; - String where = null; + String[] queryValues = null; if (it.hasNext()){ Result resultValue = it.next(); - table = resultValue.getString(0); - where = resultValue.getString(1); - // TODO ADD SpatialFilter if Geometry is available + String table = resultValue.getString(0); + String where = resultValue.getString(1); + if (this.geometryID != null){ + InputData geometryInputData = + this.inputData.get(this.geometryID); + if (geometryInputData != null){ + + try { + Collection<Result> geometryData = queryExecutor + .executeQuery(this.geometryQueryID, + new String[]{geometryInputData.getValue()}); + Iterator<Result> git = geometryData.iterator(); + if (git.hasNext()){ + Result geometryValue = git.next(); + geometryWKT = geometryValue.getString(0); + } + } catch (QueryException e) { + log.error(e,e); + // TODO: what should happen?? + } + queryValues = new String[]{table, + where, + geometryWKT}; + }else{ + // TODO: Look into the presetting for an WKT + queryValues = new String[]{table,where}; + } + }else{ + // TODO: Look into the presetting for an WKT + queryValues = new String[]{table,where}; + + } } - data = null; // TODO Fetch the Data for the Layer and Trim the Geometries - // using the Geometry if on is available. + try { + data = queryExecutor.executeQuery(dataQueryID, + queryValues); + if (data != null && geometryWKT != null){ + WKTReader wktReader = new WKTReader(); + Geometry border = wktReader.read(geometryWKT); + + Iterator<Result> dataIt = data.iterator(); + while (dataIt.hasNext()){ + // Trim the Geometries using the + // Geometry if on is available. + Result current = dataIt.next(); + String currentWKT = current.getString(0); + Geometry currentGeometry = null; + try { + currentGeometry = wktReader.read(currentWKT); + } catch (Exception e) { + log.error("Error parsing Geometry "+ currentWKT); + log.error(e,e); + } + + if (currentGeometry != null){ + Geometry newGeometry = currentGeometry.intersection(border); + current.addColumnValue(0, newGeometry.toText()); + } + } + } + } catch (QueryException e) { + log.error(e,e); + } catch (ParseException e){ + log.error(e,e); + } } return data; } @@ -95,7 +191,151 @@ public void setup(Node configuration) { log.debug("LayerOutputState.setup"); super.setup(configuration); - this.dataQueryID = Config.getStringXPath(configuration,"queryID-layerdata"); + this.dataQueryID = Config.getStringXPath(configuration, + "queryID-layerdata"); + this.geometryID = Config.getStringXPath(configuration, + "inputvalue-geometry"); + this.geometryQueryID = Config.getStringXPath(configuration, + "queryID-geometry"); } + + protected String writeToShapeFile( + String uuid, + Collection<Result> data, + CallContext callContext + ) { + File baseDir = shapefileDirectory(callContext); + + File shapeDir = new File(baseDir, uuid); + boolean success = false; + boolean createdDir = false; + + try { + synchronized (shapeFileLock) { + int count = 0; + while (shapeDir.exists()) { + shapeDir = new File(baseDir, uuid + "-" + count); + ++count; + } + + if (!shapeDir.mkdirs()) { + log.error("cannot create directory '" + + shapeDir.getAbsolutePath() + "'"); + return null; + } + createdDir = true; + } + + File shapeFile = new File(shapeDir, SHAPEFILE_NAME); + if (!ShapeFileWriter.writeDataToFile(shapeFile, "data", data)){ + log.error("writing data into shapefile failed"); + return null; + } + + shapeFilePath = shapeDir.getAbsolutePath(); + success = true; + + callContext.afterCall(CallContext.STORE); + + return shapeFilePath; + } + finally { + if (!success && createdDir) { + FileUtils.deleteRecursive(shapeDir); + } + } + } + + protected void writeZip( + String uuid, + CallContext callContext, + OutputStream output, + Collection<Result> data + ) + throws StateException + { + try { + String p = getShapeFilePath(); + if (p != null) { + File dir = new File(p); + if (dir.isDirectory()) { + FileUtils.createZipArchive(dir, output); + } + } + else { + + if ((p = writeToShapeFile(uuid, data, callContext)) != null) { + FileUtils.createZipArchive(new File(p), output); + } + } + } + catch (IOException ioe) { + log.error(ioe.getLocalizedMessage(), ioe); + } + } + + public String getShapeFilePath() { + synchronized (shapeFileLock) { + return shapeFilePath; + } + } + + private static File shapefileDirectory(CallContext callContext) { + // TODO: Refactoring nessessary it should be used only one Shapefilepath + // for alle Modes. Code was taken from HorizontalCrossSectionMeshOutputState + GNVArtifactContext context = + (GNVArtifactContext)callContext.globalContext(); + File dir = (File)context.get( + GNVArtifactContext.HORIZONTAL_CROSS_SECTION_RESULT_SHAPEFILE_PATH_KEY); + return dir != null + ? dir + : GNVArtifactContext.DEFAULT_HORIZONTAL_CROSS_SECTION_PROFILE_SHAPEFILE_PATH; + } + + /** + * @see de.intevation.gnv.state.StateBase#endOfLife(java.lang.Object) + */ + @Override + public void endOfLife(Object globalContext) { + super.endOfLife(globalContext); + + // do it in background + new Thread() { + public void run() { + // TODO: Do the un-publishing WMS stuff. + String path = resetShapeFilePath(); + + if (path == null) { + return; + } + + File dir = new File(path); + + for (int i = 0; i < 10; ++i) { + if (!dir.exists() || FileUtils.deleteRecursive(dir)) { + MapfileGenerator.getInstance().update(); + return; + } + + try { + Thread.sleep(10000L); + } + catch (InterruptedException ie) { + } + } + + log.error("failed to remove directory '" + path + "'"); + } // run + }.start(); + } + + public String resetShapeFilePath() { + synchronized (shapeFileLock) { + String path = shapeFilePath; + shapeFilePath = null; + return path; + } + } + }
--- a/gnv-artifacts/src/main/java/de/intevation/gnv/utils/ShapeFileWriter.java Fri Mar 05 09:13:17 2010 +0000 +++ b/gnv-artifacts/src/main/java/de/intevation/gnv/utils/ShapeFileWriter.java Fri Mar 05 12:35:24 2010 +0000 @@ -1,41 +1,39 @@ package de.intevation.gnv.utils; -import com.vividsolutions.jts.geom.MultiLineString; -import com.vividsolutions.jts.geom.MultiPolygon; - import java.io.File; import java.io.IOException; import java.io.Serializable; - import java.net.MalformedURLException; - +import java.util.Collection; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; import org.apache.log4j.Logger; - import org.geotools.data.DataStoreFactorySpi; import org.geotools.data.DataUtilities; import org.geotools.data.DefaultTransaction; import org.geotools.data.FeatureStore; import org.geotools.data.Transaction; - import org.geotools.data.shapefile.ShapefileDataStore; import org.geotools.data.shapefile.ShapefileDataStoreFactory; - import org.geotools.feature.FeatureCollection; import org.geotools.feature.FeatureCollections; import org.geotools.feature.SchemaException; - import org.geotools.feature.simple.SimpleFeatureBuilder; - import org.geotools.referencing.crs.DefaultGeographicCRS; - import org.opengis.feature.simple.SimpleFeature; import org.opengis.feature.simple.SimpleFeatureType; +import com.vividsolutions.jts.geom.Geometry; +import com.vividsolutions.jts.geom.MultiLineString; +import com.vividsolutions.jts.geom.MultiPolygon; +import com.vividsolutions.jts.io.ParseException; +import com.vividsolutions.jts.io.WKTReader; + +import de.intevation.gnv.geobackend.base.Result; + /** * @author Sascha L. Teichmann (sascha.teichmann@intevation.de) */ @@ -179,6 +177,104 @@ "polygons"); } + + public static boolean writeDataToFile(File shapeFile, + String name, + Collection<Result> data){ + WKTReader wktReader = new WKTReader(); + + Map<String, Serializable> params = new HashMap<String, Serializable>(); + + try { + params.put("url", shapeFile.toURI().toURL()); + } + catch (MalformedURLException mue) { + log.error(mue.getLocalizedMessage(), mue); + return false; + } + + params.put("create spatial index", Boolean.TRUE); + + + if (name == null) { + name = shapeFile.getName(); + } + + SimpleFeatureType type = null; + SimpleFeatureBuilder featureBuilder = null; + FeatureCollection<SimpleFeatureType, SimpleFeature> collection = + FeatureCollections.newCollection(); + + for (Result result: data) { + try { + Geometry g = wktReader.read(result.getString(0)); + if (type == null){ + try { + type = DataUtilities.createType( + name, + "geom:"+g.getGeometryType()+":srid=4326"); + // TODO add other AttributeTypes + } + catch (SchemaException se) { + log.error(se.getLocalizedMessage(), se); + return false; + } + featureBuilder = new SimpleFeatureBuilder(type); + } + featureBuilder.add(g); + SimpleFeature feature = featureBuilder.buildFeature(null); + collection.add(feature); + } catch (ParseException e) { + log.error(e,e); + } catch (java.lang.IllegalArgumentException e){ + log.error("cannot create geometry for "+result.getString(0)); + } + } + + DataStoreFactorySpi dataStoreFactory = new ShapefileDataStoreFactory(); + + Transaction transaction = null; + + boolean success = false; + try { + ShapefileDataStore newDataStore = + (ShapefileDataStore)dataStoreFactory.createNewDataStore(params); + + newDataStore.createSchema(type); + newDataStore.forceSchemaCRS(DefaultGeographicCRS.WGS84); + + transaction = new DefaultTransaction("create"); + + String typeName = newDataStore.getTypeNames()[0]; + + FeatureStore<SimpleFeatureType, SimpleFeature> featureStore = + (FeatureStore<SimpleFeatureType, SimpleFeature>) + newDataStore.getFeatureSource(typeName); + + featureStore.setTransaction(transaction); + + featureStore.addFeatures(collection); + transaction.commit(); + success = true; + } + catch (IOException ioe) { + log.error(ioe.getLocalizedMessage(), ioe); + } + finally { + if (transaction != null) { + if (!success) { + try { transaction.rollback(); } + catch (IOException ioe) {} + } + try { transaction.close(); } + catch (IOException ioe) {} + } + } + + return success; + + } + public static boolean writeMultiPolygonsToFile( File shapeFile, Integer parameterId,
--- a/gnv-artifacts/src/main/resources/lang/artifactMessages.properties Fri Mar 05 09:13:17 2010 +0000 +++ b/gnv-artifacts/src/main/resources/lang/artifactMessages.properties Fri Mar 05 12:35:24 2010 +0000 @@ -14,6 +14,8 @@ fis_seacat = SeaCat fis_currentmeter = Current Meter fis_icestations = Ice Station Report +fis_nauthis = Nauthis +fis_contis=Contis meshid= Mesh fis = Data set @@ -24,6 +26,7 @@ horizontalProfileCross = Horizontales Schnittprofil horizontalCrossSection = Horizontal cross-section verticalcrosssection = Vertical cross-section +layer = Layer featureid = Station mesh_coordinate = Geographic position (e.g. 56n30 6e20) mesh_linestring = Line (WKT) @@ -35,6 +38,7 @@ maxdepthid = Highest Layer parameterid = Parameter yearid = Year +layerid = Layer timeinterval = Time period minvalue = from maxvalue = to
--- a/gnv-artifacts/src/main/resources/lang/artifactMessages_de.properties Fri Mar 05 09:13:17 2010 +0000 +++ b/gnv-artifacts/src/main/resources/lang/artifactMessages_de.properties Fri Mar 05 12:35:24 2010 +0000 @@ -14,6 +14,8 @@ fis_seacat = SeaCat fis_currentmeter = Strommesser fis_icestations = Eismeldungen +fis_nauthis = Nauthis +fis_contis=Contis fis = Fachinformationssystem product= Produkt @@ -23,6 +25,7 @@ horizontalProfileCross = Horizontales Schnittprofil horizontalCrossSection = Horizontalschnitt verticalcrosssection = Profilschnitt +layer = Layer featureid = Station meshid= Datengitter mesh_coordinate = Geographische Position (z.B. 56n30 6e20) @@ -35,6 +38,7 @@ maxdepthid = Obere Grenzschicht parameterid = Parameter yearid = Jahr +layerid = Layer timeinterval = Zeitfenster minvalue = von maxvalue = bis
--- a/gnv-artifacts/src/main/resources/lang/artifactMessages_de_DE.properties Fri Mar 05 09:13:17 2010 +0000 +++ b/gnv-artifacts/src/main/resources/lang/artifactMessages_de_DE.properties Fri Mar 05 12:35:24 2010 +0000 @@ -14,6 +14,8 @@ fis_seacat = SeaCat fis_currentmeter = Strommesser fis_icestations = Eismeldungen +fis_nauthis = Nauthis +fis_contis=Contis fis= Fachinformationssystem product= Produkt @@ -23,6 +25,7 @@ horizontalProfileCross = Horizontales Schnittprofil horizontalCrossSection = Horizontalschnitt verticalcrosssection = Profilschnitt +layer = Layer featureid = Station meshid= Datengitter mesh_coordinate = Geographische Position (z.B. 56n30 6e20) @@ -35,6 +38,7 @@ maxdepthid = Obere Grenzschicht parameterid = Parameter yearid = Jahr +layerid = Layer timeinterval = Zeitfenster minvalue = von maxvalue = bis
--- a/gnv-artifacts/src/main/resources/lang/artifactMessages_en.properties Fri Mar 05 09:13:17 2010 +0000 +++ b/gnv-artifacts/src/main/resources/lang/artifactMessages_en.properties Fri Mar 05 12:35:24 2010 +0000 @@ -14,6 +14,8 @@ fis_seacat = SeaCat fis_currentmeter = Current Meter fis_icestations = Ice Station Report +fis_nauthis = Nauthis +fis_contis=Contis meshid= Mesh fis = Data set @@ -24,6 +26,7 @@ horizontalProfileCross = Horizontales Schnittprofil horizontalCrossSection = Horizontal cross-section verticalcrosssection = Vertical cross-section +layer = Layer featureid = Station mesh_coordinate = Geographic position (e.g. 56n30 6e20) mesh_linestring = Line (WKT) @@ -35,6 +38,7 @@ maxdepthid = Highest Layer parameterid = Parameter yearid = Year +layerid = Layer timeinterval = Time period minvalue = from maxvalue = to