ingo@1129: package de.intevation.flys.utils;
ingo@1129: 
christian@3303: import de.intevation.artifacts.common.utils.Config;
christian@3303: import de.intevation.flys.artifacts.model.LayerInfo;
christian@3303: 
ingo@1129: import java.io.File;
ingo@1129: import java.io.FileNotFoundException;
ingo@1129: import java.io.FileWriter;
ingo@3302: import java.io.FilenameFilter;
ingo@1129: import java.io.IOException;
ingo@1129: import java.io.Writer;
ingo@1129: import java.util.ArrayList;
ingo@1129: import java.util.Date;
ingo@1129: import java.util.List;
ingo@1129: 
ingo@1129: import org.apache.log4j.Logger;
ingo@1129: import org.apache.velocity.Template;
ingo@1129: import org.apache.velocity.VelocityContext;
ingo@1129: import org.apache.velocity.app.VelocityEngine;
christian@4656: import org.apache.velocity.runtime.RuntimeConstants;
ingo@1129: 
ingo@1129: /**
ingo@1129:  * This class iterates over a bunch of directories, searches for meta
ingo@1129:  * information coresponding to shapefiles and creates a mapfile which is used by
ingo@1129:  * a <i>MapServer</i>.
ingo@1129:  *
ingo@1129:  * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a>
ingo@1129:  */
christian@4654: public abstract class MapfileGenerator
ingo@1129: {
ingo@1134:     public static final String WSPLGEN_RESULT_SHAPE   = "wsplgen.shp";
ingo@1134:     public static final String WSPLGEN_LINES_SHAPE    = "barrier_lines.shp";
ingo@1134:     public static final String WSPLGEN_POLYGONS_SHAPE = "barrier_polygons.shp";
raimund@2639:     public static final String WSPLGEN_USER_SHAPE     = "user-rgd.shp";
ingo@1134: 
raimund@2637:     public static final String WSPLGEN_LAYER_TEMPLATE = "wsplgen_layer.vm";
ingo@1775:     public static final String SHP_LAYER_TEMPLATE = "shapefile_layer.vm";
ingo@1792:     public static final String DB_LAYER_TEMPLATE  = "db_layer.vm";
christian@4648:     public static final String RIVERAXIS_LAYER_TEMPLATE = "riveraxis-layer.vm";
ingo@1775: 
raimund@2639:     public static final String MS_WSPLGEN_PREFIX   = "wsplgen-";
raimund@2639:     public static final String MS_BARRIERS_PREFIX  = "barriers-";
raimund@2639:     public static final String MS_LINE_PREFIX      = "lines-";
raimund@2639:     public static final String MS_POLYGONS_PREFIX  = "polygons-";
raimund@2639:     public static final String MS_LAYER_PREFIX     = "ms_layer-";
raimund@2639:     public static final String MS_USERSHAPE_PREFIX = "user-";
ingo@1129: 
ingo@1129:     private static Logger logger = Logger.getLogger(MapfileGenerator.class);
ingo@1129: 
ingo@1129:     private File shapefileDirectory;
ingo@1129: 
ingo@1129:     private VelocityEngine velocityEngine;
ingo@1129: 
ingo@1129: 
christian@4654:     protected MapfileGenerator() {
ingo@1129:     }
ingo@1129: 
ingo@1129: 
ingo@1129:     /**
ingo@1129:      * Method to check the existance of a template file.
ingo@1129:      *
ingo@1129:      * @param templateID The name of a template.
ingo@1129:      * @return true, of the template exists - otherwise false.
ingo@1129:      */
ingo@1129:     public boolean templateExists(String templateID){
ingo@1129:         Template template = getTemplateByName(templateID);
ingo@1129:         return template != null;
ingo@1129:     }
ingo@1129: 
ingo@1129: 
christian@4656:     public abstract void generate() throws Exception;
christian@4648: 
christian@4648: 
christian@4648:     /**
ingo@1129:      * Returns the VelocityEngine used for the template mechanism.
ingo@1129:      *
ingo@1129:      * @return the velocity engine.
ingo@1129:      */
ingo@1129:     protected VelocityEngine getVelocityEngine() {
ingo@1129:         if (velocityEngine == null) {
ingo@1129:             velocityEngine = new VelocityEngine();
ingo@1129:             try {
ingo@1129:                 setupVelocity(velocityEngine);
ingo@1129:             }
ingo@1129:             catch (Exception e) {
ingo@1129:                 logger.error(e, e);
ingo@1129:                 return null;
ingo@1129:             }
ingo@1129:         }
ingo@1129:         return velocityEngine;
ingo@1129:     }
ingo@1129: 
ingo@1129: 
ingo@1129:     /**
ingo@1129:      * Initialize velocity.
ingo@1129:      *
ingo@1129:      * @param engine Velocity engine.
ingo@1129:      * @throws Exception if an error occured while initializing velocity.
ingo@1129:      */
ingo@1129:     protected void setupVelocity(VelocityEngine engine)
ingo@1129:     throws Exception
ingo@1129:     {
ingo@1129:         engine.setProperty(
ingo@1129:             "input.encoding",
ingo@1129:             "UTF-8");
ingo@1129: 
ingo@1129:         engine.setProperty(
christian@4656:             RuntimeConstants.RUNTIME_LOG,
christian@4656:             getVelocityLogfile());
ingo@1129: 
ingo@1129:         engine.setProperty(
ingo@1129:             "resource.loader",
ingo@1129:             "file");
ingo@1129: 
ingo@1129:         engine.setProperty(
ingo@1129:             "file.resource.loader.path",
christian@4656:             getMapserverTemplatePath());
ingo@1129: 
ingo@1129:         engine.init();
ingo@1129:     }
ingo@1129: 
christian@4656:     protected abstract String getVelocityLogfile();
christian@4656: 
christian@4656:     protected abstract String getMapserverTemplatePath();
christian@4656: 
christian@4656:     protected abstract String getMapserverUrl();
ingo@1129: 
ingo@1792:     protected VelocityContext getVelocityContext() {
ingo@1792:         VelocityContext context = new VelocityContext();
ingo@1792: 
ingo@1792:         try {
ingo@1792:             context.put("MAPSERVERURL",
christian@4656:                 getMapserverUrl());
ingo@1792:             context.put("SHAPEFILEPATH",
ingo@1792:                 getShapefileBaseDir().getCanonicalPath());
ingo@1792:             context.put("CONFIGDIR",
ingo@1792:                 Config.getConfigDirectory().getCanonicalPath());
ingo@1792:         }
ingo@1792:         catch (FileNotFoundException fnfe) {
ingo@1792:             // this is bad
christian@4633:             logger.warn(fnfe, fnfe);
ingo@1792:         }
ingo@1792:         catch (IOException ioe) {
ingo@1792:             // this is also bad
christian@4633:             logger.warn(ioe, ioe);
ingo@1792:         }
ingo@1792: 
ingo@1792:         return context;
ingo@1792:     }
ingo@1792: 
ingo@1792: 
ingo@1129:     /**
ingo@1129:      * Returns a template specified by <i>model</i>.
ingo@1129:      *
ingo@1129:      * @param model The name of the template.
ingo@1129:      * @return a template.
ingo@1129:      */
ingo@1129:     protected Template getTemplateByName(String model) {
ingo@1129:         if (model.indexOf(".vm") < 0) {
ingo@1129:             model = model.concat(".vm");
ingo@1129:         }
ingo@1129: 
ingo@1129:         try {
ingo@1129:             VelocityEngine engine = getVelocityEngine();
ingo@1129:             if (engine == null) {
ingo@1129:                 logger.error("Error while fetching VelocityEngine.");
ingo@1129:                 return null;
ingo@1129:             }
ingo@1129: 
ingo@1129:             return engine.getTemplate(model);
ingo@1129:         }
ingo@1129:         catch (Exception e) {
ingo@1129:             logger.warn(e, e);
ingo@1129:         }
ingo@1129: 
ingo@1129:         return null;
ingo@1129:     }
ingo@1129: 
ingo@1129: 
ingo@1129:     /**
ingo@1129:      * Returns the mapfile  template.
ingo@1129:      *
ingo@1129:      * @return the mapfile template.
ingo@1129:      * @throws Exception if an error occured while reading the configuration.
ingo@1129:      */
christian@4656:     protected Template getMapfileTemplateObj()
ingo@1129:     throws Exception
ingo@1129:     {
christian@4703:         String mapfileName = getMapfileTemplate();
ingo@1129:         return getTemplateByName(mapfileName);
ingo@1129:     }
ingo@1129: 
christian@4656:     protected abstract String getMapfilePath();
christian@4656: 
christian@4656:     protected abstract String getMapfileTemplate();
christian@4656: 
ingo@1129: 
ingo@1129:     /**
ingo@1129:      * Returns the base directory storing the shapefiles.
ingo@1129:      *
ingo@1129:      * @return the shapefile base directory.
ingo@1129:      *
ingo@1129:      * @throws FileNotFoundException if no shapefile path is found or
ingo@1129:      * configured.
ingo@1129:      */
ingo@1792:     public File getShapefileBaseDir()
christian@3306:             throws FileNotFoundException, IOException
ingo@1129:     {
ingo@1129:         if (shapefileDirectory == null) {
ingo@1129:             String path = FLYSUtils.getXPathString(
christian@4656:                 FLYSUtils.XPATH_FLOODMAP_SHAPEFILE_DIR);
ingo@1129: 
ingo@1129:             if (path != null) {
ingo@1129:                 shapefileDirectory = new File(path);
ingo@1129:             }
ingo@1129: 
ingo@1775:             if (shapefileDirectory == null) {
ingo@1129:                 throw new FileNotFoundException("No shapefile directory given");
ingo@1129:             }
ingo@1775: 
ingo@1775:             if (!shapefileDirectory.exists()) {
christian@3306:                 shapefileDirectory.mkdirs();
ingo@1775:             }
ingo@1129:         }
ingo@1129: 
ingo@1129:         return shapefileDirectory;
ingo@1129:     }
ingo@1129: 
ingo@1129: 
ingo@1129:     protected File[] getUserDirs()
christian@3306:             throws FileNotFoundException, IOException
ingo@1129:     {
ingo@1129:         File   baseDir      = getShapefileBaseDir();
ingo@1129:         File[] artifactDirs = baseDir.listFiles();
ingo@1129: 
ingo@1129:         // TODO ONLY RETURN DIRECTORIES OF THE SPECIFIED USER
ingo@1129: 
ingo@1129:         return artifactDirs;
ingo@1129:     }
ingo@1129: 
ingo@1129: 
ingo@1129: 
ingo@1781:     protected List<String> parseLayers(File[] dirs) {
ingo@1781:         List<String> layers = new ArrayList<String>();
ingo@1129: 
ingo@1129:         for (File dir: dirs) {
ingo@1781:             File[] layerFiles = dir.listFiles(new FilenameFilter() {
ingo@1781:                 @Override
ingo@1781:                 public boolean accept(File directory, String name) {
ingo@1781:                     return name.startsWith(MS_LAYER_PREFIX);
ingo@1781:                 }
ingo@1781:             });
ingo@1129: 
ingo@1781:             for (File layer: layerFiles) {
ingo@1781:                 try {
ingo@1781:                     layers.add(layer.getCanonicalPath());
ingo@1781:                 }
ingo@1781:                 catch (IOException ioe) {
ingo@1781:                     logger.warn(ioe, ioe);
ingo@1134:                 }
ingo@1129:             }
ingo@1129:         }
ingo@1129: 
ingo@1129:         return layers;
ingo@1129:     }
ingo@1129: 
ingo@1129: 
ingo@1792: 
ingo@1792: 
ingo@1792:     /**
ingo@1781:      * Creates a layer snippet which might be included in the mapfile.
ingo@1781:      *
ingo@1781:      * @param layerinfo A LayerInfo object that contains all necessary
ingo@1781:      * information to build a Mapserver LAYER section.
ingo@1781:      * @param dir The base dir for the LAYER snippet.
ingo@1781:      * @param filename The name of the file that is written.
ingo@1781:      * @param tpl The Velocity template which is used to create the LAYER
ingo@1781:      * section.
ingo@1781:      */
ingo@1775:     protected void writeLayer(
christian@4656:         LayerInfo layerInfo,
christian@4656:         File      layerFile,
ingo@1775:         Template  tpl
ingo@1775:     )
ingo@1775:     throws    FileNotFoundException
ingo@1775:     {
ingo@1775:         if (logger.isDebugEnabled()) {
ingo@1775:             logger.debug("Write layer for:");
christian@4656:             logger.debug("   directory/file: " + layerFile.getName());
ingo@1775:         }
ingo@1775: 
ingo@1775:         Writer writer = null;
ingo@1775: 
ingo@1775:         try {
christian@4656:             writer = new FileWriter(layerFile);
ingo@1775: 
ingo@1792:             VelocityContext context = getVelocityContext();
christian@4656:             context.put("LAYER", layerInfo);
ingo@1775: 
ingo@1775:             tpl.merge(context, writer);
ingo@1775:         }
ingo@1775:         catch (FileNotFoundException fnfe) {
ingo@1775:             logger.error(fnfe, fnfe);
ingo@1775:         }
ingo@1775:         catch (IOException ioe) {
ingo@1775:             logger.error(ioe, ioe);
ingo@1775:         }
ingo@1775:         catch (Exception e) {
ingo@1775:             logger.error(e, e);
ingo@1775:         }
ingo@1775:         finally {
ingo@1775:             try {
ingo@1775:                 if (writer != null) {
ingo@1775:                     writer.close();
ingo@1775:                 }
ingo@1775:             }
ingo@1775:             catch (IOException ioe) {
ingo@1775:                 logger.debug(ioe, ioe);
ingo@1775:             }
ingo@1775:         }
ingo@1775:     }
ingo@1775: 
ingo@1775: 
ingo@1129:     /**
ingo@1129:      * Creates a mapfile with the layer information stored in <i>layers</i>.
ingo@1129:      *
ingo@1129:      * @param layers Layer information.
ingo@1129:      */
ingo@1781:     protected void writeMapfile(List<String> layers) {
ingo@1129:         String tmpMapName = "mapfile" + new Date().getTime();
ingo@1129: 
christian@4656:         File mapfile = new File(getMapfilePath());
ingo@1129: 
ingo@1129:         File   tmp     = null;
ingo@1129:         Writer writer  = null;
ingo@1129: 
ingo@1129:         try {
ingo@1129:             tmp = new File(mapfile.getParent(), tmpMapName);
ingo@1129:             tmp.createNewFile();
ingo@1129: 
ingo@1129:             writer = new FileWriter(tmp);
ingo@1129: 
ingo@1792:             VelocityContext context = getVelocityContext();
ingo@1781:             context.put("LAYERS", layers);
ingo@1129: 
christian@4656:             Template mapTemplate = getMapfileTemplateObj();
ingo@1129:             if (mapTemplate == null) {
ingo@1129:                 logger.warn("No mapfile template found.");
ingo@1129:                 return;
ingo@1129:             }
ingo@1129: 
ingo@1129:             mapTemplate.merge(context, writer);
ingo@1129: 
ingo@1129:             // we need to create a temporary mapfile first und rename it into
ingo@1129:             // real mapfile because we don't run into race conditions on this
ingo@1129:             // way. (iw)
ingo@1129:             tmp.renameTo(mapfile);
ingo@1129:         }
ingo@1129:         catch (FileNotFoundException fnfe) {
ingo@1129:             logger.error(fnfe, fnfe);
ingo@1129:         }
ingo@1129:         catch (IOException ioe) {
ingo@1129:             logger.error(ioe, ioe);
ingo@1129:         }
ingo@1129:         catch (Exception e) {
ingo@1129:             logger.error(e, e);
ingo@1129:         }
ingo@1129:         finally {
ingo@1129:             try {
ingo@1129:                 if (writer != null) {
ingo@1129:                     writer.close();
ingo@1129:                 }
ingo@1129: 
ingo@1129:                 if (tmp.exists()) {
ingo@1129:                     tmp.delete();
ingo@1129:                 }
ingo@1129:             }
ingo@1129:             catch (IOException ioe) {
ingo@1129:                 logger.debug(ioe, ioe);
ingo@1129:             }
ingo@1129:         }
ingo@1129:     }
ingo@1129: }
ingo@1129: // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :