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 :

http://dive4elements.wald.intevation.org