ingo@1129: package de.intevation.flys.utils;
ingo@1129:
ingo@1129: import java.io.File;
ingo@1129: import java.io.FileNotFoundException;
ingo@1129: import java.io.FileWriter;
ingo@1129: import java.io.IOException;
ingo@1129: import java.io.StringWriter;
ingo@1129: import java.io.Writer;
ingo@1129:
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:
ingo@1129: import org.apache.velocity.Template;
ingo@1129: import org.apache.velocity.VelocityContext;
ingo@1129: import org.apache.velocity.app.VelocityEngine;
ingo@1129:
ingo@1710: import de.intevation.artifacts.common.utils.Config;
ingo@1710:
ingo@1129: import de.intevation.flys.artifacts.model.LayerInfo;
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 MapServer.
ingo@1129: *
ingo@1129: * @author Ingo Weinzierl
ingo@1129: */
ingo@1129: public class MapfileGenerator
ingo@1129: extends Thread
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";
ingo@1134:
ingo@1134: public static final String MS_WSPLGEN_POSTFIX = "-wsplgen";
ingo@1134: public static final String MS_BARRIERS_POSTFIX = "-barriers";
ingo@1134: public static final String MS_LINE_POSTFIX = "-lines";
ingo@1134: public static final String MS_POLYGONS_POSTFIX = "-polygons";
ingo@1129:
ingo@1129: protected static final long SLEEPTIME = 10 * 1000L; // 10 seconds
ingo@1129:
ingo@1129: private static Logger logger = Logger.getLogger(MapfileGenerator.class);
ingo@1129:
ingo@1129: private static MapfileGenerator instance;
ingo@1129:
ingo@1129: private File mapfile;
ingo@1129: private File shapefileDirectory;
ingo@1129:
ingo@1129: private String mapServerUrl;
ingo@1129: private String templatePath;
ingo@1129: private String velocityLogfile;
ingo@1129:
ingo@1129: private VelocityEngine velocityEngine;
ingo@1129: private boolean lock[];
ingo@1129:
ingo@1129:
ingo@1129:
ingo@1129: private MapfileGenerator() {
ingo@1129: lock = new boolean[1];
ingo@1129: }
ingo@1129:
ingo@1129:
ingo@1129: /**
ingo@1129: * A main method which can be used to create a mapfile without a running
ingo@1129: * artifact server.
ingo@1129: * NOTE: This method is not implemented yet!
ingo@1129: *
ingo@1129: * @param args Arguments.
ingo@1129: */
ingo@1129: public static void main(String[] args) {
ingo@1129: throw new Error("MapfileGenerator.main() is CURRENTLY NOT IMPLEMENTED!");
ingo@1129: }
ingo@1129:
ingo@1129:
ingo@1129: /**
ingo@1129: * Returns the instance of this generator.
ingo@1129: *
ingo@1129: * @return the instance.
ingo@1129: */
ingo@1129: public static synchronized MapfileGenerator getInstance() {
ingo@1129: if (instance == null) {
ingo@1129: instance = new MapfileGenerator();
ingo@1129: instance.setDaemon(true);
ingo@1129: instance.start();
ingo@1129: }
ingo@1129:
ingo@1129: return instance;
ingo@1129: }
ingo@1129:
ingo@1129:
ingo@1129: /**
ingo@1129: * Triggers the mapfile generation process.
ingo@1129: */
ingo@1129: public void update() {
ingo@1129: synchronized (lock) {
ingo@1129: logger.debug("update");
ingo@1129: lock[0] = true;
ingo@1129: lock.notify();
ingo@1129: }
ingo@1129: }
ingo@1129:
ingo@1129:
ingo@1129: /**
ingo@1129: * Thread to generate a mapfile.
ingo@1129: */
ingo@1129: @Override
ingo@1129: public void run() {
ingo@1129: logger.debug("Start MapfileGenerator thread...");
ingo@1129: try {
ingo@1129: for (;;) {
ingo@1129: synchronized (lock) {
ingo@1129: while (!lock[0]) {
ingo@1129: lock.wait(SLEEPTIME);
ingo@1129: }
ingo@1129: lock[0] = false;
ingo@1129: }
ingo@1129:
ingo@1129: logger.debug("Start sync process now...");
ingo@1129: generate();
ingo@1129: }
ingo@1129: }
ingo@1129: catch (InterruptedException ie) {
ingo@1129: logger.debug("MapfileGenerator thread got an interrupt.");
ingo@1129: }
ingo@1129: catch (FileNotFoundException fnfe) {
ingo@1129: logger.debug("Error while mapfile creation: " + fnfe.getMessage());
ingo@1129: }
ingo@1129: finally {
ingo@1129: logger.debug("THREAD END");
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:
ingo@1129: /**
ingo@1129: * Method which starts searching for meta information file and mapfile
ingo@1129: * generation.
ingo@1129: */
ingo@1129: protected void generate()
ingo@1129: throws FileNotFoundException
ingo@1129: {
ingo@1129: File[] userDirs = getUserDirs();
ingo@1129: List layers = parseLayers(userDirs);
ingo@1129:
ingo@1129: logger.info("Found " + layers.size() + " layers for user mapfile.");
ingo@1129:
ingo@1129: writeMapfile(layers);
ingo@1129: }
ingo@1129:
ingo@1129:
ingo@1129: /**
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(
ingo@1129: VelocityEngine.RUNTIME_LOG,
ingo@1129: FLYSUtils.getXPathString(FLYSUtils.XPATH_VELOCITY_LOGFILE));
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",
ingo@1129: FLYSUtils.getXPathString(FLYSUtils.XPATH_MAPSERVER_TEMPLATE_PATH));
ingo@1129:
ingo@1129: engine.init();
ingo@1129: }
ingo@1129:
ingo@1129:
ingo@1129: /**
ingo@1129: * Returns a template specified by model.
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: */
ingo@1129: protected Template getMapfileTemplate()
ingo@1129: throws Exception
ingo@1129: {
ingo@1129: String mapfileName = FLYSUtils.getXPathString(
ingo@1129: FLYSUtils.XPATH_MAPFILE_TEMPLATE);
ingo@1129:
ingo@1129: return getTemplateByName(mapfileName);
ingo@1129: }
ingo@1129:
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@1129: protected File getShapefileBaseDir()
ingo@1129: throws FileNotFoundException
ingo@1129: {
ingo@1129: if (shapefileDirectory == null) {
ingo@1129: String path = FLYSUtils.getXPathString(
ingo@1129: FLYSUtils.XPATH_SHAPEFILE_DIR);
ingo@1129:
ingo@1129: if (path != null) {
ingo@1129: shapefileDirectory = new File(path);
ingo@1129: }
ingo@1129:
ingo@1129: if (shapefileDirectory == null || !shapefileDirectory.exists()) {
ingo@1129: throw new FileNotFoundException("No shapefile directory given");
ingo@1129: }
ingo@1129: }
ingo@1129:
ingo@1129: return shapefileDirectory;
ingo@1129: }
ingo@1129:
ingo@1129:
ingo@1129: protected File[] getUserDirs()
ingo@1129: throws FileNotFoundException
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@1129: protected List parseLayers(File[] dirs) {
ingo@1129: List layers = new ArrayList();
ingo@1129:
ingo@1129: for (File dir: dirs) {
ingo@1129: LayerInfo layer = parseUeskLayer(dir);
ingo@1134: if (layer != null && layer.getData() != null) {
ingo@1134: logger.debug(" Add WSPLGEN layer.");
ingo@1134: layers.add(layer);
ingo@1134: }
ingo@1129:
ingo@1134: List barriers = parseBarriersLayers(dir);
ingo@1134: int num = barriers != null ? barriers.size() : 0;
ingo@1134: if (num > 0) {
ingo@1134: if (barriers.get(0).getData() != null) {
ingo@1134: logger.debug(" Add " + num + " BARRIERS layers.");
ingo@1134: layers.addAll(barriers);
ingo@1134: }
ingo@1129: }
ingo@1129: }
ingo@1129:
ingo@1129: return layers;
ingo@1129: }
ingo@1129:
ingo@1129:
ingo@1129: protected LayerInfo parseUeskLayer(File dir) {
ingo@1129: File uesk = new File(dir, WSPLGEN_RESULT_SHAPE);
ingo@1129:
ingo@1129: if (!uesk.exists() || !uesk.isFile()) {
ingo@1129: return null;
ingo@1129: }
ingo@1129:
ingo@1134: return new LayerInfo(
ingo@1134: dir.getName() + MS_WSPLGEN_POSTFIX,
ingo@1134: "POLYGON",
ingo@1134: dir.getName(),
ingo@1134: WSPLGEN_RESULT_SHAPE,
ingo@1134: "I18N_WSPLGEN_RESULT");
ingo@1129: }
ingo@1129:
ingo@1129:
ingo@1134: protected List parseBarriersLayers(File dir) {
ingo@1134: List barriers = new ArrayList(2);
ingo@1129:
ingo@1134: String group = dir.getName() + MS_BARRIERS_POSTFIX;
ingo@1134: String groupTitle = "I18N_BARRIERS_TITLE";
ingo@1134:
ingo@1134: File lines = new File(dir, WSPLGEN_LINES_SHAPE);
ingo@1134: File polygons = new File(dir, WSPLGEN_POLYGONS_SHAPE);
ingo@1134:
ingo@1134: if (lines.exists() || lines.isFile()) {
ingo@1134: barriers.add(
ingo@1134: new LayerInfo(
ingo@1134: dir.getName() + MS_LINE_POSTFIX,
ingo@1134: "LINE",
ingo@1134: dir.getName(),
ingo@1134: WSPLGEN_LINES_SHAPE,
ingo@1134: "I18N_LINE_SHAPE",
ingo@1134: group,
ingo@1134: groupTitle));
ingo@1134: }
ingo@1134:
ingo@1134: if (polygons.exists() || polygons.isFile()) {
ingo@1134: barriers.add(
ingo@1134: new LayerInfo(
ingo@1134: dir.getName() + MS_POLYGONS_POSTFIX,
ingo@1134: "POLYGON",
ingo@1134: dir.getName(),
ingo@1134: WSPLGEN_POLYGONS_SHAPE,
ingo@1134: "I18N_POLYGON_SHAPE",
ingo@1134: group,
ingo@1134: groupTitle));
ingo@1134: }
ingo@1134:
ingo@1134: return barriers;
ingo@1129: }
ingo@1129:
ingo@1129:
ingo@1129: /**
ingo@1129: * Creates a mapfile with the layer information stored in layers.
ingo@1129: *
ingo@1129: * @param layers Layer information.
ingo@1129: */
ingo@1129: protected void writeMapfile(List layers) {
ingo@1129: String tmpMapName = "mapfile" + new Date().getTime();
ingo@1129:
ingo@1129: File mapfile = new File(
ingo@1129: FLYSUtils.getXPathString(FLYSUtils.XPATH_MAPFILE_PATH));
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@1129: VelocityContext context = new VelocityContext();
ingo@1129: context.put("MAPSERVERURL",
ingo@1129: FLYSUtils.getXPathString(FLYSUtils.XPATH_MAPSERVER_URL));
ingo@1129: context.put("SHAPEFILEPATH",
ingo@1642: getShapefileBaseDir().getCanonicalPath());
ingo@1710: context.put("CONFIGDIR",
ingo@1710: Config.getConfigDirectory().getCanonicalPath());
ingo@1129: context.put("LAYERS", fillLayerTemplates(layers));
ingo@1129:
ingo@1129: Template mapTemplate = getMapfileTemplate();
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:
ingo@1129: protected List fillLayerTemplates(List layers) {
ingo@1129: List evaluated = new ArrayList(layers.size());
ingo@1129:
ingo@1129: for (LayerInfo layer: layers) {
ingo@1129: StringWriter writer = new StringWriter();
ingo@1129:
ingo@1129: VelocityContext context = new VelocityContext();
ingo@1129: context.put("LAYER", layer);
ingo@1129:
ingo@1129: Template t = getTemplateByName("layer.vm");
ingo@1129: if (t == null) {
ingo@1129: logger.warn("No 'layer.vm' template found.");
ingo@1129: return evaluated;
ingo@1129: }
ingo@1129:
ingo@1129: t.merge(context, writer);
ingo@1129:
ingo@1129: evaluated.add(writer.toString());
ingo@1129: }
ingo@1129:
ingo@1129: return evaluated;
ingo@1129: }
ingo@1129: }
ingo@1129: // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :