comparison flys-artifacts/src/main/java/de/intevation/flys/utils/MapfileGenerator.java @ 3786:4adc35aa655c

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

http://dive4elements.wald.intevation.org