Mercurial > dive4elements > river
comparison flys-artifacts/src/main/java/de/intevation/flys/utils/MapfileGenerator.java @ 3818:dc18457b1cef
merged flys-artifacts/pre2.7-2012-03-16
author | Thomas Arendsen Hein <thomas@intevation.de> |
---|---|
date | Fri, 28 Sep 2012 12:14:59 +0200 |
parents | a5f87f8dbe57 |
children | 27cc95e65f18 |
comparison
equal
deleted
inserted
replaced
2456:60ab1054069d | 3818:dc18457b1cef |
---|---|
1 package de.intevation.flys.utils; | |
2 | |
3 import java.io.File; | |
4 import java.io.FilenameFilter; | |
5 import java.io.FileNotFoundException; | |
6 import java.io.FileWriter; | |
7 import java.io.IOException; | |
8 import java.io.Writer; | |
9 | |
10 import java.util.ArrayList; | |
11 import java.util.Date; | |
12 import java.util.List; | |
13 | |
14 import org.apache.log4j.Logger; | |
15 | |
16 import org.apache.velocity.Template; | |
17 import org.apache.velocity.VelocityContext; | |
18 import org.apache.velocity.app.VelocityEngine; | |
19 | |
20 import de.intevation.artifacts.common.utils.Config; | |
21 | |
22 import de.intevation.flys.artifacts.FLYSArtifact; | |
23 import de.intevation.flys.artifacts.model.LayerInfo; | |
24 import de.intevation.flys.artifacts.model.WMSLayerFacet; | |
25 import de.intevation.flys.artifacts.model.WMSDBLayerFacet; | |
26 | |
27 /** | |
28 * This class iterates over a bunch of directories, searches for meta | |
29 * information coresponding to shapefiles and creates a mapfile which is used by | |
30 * a <i>MapServer</i>. | |
31 * | |
32 * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a> | |
33 */ | |
34 public class MapfileGenerator | |
35 extends Thread | |
36 { | |
37 public static final String WSPLGEN_RESULT_SHAPE = "wsplgen.shp"; | |
38 public static final String WSPLGEN_LINES_SHAPE = "barrier_lines.shp"; | |
39 public static final String WSPLGEN_POLYGONS_SHAPE = "barrier_polygons.shp"; | |
40 | |
41 public static final String SHP_LAYER_TEMPLATE = "shapefile_layer.vm"; | |
42 public static final String DB_LAYER_TEMPLATE = "db_layer.vm"; | |
43 | |
44 public static final String MS_WSPLGEN_PREFIX = "wsplgen-"; | |
45 public static final String MS_BARRIERS_PREFIX = "barriers-"; | |
46 public static final String MS_LINE_PREFIX = "lines-"; | |
47 public static final String MS_POLYGONS_PREFIX = "polygons-"; | |
48 public static final String MS_LAYER_PREFIX = "ms_layer-"; | |
49 | |
50 protected static final long SLEEPTIME = 10 * 1000L; // 10 seconds | |
51 | |
52 private static Logger logger = Logger.getLogger(MapfileGenerator.class); | |
53 | |
54 private static MapfileGenerator instance; | |
55 | |
56 private File mapfile; | |
57 private File shapefileDirectory; | |
58 | |
59 private String mapServerUrl; | |
60 private String templatePath; | |
61 private String velocityLogfile; | |
62 | |
63 private VelocityEngine velocityEngine; | |
64 private boolean lock[]; | |
65 | |
66 | |
67 | |
68 private MapfileGenerator() { | |
69 lock = new boolean[1]; | |
70 } | |
71 | |
72 | |
73 /** | |
74 * A main method which can be used to create a mapfile without a running | |
75 * artifact server.<br> | |
76 * <b>NOTE:</b> This method is not implemented yet! | |
77 * | |
78 * @param args Arguments. | |
79 */ | |
80 public static void main(String[] args) { | |
81 throw new Error("MapfileGenerator.main() is CURRENTLY NOT IMPLEMENTED!"); | |
82 } | |
83 | |
84 | |
85 /** | |
86 * Returns the instance of this generator. | |
87 * | |
88 * @return the instance. | |
89 */ | |
90 public static synchronized MapfileGenerator getInstance() { | |
91 if (instance == null) { | |
92 instance = new MapfileGenerator(); | |
93 instance.setDaemon(true); | |
94 instance.start(); | |
95 } | |
96 | |
97 return instance; | |
98 } | |
99 | |
100 | |
101 /** | |
102 * Triggers the mapfile generation process. | |
103 */ | |
104 public void update() { | |
105 synchronized (lock) { | |
106 logger.debug("update"); | |
107 lock[0] = true; | |
108 lock.notify(); | |
109 } | |
110 } | |
111 | |
112 | |
113 /** | |
114 * Thread to generate a mapfile. | |
115 */ | |
116 @Override | |
117 public void run() { | |
118 logger.debug("Start MapfileGenerator thread..."); | |
119 try { | |
120 for (;;) { | |
121 synchronized (lock) { | |
122 while (!lock[0]) { | |
123 lock.wait(SLEEPTIME); | |
124 } | |
125 lock[0] = false; | |
126 } | |
127 | |
128 logger.debug("Start sync process now..."); | |
129 generate(); | |
130 } | |
131 } | |
132 catch (InterruptedException ie) { | |
133 logger.debug("MapfileGenerator thread got an interrupt."); | |
134 } | |
135 catch (FileNotFoundException fnfe) { | |
136 logger.debug("Error while mapfile creation: " + fnfe.getMessage()); | |
137 } | |
138 catch (IOException ioe) { | |
139 logger.error(ioe, ioe); | |
140 } | |
141 finally { | |
142 logger.debug("THREAD END"); | |
143 } | |
144 } | |
145 | |
146 /** | |
147 * Method to check the existance of a template file. | |
148 * | |
149 * @param templateID The name of a template. | |
150 * @return true, of the template exists - otherwise false. | |
151 */ | |
152 public boolean templateExists(String templateID){ | |
153 Template template = getTemplateByName(templateID); | |
154 return template != null; | |
155 } | |
156 | |
157 | |
158 /** | |
159 * Method which starts searching for meta information file and mapfile | |
160 * generation. | |
161 */ | |
162 protected void generate() | |
163 throws FileNotFoundException, IOException | |
164 { | |
165 File[] userDirs = getUserDirs(); | |
166 | |
167 List<String> layers = parseLayers(userDirs); | |
168 | |
169 logger.info("Found " + layers.size() + " layers for user mapfile."); | |
170 | |
171 writeMapfile(layers); | |
172 } | |
173 | |
174 | |
175 /** | |
176 * Returns the VelocityEngine used for the template mechanism. | |
177 * | |
178 * @return the velocity engine. | |
179 */ | |
180 protected VelocityEngine getVelocityEngine() { | |
181 if (velocityEngine == null) { | |
182 velocityEngine = new VelocityEngine(); | |
183 try { | |
184 setupVelocity(velocityEngine); | |
185 } | |
186 catch (Exception e) { | |
187 logger.error(e, e); | |
188 return null; | |
189 } | |
190 } | |
191 return velocityEngine; | |
192 } | |
193 | |
194 | |
195 /** | |
196 * Initialize velocity. | |
197 * | |
198 * @param engine Velocity engine. | |
199 * @throws Exception if an error occured while initializing velocity. | |
200 */ | |
201 protected void setupVelocity(VelocityEngine engine) | |
202 throws Exception | |
203 { | |
204 engine.setProperty( | |
205 "input.encoding", | |
206 "UTF-8"); | |
207 | |
208 engine.setProperty( | |
209 VelocityEngine.RUNTIME_LOG, | |
210 FLYSUtils.getXPathString(FLYSUtils.XPATH_VELOCITY_LOGFILE)); | |
211 | |
212 engine.setProperty( | |
213 "resource.loader", | |
214 "file"); | |
215 | |
216 engine.setProperty( | |
217 "file.resource.loader.path", | |
218 FLYSUtils.getXPathString(FLYSUtils.XPATH_MAPSERVER_TEMPLATE_PATH)); | |
219 | |
220 engine.init(); | |
221 } | |
222 | |
223 | |
224 protected VelocityContext getVelocityContext() { | |
225 VelocityContext context = new VelocityContext(); | |
226 | |
227 try { | |
228 context.put("MAPSERVERURL", | |
229 FLYSUtils.getXPathString(FLYSUtils.XPATH_MAPSERVER_URL)); | |
230 context.put("SHAPEFILEPATH", | |
231 getShapefileBaseDir().getCanonicalPath()); | |
232 context.put("CONFIGDIR", | |
233 Config.getConfigDirectory().getCanonicalPath()); | |
234 } | |
235 catch (FileNotFoundException fnfe) { | |
236 // this is bad | |
237 } | |
238 catch (IOException ioe) { | |
239 // this is also bad | |
240 } | |
241 | |
242 return context; | |
243 } | |
244 | |
245 | |
246 /** | |
247 * Returns a template specified by <i>model</i>. | |
248 * | |
249 * @param model The name of the template. | |
250 * @return a template. | |
251 */ | |
252 protected Template getTemplateByName(String model) { | |
253 if (model.indexOf(".vm") < 0) { | |
254 model = model.concat(".vm"); | |
255 } | |
256 | |
257 try { | |
258 VelocityEngine engine = getVelocityEngine(); | |
259 if (engine == null) { | |
260 logger.error("Error while fetching VelocityEngine."); | |
261 return null; | |
262 } | |
263 | |
264 return engine.getTemplate(model); | |
265 } | |
266 catch (Exception e) { | |
267 logger.warn(e, e); | |
268 } | |
269 | |
270 return null; | |
271 } | |
272 | |
273 | |
274 /** | |
275 * Returns the mapfile template. | |
276 * | |
277 * @return the mapfile template. | |
278 * @throws Exception if an error occured while reading the configuration. | |
279 */ | |
280 protected Template getMapfileTemplate() | |
281 throws Exception | |
282 { | |
283 String mapfileName = FLYSUtils.getXPathString( | |
284 FLYSUtils.XPATH_MAPFILE_TEMPLATE); | |
285 | |
286 return getTemplateByName(mapfileName); | |
287 } | |
288 | |
289 | |
290 /** | |
291 * Returns the base directory storing the shapefiles. | |
292 * | |
293 * @return the shapefile base directory. | |
294 * | |
295 * @throws FileNotFoundException if no shapefile path is found or | |
296 * configured. | |
297 */ | |
298 public File getShapefileBaseDir() | |
299 throws FileNotFoundException, IOException | |
300 { | |
301 if (shapefileDirectory == null) { | |
302 String path = FLYSUtils.getXPathString( | |
303 FLYSUtils.XPATH_SHAPEFILE_DIR); | |
304 | |
305 if (path != null) { | |
306 shapefileDirectory = new File(path); | |
307 } | |
308 | |
309 if (shapefileDirectory == null) { | |
310 throw new FileNotFoundException("No shapefile directory given"); | |
311 } | |
312 | |
313 if (!shapefileDirectory.exists()) { | |
314 shapefileDirectory.createNewFile(); | |
315 } | |
316 } | |
317 | |
318 return shapefileDirectory; | |
319 } | |
320 | |
321 | |
322 protected File[] getUserDirs() | |
323 throws FileNotFoundException, IOException | |
324 { | |
325 File baseDir = getShapefileBaseDir(); | |
326 File[] artifactDirs = baseDir.listFiles(); | |
327 | |
328 // TODO ONLY RETURN DIRECTORIES OF THE SPECIFIED USER | |
329 | |
330 return artifactDirs; | |
331 } | |
332 | |
333 | |
334 | |
335 protected List<String> parseLayers(File[] dirs) { | |
336 List<String> layers = new ArrayList<String>(); | |
337 | |
338 for (File dir: dirs) { | |
339 File[] layerFiles = dir.listFiles(new FilenameFilter() { | |
340 @Override | |
341 public boolean accept(File directory, String name) { | |
342 return name.startsWith(MS_LAYER_PREFIX); | |
343 } | |
344 }); | |
345 | |
346 for (File layer: layerFiles) { | |
347 try { | |
348 layers.add(layer.getCanonicalPath()); | |
349 } | |
350 catch (IOException ioe) { | |
351 logger.warn(ioe, ioe); | |
352 } | |
353 } | |
354 } | |
355 | |
356 return layers; | |
357 } | |
358 | |
359 | |
360 /** | |
361 * Creates a layer file used for Mapserver's mapfile which represents the | |
362 * floodmap. | |
363 * | |
364 * @param flys The FLYSArtifact that owns <i>wms</i>. | |
365 * @param wms The WMSLayerFacet that contains information for the layer. | |
366 */ | |
367 public void createUeskLayer(FLYSArtifact flys, WMSLayerFacet wms) | |
368 throws FileNotFoundException, IOException | |
369 { | |
370 logger.debug("createUeskLayer"); | |
371 | |
372 LayerInfo layerinfo = new LayerInfo(); | |
373 layerinfo.setName(MS_WSPLGEN_PREFIX + flys.identifier()); | |
374 layerinfo.setType("POLYGON"); | |
375 layerinfo.setDirectory(flys.identifier()); | |
376 layerinfo.setData(WSPLGEN_RESULT_SHAPE); | |
377 layerinfo.setTitle("I18N_WSPLGEN_RESULT"); | |
378 | |
379 String name = MS_LAYER_PREFIX + wms.getName(); | |
380 | |
381 Template template = getTemplateByName(SHP_LAYER_TEMPLATE); | |
382 if (template == null) { | |
383 logger.warn("Template '" + SHP_LAYER_TEMPLATE + "' found."); | |
384 return; | |
385 } | |
386 | |
387 try { | |
388 File dir = new File(getShapefileBaseDir(), flys.identifier()); | |
389 writeLayer(layerinfo, dir, name, template); | |
390 } | |
391 catch (FileNotFoundException fnfe) { | |
392 logger.error(fnfe, fnfe); | |
393 logger.warn("Unable to write layer: " + name); | |
394 } | |
395 } | |
396 | |
397 | |
398 /** | |
399 * Creates a layer file used for Mapserver's mapfile which represents the | |
400 * user defined barriers. | |
401 * | |
402 * @param flys The FLYSArtifact that owns <i>wms</i>. | |
403 * @param wms The WMSLayerFacet that contains information for the layer. | |
404 */ | |
405 public void createBarriersLayer(FLYSArtifact flys, WMSLayerFacet wms) | |
406 throws FileNotFoundException, IOException | |
407 { | |
408 logger.debug("createBarriersLayer"); | |
409 | |
410 String uuid = flys.identifier(); | |
411 File dir = new File(getShapefileBaseDir(), uuid); | |
412 | |
413 createBarriersLineLayer(flys, wms); | |
414 createBarriersPolygonLayer(flys, wms); | |
415 } | |
416 | |
417 | |
418 protected void createBarriersLineLayer( | |
419 FLYSArtifact flys, | |
420 WMSLayerFacet wms | |
421 ) | |
422 throws FileNotFoundException, IOException | |
423 { | |
424 String uuid = flys.identifier(); | |
425 String group = MS_BARRIERS_PREFIX + uuid; | |
426 String groupTitle = "I18N_BARRIERS_TITLE"; | |
427 | |
428 File dir = new File(getShapefileBaseDir(), uuid); | |
429 File test = new File(dir, WSPLGEN_LINES_SHAPE); | |
430 | |
431 if (!test.exists() || !test.canRead()) { | |
432 logger.debug("No barrier line layer existing."); | |
433 return; | |
434 } | |
435 | |
436 LayerInfo lineInfo = new LayerInfo(); | |
437 lineInfo.setName(MS_LINE_PREFIX + uuid); | |
438 lineInfo.setType("LINE"); | |
439 lineInfo.setDirectory(uuid); | |
440 lineInfo.setData(WSPLGEN_LINES_SHAPE); | |
441 lineInfo.setTitle("I18N_LINE_SHAPE"); | |
442 lineInfo.setGroup(group); | |
443 lineInfo.setGroupTitle(groupTitle); | |
444 | |
445 String nameLines = MS_LAYER_PREFIX + wms.getName() + "-lines"; | |
446 | |
447 Template tpl = getTemplateByName(SHP_LAYER_TEMPLATE); | |
448 if (tpl == null) { | |
449 logger.warn("Template '" + SHP_LAYER_TEMPLATE + "' found."); | |
450 return; | |
451 } | |
452 | |
453 try { | |
454 writeLayer(lineInfo, dir, nameLines, tpl); | |
455 } | |
456 catch (FileNotFoundException fnfe) { | |
457 logger.error(fnfe, fnfe); | |
458 logger.warn("Unable to write layer: " + nameLines); | |
459 } | |
460 } | |
461 | |
462 | |
463 protected void createBarriersPolygonLayer( | |
464 FLYSArtifact flys, | |
465 WMSLayerFacet wms | |
466 ) | |
467 throws FileNotFoundException, IOException | |
468 { | |
469 String uuid = flys.identifier(); | |
470 String group = uuid + MS_BARRIERS_PREFIX; | |
471 String groupTitle = "I18N_BARRIERS_TITLE"; | |
472 | |
473 File dir = new File(getShapefileBaseDir(), uuid); | |
474 File test = new File(dir, WSPLGEN_POLYGONS_SHAPE); | |
475 | |
476 if (!test.exists() || !test.canRead()) { | |
477 logger.debug("No barrier line layer existing."); | |
478 return; | |
479 } | |
480 | |
481 LayerInfo polygonInfo = new LayerInfo(); | |
482 polygonInfo.setName(MS_POLYGONS_PREFIX + uuid); | |
483 polygonInfo.setType("POLYGON"); | |
484 polygonInfo.setDirectory(uuid); | |
485 polygonInfo.setData(WSPLGEN_POLYGONS_SHAPE); | |
486 polygonInfo.setTitle("I18N_POLYGON_SHAPE"); | |
487 polygonInfo.setGroup(group); | |
488 polygonInfo.setGroupTitle(groupTitle); | |
489 | |
490 String namePolygons = MS_LAYER_PREFIX + wms.getName() + "-polygons"; | |
491 | |
492 Template tpl = getTemplateByName(SHP_LAYER_TEMPLATE); | |
493 if (tpl == null) { | |
494 logger.warn("Template '" + SHP_LAYER_TEMPLATE + "' found."); | |
495 return; | |
496 } | |
497 | |
498 try { | |
499 writeLayer(polygonInfo, dir, namePolygons, tpl); | |
500 } | |
501 catch (FileNotFoundException fnfe) { | |
502 logger.error(fnfe, fnfe); | |
503 logger.warn("Unable to write layer: " + namePolygons); | |
504 } | |
505 } | |
506 | |
507 | |
508 /** | |
509 * Creates a layer file used for Mapserver's mapfile which represents | |
510 * geometries from database. | |
511 * | |
512 * @param flys The FLYSArtifact that owns <i>wms</i>. | |
513 * @param wms The WMSLayerFacet that contains information for the layer. | |
514 */ | |
515 public void createDatabaseLayer( | |
516 FLYSArtifact flys, | |
517 WMSDBLayerFacet wms, | |
518 String style | |
519 ) | |
520 throws FileNotFoundException, IOException | |
521 { | |
522 logger.debug("createDatabaseLayer"); | |
523 | |
524 LayerInfo layerinfo = new LayerInfo(); | |
525 layerinfo.setName(wms.getName() + "-" + flys.identifier()); | |
526 layerinfo.setType(wms.getGeometryType()); | |
527 layerinfo.setFilter(wms.getFilter()); | |
528 layerinfo.setData(wms.getData()); | |
529 layerinfo.setTitle(wms.getDescription()); | |
530 layerinfo.setStyle(style); | |
531 layerinfo.setExtent(GeometryUtils.jtsBoundsToOLBounds(wms.getExtent())); | |
532 layerinfo.setConnection(wms.getConnection()); | |
533 layerinfo.setConnectionType(wms.getConnectionType()); | |
534 layerinfo.setLabelItem(wms.getLabelItem()); | |
535 | |
536 String name = MS_LAYER_PREFIX + wms.getName(); | |
537 | |
538 Template template = getTemplateByName(DB_LAYER_TEMPLATE); | |
539 if (template == null) { | |
540 logger.warn("Template '" + DB_LAYER_TEMPLATE + "' found."); | |
541 return; | |
542 } | |
543 | |
544 try { | |
545 File dir = new File(getShapefileBaseDir(), flys.identifier()); | |
546 writeLayer(layerinfo, dir, name, template); | |
547 } | |
548 catch (FileNotFoundException fnfe) { | |
549 logger.error(fnfe, fnfe); | |
550 logger.warn("Unable to write layer: " + name); | |
551 } | |
552 } | |
553 | |
554 | |
555 /** | |
556 * Creates a layer snippet which might be included in the mapfile. | |
557 * | |
558 * @param layerinfo A LayerInfo object that contains all necessary | |
559 * information to build a Mapserver LAYER section. | |
560 * @param dir The base dir for the LAYER snippet. | |
561 * @param filename The name of the file that is written. | |
562 * @param tpl The Velocity template which is used to create the LAYER | |
563 * section. | |
564 */ | |
565 protected void writeLayer( | |
566 LayerInfo layerinfo, | |
567 File dir, | |
568 String filename, | |
569 Template tpl | |
570 ) | |
571 throws FileNotFoundException | |
572 { | |
573 if (logger.isDebugEnabled()) { | |
574 logger.debug("Write layer for:"); | |
575 logger.debug(" directory: " + dir.getName()); | |
576 logger.debug(" name: " + filename); | |
577 } | |
578 | |
579 File layer = new File(dir, filename); | |
580 Writer writer = null; | |
581 | |
582 try { | |
583 writer = new FileWriter(layer); | |
584 | |
585 VelocityContext context = getVelocityContext(); | |
586 context.put("LAYER", layerinfo); | |
587 | |
588 tpl.merge(context, writer); | |
589 } | |
590 catch (FileNotFoundException fnfe) { | |
591 logger.error(fnfe, fnfe); | |
592 } | |
593 catch (IOException ioe) { | |
594 logger.error(ioe, ioe); | |
595 } | |
596 catch (Exception e) { | |
597 logger.error(e, e); | |
598 } | |
599 finally { | |
600 try { | |
601 if (writer != null) { | |
602 writer.close(); | |
603 } | |
604 } | |
605 catch (IOException ioe) { | |
606 logger.debug(ioe, ioe); | |
607 } | |
608 } | |
609 } | |
610 | |
611 | |
612 /** | |
613 * Creates a mapfile with the layer information stored in <i>layers</i>. | |
614 * | |
615 * @param layers Layer information. | |
616 */ | |
617 protected void writeMapfile(List<String> layers) { | |
618 String tmpMapName = "mapfile" + new Date().getTime(); | |
619 | |
620 File mapfile = new File( | |
621 FLYSUtils.getXPathString(FLYSUtils.XPATH_MAPFILE_PATH)); | |
622 | |
623 File tmp = null; | |
624 Writer writer = null; | |
625 | |
626 try { | |
627 tmp = new File(mapfile.getParent(), tmpMapName); | |
628 tmp.createNewFile(); | |
629 | |
630 writer = new FileWriter(tmp); | |
631 | |
632 VelocityContext context = getVelocityContext(); | |
633 context.put("LAYERS", layers); | |
634 | |
635 Template mapTemplate = getMapfileTemplate(); | |
636 if (mapTemplate == null) { | |
637 logger.warn("No mapfile template found."); | |
638 return; | |
639 } | |
640 | |
641 mapTemplate.merge(context, writer); | |
642 | |
643 // we need to create a temporary mapfile first und rename it into | |
644 // real mapfile because we don't run into race conditions on this | |
645 // way. (iw) | |
646 tmp.renameTo(mapfile); | |
647 } | |
648 catch (FileNotFoundException fnfe) { | |
649 logger.error(fnfe, fnfe); | |
650 } | |
651 catch (IOException ioe) { | |
652 logger.error(ioe, ioe); | |
653 } | |
654 catch (Exception e) { | |
655 logger.error(e, e); | |
656 } | |
657 finally { | |
658 try { | |
659 if (writer != null) { | |
660 writer.close(); | |
661 } | |
662 | |
663 if (tmp.exists()) { | |
664 tmp.delete(); | |
665 } | |
666 } | |
667 catch (IOException ioe) { | |
668 logger.debug(ioe, ioe); | |
669 } | |
670 } | |
671 } | |
672 } | |
673 // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 : |