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