Mercurial > dive4elements > gnv-client
comparison gnv-artifacts/src/main/java/de/intevation/gnv/state/layer/LayerOutputState.java @ 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 | 93978859fa9e |
children | 6eccb68a8b99 |
comparison
equal
deleted
inserted
replaced
648:7c67ff162e87 | 649:4fc97074eb90 |
---|---|
1 /** | 1 /** |
2 * | 2 * |
3 */ | 3 */ |
4 package de.intevation.gnv.state.layer; | 4 package de.intevation.gnv.state.layer; |
5 | 5 |
6 import java.io.File; | |
7 import java.io.IOException; | |
6 import java.io.OutputStream; | 8 import java.io.OutputStream; |
7 import java.util.Collection; | 9 import java.util.Collection; |
8 import java.util.Iterator; | 10 import java.util.Iterator; |
9 | 11 |
10 import org.apache.log4j.Logger; | 12 import org.apache.log4j.Logger; |
11 import org.w3c.dom.Document; | 13 import org.w3c.dom.Document; |
12 import org.w3c.dom.Node; | 14 import org.w3c.dom.Node; |
15 | |
16 import com.vividsolutions.jts.geom.Geometry; | |
17 import com.vividsolutions.jts.io.ParseException; | |
18 import com.vividsolutions.jts.io.WKTReader; | |
13 | 19 |
14 import de.intevation.artifactdatabase.Config; | 20 import de.intevation.artifactdatabase.Config; |
15 import de.intevation.artifactdatabase.XMLUtils; | 21 import de.intevation.artifactdatabase.XMLUtils; |
16 import de.intevation.artifacts.ArtifactNamespaceContext; | 22 import de.intevation.artifacts.ArtifactNamespaceContext; |
17 import de.intevation.artifacts.CallContext; | 23 import de.intevation.artifacts.CallContext; |
24 import de.intevation.gnv.artifacts.context.GNVArtifactContext; | |
18 import de.intevation.gnv.geobackend.base.Result; | 25 import de.intevation.gnv.geobackend.base.Result; |
26 import de.intevation.gnv.geobackend.base.query.QueryExecutor; | |
27 import de.intevation.gnv.geobackend.base.query.QueryExecutorFactory; | |
28 import de.intevation.gnv.geobackend.base.query.exception.QueryException; | |
19 import de.intevation.gnv.state.InputData; | 29 import de.intevation.gnv.state.InputData; |
20 import de.intevation.gnv.state.OutputStateBase; | 30 import de.intevation.gnv.state.OutputStateBase; |
21 import de.intevation.gnv.state.exception.StateException; | 31 import de.intevation.gnv.state.exception.StateException; |
32 import de.intevation.gnv.utils.FileUtils; | |
33 import de.intevation.gnv.utils.MapfileGenerator; | |
34 import de.intevation.gnv.utils.ShapeFileWriter; | |
22 | 35 |
23 /** | 36 /** |
24 * @author Tim Englich <tim.englich@intevation.de> | 37 * @author Tim Englich <tim.englich@intevation.de> |
25 * | 38 * |
26 */ | 39 */ |
38 | 51 |
39 /** | 52 /** |
40 * The ID for the Query fetching the Layer from the DB | 53 * The ID for the Query fetching the Layer from the DB |
41 */ | 54 */ |
42 private String dataQueryID = null; | 55 private String dataQueryID = null; |
56 | |
57 /** | |
58 * The ID for the Query fetching the Geometry from the DB | |
59 * which should be used to Clip the Layerdata | |
60 */ | |
61 private String geometryQueryID = null; | |
62 | |
63 /** | |
64 * The ID for the Value which will hold the Geometrie-Value | |
65 */ | |
66 private String geometryID = null; | |
67 | |
68 private Boolean shapeFileLock = new Boolean(true); | |
69 | |
70 private String shapeFilePath; | |
71 | |
72 public static final String SHAPEFILE_NAME = "data.shp"; | |
73 | |
43 /** | 74 /** |
44 * Constructor | 75 * Constructor |
45 */ | 76 */ |
46 public LayerOutputState() { | 77 public LayerOutputState() { |
47 super(); | 78 super(); |
62 if (outputMode.equalsIgnoreCase("wms")) { | 93 if (outputMode.equalsIgnoreCase("wms")) { |
63 Collection<Result> data = this.fetchData(); | 94 Collection<Result> data = this.fetchData(); |
64 // TODO USE ME | 95 // TODO USE ME |
65 }else if (outputMode.equalsIgnoreCase("zip")){ | 96 }else if (outputMode.equalsIgnoreCase("zip")){ |
66 Collection<Result> data = this.fetchData(); | 97 Collection<Result> data = this.fetchData(); |
67 // TODO USE ME | 98 this.writeZip(uuid, callContext, outputStream, data); |
68 } | 99 } |
69 } | 100 } |
70 | 101 |
71 | 102 |
103 /** | |
104 * Fetches the Data from the Databasebackend | |
105 * @return | |
106 */ | |
72 protected Collection<Result> fetchData(){ | 107 protected Collection<Result> fetchData(){ |
73 log.debug("LayerOutputState.fetchData"); | 108 log.debug("LayerOutputState.fetchData"); |
74 // TODO PUT ALL in CACHE | 109 // TODO PUT ALL in CACHE |
75 Collection<Result> result = this.getData(this.queryID); | 110 Collection<Result> result = this.getData(this.queryID); |
76 Collection<Result> data = null; | 111 Collection<Result> data = null; |
112 String geometryWKT = null; | |
77 if (result != null){ | 113 if (result != null){ |
114 QueryExecutor queryExecutor = QueryExecutorFactory.getInstance() | |
115 .getQueryExecutor(); | |
78 Iterator<Result> it = result.iterator(); | 116 Iterator<Result> it = result.iterator(); |
79 String table = null; | 117 String[] queryValues = null; |
80 String where = null; | |
81 if (it.hasNext()){ | 118 if (it.hasNext()){ |
82 Result resultValue = it.next(); | 119 Result resultValue = it.next(); |
83 table = resultValue.getString(0); | 120 String table = resultValue.getString(0); |
84 where = resultValue.getString(1); | 121 String where = resultValue.getString(1); |
85 // TODO ADD SpatialFilter if Geometry is available | 122 if (this.geometryID != null){ |
123 InputData geometryInputData = | |
124 this.inputData.get(this.geometryID); | |
125 if (geometryInputData != null){ | |
126 | |
127 try { | |
128 Collection<Result> geometryData = queryExecutor | |
129 .executeQuery(this.geometryQueryID, | |
130 new String[]{geometryInputData.getValue()}); | |
131 Iterator<Result> git = geometryData.iterator(); | |
132 if (git.hasNext()){ | |
133 Result geometryValue = git.next(); | |
134 geometryWKT = geometryValue.getString(0); | |
135 } | |
136 } catch (QueryException e) { | |
137 log.error(e,e); | |
138 // TODO: what should happen?? | |
139 } | |
140 queryValues = new String[]{table, | |
141 where, | |
142 geometryWKT}; | |
143 }else{ | |
144 // TODO: Look into the presetting for an WKT | |
145 queryValues = new String[]{table,where}; | |
146 } | |
147 }else{ | |
148 // TODO: Look into the presetting for an WKT | |
149 queryValues = new String[]{table,where}; | |
150 | |
151 } | |
86 } | 152 } |
87 | 153 |
88 data = null; // TODO Fetch the Data for the Layer and Trim the Geometries | 154 try { |
89 // using the Geometry if on is available. | 155 data = queryExecutor.executeQuery(dataQueryID, |
156 queryValues); | |
157 if (data != null && geometryWKT != null){ | |
158 WKTReader wktReader = new WKTReader(); | |
159 Geometry border = wktReader.read(geometryWKT); | |
160 | |
161 Iterator<Result> dataIt = data.iterator(); | |
162 while (dataIt.hasNext()){ | |
163 // Trim the Geometries using the | |
164 // Geometry if on is available. | |
165 Result current = dataIt.next(); | |
166 String currentWKT = current.getString(0); | |
167 Geometry currentGeometry = null; | |
168 try { | |
169 currentGeometry = wktReader.read(currentWKT); | |
170 } catch (Exception e) { | |
171 log.error("Error parsing Geometry "+ currentWKT); | |
172 log.error(e,e); | |
173 } | |
174 | |
175 if (currentGeometry != null){ | |
176 Geometry newGeometry = currentGeometry.intersection(border); | |
177 current.addColumnValue(0, newGeometry.toText()); | |
178 } | |
179 } | |
180 } | |
181 } catch (QueryException e) { | |
182 log.error(e,e); | |
183 } catch (ParseException e){ | |
184 log.error(e,e); | |
185 } | |
90 } | 186 } |
91 return data; | 187 return data; |
92 } | 188 } |
93 | 189 |
94 @Override | 190 @Override |
95 public void setup(Node configuration) { | 191 public void setup(Node configuration) { |
96 log.debug("LayerOutputState.setup"); | 192 log.debug("LayerOutputState.setup"); |
97 super.setup(configuration); | 193 super.setup(configuration); |
98 this.dataQueryID = Config.getStringXPath(configuration,"queryID-layerdata"); | 194 this.dataQueryID = Config.getStringXPath(configuration, |
99 } | 195 "queryID-layerdata"); |
196 this.geometryID = Config.getStringXPath(configuration, | |
197 "inputvalue-geometry"); | |
198 this.geometryQueryID = Config.getStringXPath(configuration, | |
199 "queryID-geometry"); | |
200 } | |
201 | |
202 protected String writeToShapeFile( | |
203 String uuid, | |
204 Collection<Result> data, | |
205 CallContext callContext | |
206 ) { | |
207 File baseDir = shapefileDirectory(callContext); | |
208 | |
209 File shapeDir = new File(baseDir, uuid); | |
210 boolean success = false; | |
211 boolean createdDir = false; | |
212 | |
213 try { | |
214 synchronized (shapeFileLock) { | |
215 int count = 0; | |
216 while (shapeDir.exists()) { | |
217 shapeDir = new File(baseDir, uuid + "-" + count); | |
218 ++count; | |
219 } | |
220 | |
221 if (!shapeDir.mkdirs()) { | |
222 log.error("cannot create directory '" | |
223 + shapeDir.getAbsolutePath() + "'"); | |
224 return null; | |
225 } | |
226 createdDir = true; | |
227 } | |
228 | |
229 File shapeFile = new File(shapeDir, SHAPEFILE_NAME); | |
230 if (!ShapeFileWriter.writeDataToFile(shapeFile, "data", data)){ | |
231 log.error("writing data into shapefile failed"); | |
232 return null; | |
233 } | |
234 | |
235 shapeFilePath = shapeDir.getAbsolutePath(); | |
236 success = true; | |
237 | |
238 callContext.afterCall(CallContext.STORE); | |
239 | |
240 return shapeFilePath; | |
241 } | |
242 finally { | |
243 if (!success && createdDir) { | |
244 FileUtils.deleteRecursive(shapeDir); | |
245 } | |
246 } | |
247 } | |
248 | |
249 protected void writeZip( | |
250 String uuid, | |
251 CallContext callContext, | |
252 OutputStream output, | |
253 Collection<Result> data | |
254 ) | |
255 throws StateException | |
256 { | |
257 try { | |
258 String p = getShapeFilePath(); | |
259 if (p != null) { | |
260 File dir = new File(p); | |
261 if (dir.isDirectory()) { | |
262 FileUtils.createZipArchive(dir, output); | |
263 } | |
264 } | |
265 else { | |
266 | |
267 if ((p = writeToShapeFile(uuid, data, callContext)) != null) { | |
268 FileUtils.createZipArchive(new File(p), output); | |
269 } | |
270 } | |
271 } | |
272 catch (IOException ioe) { | |
273 log.error(ioe.getLocalizedMessage(), ioe); | |
274 } | |
275 } | |
276 | |
277 public String getShapeFilePath() { | |
278 synchronized (shapeFileLock) { | |
279 return shapeFilePath; | |
280 } | |
281 } | |
282 | |
283 private static File shapefileDirectory(CallContext callContext) { | |
284 // TODO: Refactoring nessessary it should be used only one Shapefilepath | |
285 // for alle Modes. Code was taken from HorizontalCrossSectionMeshOutputState | |
286 GNVArtifactContext context = | |
287 (GNVArtifactContext)callContext.globalContext(); | |
288 File dir = (File)context.get( | |
289 GNVArtifactContext.HORIZONTAL_CROSS_SECTION_RESULT_SHAPEFILE_PATH_KEY); | |
290 return dir != null | |
291 ? dir | |
292 : GNVArtifactContext.DEFAULT_HORIZONTAL_CROSS_SECTION_PROFILE_SHAPEFILE_PATH; | |
293 } | |
294 | |
295 /** | |
296 * @see de.intevation.gnv.state.StateBase#endOfLife(java.lang.Object) | |
297 */ | |
298 @Override | |
299 public void endOfLife(Object globalContext) { | |
300 super.endOfLife(globalContext); | |
301 | |
302 // do it in background | |
303 new Thread() { | |
304 public void run() { | |
305 // TODO: Do the un-publishing WMS stuff. | |
306 String path = resetShapeFilePath(); | |
307 | |
308 if (path == null) { | |
309 return; | |
310 } | |
311 | |
312 File dir = new File(path); | |
313 | |
314 for (int i = 0; i < 10; ++i) { | |
315 if (!dir.exists() || FileUtils.deleteRecursive(dir)) { | |
316 MapfileGenerator.getInstance().update(); | |
317 return; | |
318 } | |
319 | |
320 try { | |
321 Thread.sleep(10000L); | |
322 } | |
323 catch (InterruptedException ie) { | |
324 } | |
325 } | |
326 | |
327 log.error("failed to remove directory '" + path + "'"); | |
328 } // run | |
329 }.start(); | |
330 } | |
331 | |
332 public String resetShapeFilePath() { | |
333 synchronized (shapeFileLock) { | |
334 String path = shapeFilePath; | |
335 shapeFilePath = null; | |
336 return path; | |
337 } | |
338 } | |
339 | |
100 | 340 |
101 } | 341 } |