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