Mercurial > dive4elements > gnv-client
view gnv-artifacts/src/main/java/de/intevation/gnv/utils/MapfileGenerator.java @ 949:11d8cc2deb92 1.0
merged doc/1.0
author | Thomas Arendsen Hein <thomas@intevation.de> |
---|---|
date | Fri, 28 Sep 2012 12:13:58 +0200 |
parents | 47578d91c4f0 |
children | f953c9a559d8 |
line wrap: on
line source
package de.intevation.gnv.utils; import de.intevation.artifactdatabase.Config; import de.intevation.artifactdatabase.XMLUtils; import de.intevation.artifacts.ArtifactNamespaceContext; import de.intevation.gnv.wms.LayerInfo; import java.io.File; import java.io.FileNotFoundException; import java.io.FileWriter; import java.io.IOException; import java.io.StringWriter; import java.io.Writer; import java.util.ArrayList; import java.util.Date; import java.util.List; import javax.xml.xpath.XPathConstants; import org.apache.log4j.Logger; import org.apache.velocity.Template; import org.apache.velocity.VelocityContext; import org.apache.velocity.app.VelocityEngine; import org.w3c.dom.Document; import org.w3c.dom.Node; import org.w3c.dom.NodeList; /** * This class iterates over a bunch of directories, searches for meta * information coresponding to shapefiles and creates a mapfile which is used by * a <i>MapServer</i>. * * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a> */ public class MapfileGenerator extends Thread { /** * The configured template path. */ public static final String TEMPLATE_PATH = "/artifact-database/gnv/map-generator/templates/path/text()"; /** * The configured template mapfile. */ public static final String TEMPLATE_MAPFILE = "/artifact-database/gnv/map-generator/templates/maptemplate/text()"; /** * The configured mapfile path. */ public static final String MAPFILE_PATH = "/artifact-database/gnv/map-generator/mapfile/@path"; /** * The configured shapefile base directory where the subdirectories for each * artifact are stored. */ public static final String SHAPEFILE_BASE_DIR = "/artifact-database/gnv/shapefile-directory/@path"; /** * The configured velocity logfile. */ public static final String VELOCITY_LOGFILE = "/artifact-database/velocity/logfile/@path"; /** * The URL for calling the mapserver */ public static final String MAPSERVER_URL = "/artifact-database/mapserver/server/@path"; /** * The name of the file storing meta information coresponding to shapefiles. */ public static final String META_FILE_NAME = "meta.xml"; /** * The XPath to layer nodes in the meta information xml file. */ public static final String XPATH_LAYER = "/art:meta/art:layer"; public static final String XPATH_LAYER_NAME = "art:name"; public static final String XPATH_LAYER_TITLE = "art:title"; public static final String XPATH_LAYER_TYPE = "art:type"; public static final String XPATH_LAYER_DATA = "art:data"; public static final String XPATH_LAYER_STATUS = "art:status"; public static final String XPATH_LAYER_MODEL = "art:model"; protected static final long SLEEPTIME = 10 * 1000L; // 10 seconds private static Logger logger = Logger.getLogger(MapfileGenerator.class); private static MapfileGenerator instance; private File mapfile; private String mapServerUrl; private String shapefileDirectory; private String templatePath; private String velocityLogfile; private VelocityEngine velocityEngine; private boolean lock[]; private MapfileGenerator() { lock = new boolean[1]; } /** * A main method which can be used to create a mapfile without a running * artifact server.<br> * <b>NOTE:</b> This method is not implemented yet! * * @param args Arguments. */ public static void main(String[] args) { // TODO IMPLEMENT ME } /** * Returns the instance of this generator. * * @return the instance. */ public static synchronized MapfileGenerator getInstance() { if (instance == null) { instance = new MapfileGenerator(); instance.setDaemon(true); instance.start(); } return instance; } /** * Triggers the mapfile generation process. */ public void update() { synchronized (lock) { logger.debug("update"); lock[0] = true; lock.notify(); } } /** * Thread to generate a mapfile. */ @Override public void run() { logger.debug("Start MapfileGenerator thread..."); try { for (;;) { synchronized (lock) { while (!lock[0]) { lock.wait(SLEEPTIME); } lock[0] = false; } logger.debug("Start sync process now..."); generate(); } } catch (InterruptedException ie) { logger.debug("MapfileGenerator thread got an interrupt."); } finally { logger.debug("THREAD END"); } } /** * Method to check the existance of a template file. * * @param templateID The name of a template. * @return true, of the template exists - otherwise false. */ public boolean templateExists(String templateID){ Template template = getTemplateByName(templateID); return template != null; } /** * Method which starts searching for meta information file and mapfile * generation. */ protected void generate() { File basedir = new File(getShapefileBaseDir()); List layers = new ArrayList(); searchMetaInformation(basedir, layers); writeMapfile(layers); } /** * Returns the VelocityEngine used for the template mechanism. * * @return the velocity engine. */ protected VelocityEngine getVelocityEngine() { if (velocityEngine == null) { velocityEngine = new VelocityEngine(); try { setupVelocity(velocityEngine); } catch (Exception e) { logger.error(e, e); return null; } } return velocityEngine; } /** * Initialize velocity. * * @param engine Velocity engine. * @throws Exception if an error occured while initializing velocity. */ protected void setupVelocity(VelocityEngine engine) throws Exception { engine.setProperty( "input.encoding", "UTF-8"); engine.setProperty( VelocityEngine.RUNTIME_LOG, getVelocityLogfile()); engine.setProperty( "resource.loader", "file"); engine.setProperty( "file.resource.loader.path", getTemplateBaseDir()); engine.init(); } /** * Returns the path specifying the logfile for velocity. * * @return Velocity logfile path. */ protected String getVelocityLogfile() { if (velocityLogfile == null) velocityLogfile = Config.getStringXPath(VELOCITY_LOGFILE); return velocityLogfile; } /** * Returns the base directory storing the templates. * * @return the template base directory. */ protected String getTemplateBaseDir() { if (templatePath == null) { templatePath = Config.getStringXPath(TEMPLATE_PATH); templatePath = Config.replaceConfigDir(templatePath); } return templatePath; } /** * Returns the URL for calling the MapServer. * * @return the url for calling the MapServer. */ protected String getMapServerUrl() { if (mapServerUrl == null) { mapServerUrl = Config.getStringXPath(MAPSERVER_URL); mapServerUrl = Config.replaceConfigDir(mapServerUrl); } return mapServerUrl; } /** * Returns a template specified by <i>model</i>. * * @param model The name of the template. * @return a template. */ protected Template getTemplateByName(String model) { if (model.indexOf(".vm") < 0) { model = model.concat(".vm"); } try { VelocityEngine engine = getVelocityEngine(); if (engine == null) { logger.error("Error while fetching VelocityEngine."); return null; } return engine.getTemplate(model); } catch (Exception e) { logger.warn(e, e); } return null; } /** * Returns the mapfile template. * * @return the mapfile template. * @throws Exception if an error occured while reading the configuration. */ protected Template getMapfileTemplate() throws Exception { String mapfileName = Config.getStringXPath(TEMPLATE_MAPFILE); return getTemplateByName(mapfileName); } /** * Returns the base directory storing the shapefiles. * * @return the shapefile base directory. */ protected String getShapefileBaseDir() { if (shapefileDirectory == null) { shapefileDirectory = Config.getStringXPath(SHAPEFILE_BASE_DIR); shapefileDirectory = Config.replaceConfigDir(shapefileDirectory); } return shapefileDirectory; } /** * Returns the mapfile. * * @return the mapfile. */ protected File getMapfile() { if (mapfile == null) { String tmp = Config.getStringXPath(MAPFILE_PATH); tmp = Config.replaceConfigDir(tmp); mapfile = new File(tmp); } return mapfile; } /** * Search for meta information file in <i>file</i> and store the layer * information in <i>store</i> if a meta file was found. * * @param file The root directory to be searched for meta files. * @param store A list storing <code>LayerInfo</code> objects. */ protected void searchMetaInformation(File file, List store) { if (file.isDirectory()) { File[] files = file.listFiles(); if (files != null && files.length != 0) { int size = files.length; for (File tmp: files) { searchMetaInformation(tmp, store); } } } else if (file.getName().equals(META_FILE_NAME)) { LayerInfo[] info = parseMeta(file); int infoSize = info.length; for (int j = 0; j < infoSize; j++) { if (info[j] != null) { store.add(info[j]); } } } } /** * Parses a meta information file and returns necessary information as * <code>LayerInfo</code> array. * * @param file Meta information file. * @return Array of LayerInfo objects. */ protected LayerInfo[] parseMeta(File file) { Document meta = XMLUtils.parseDocument(file); List layers = new ArrayList(); NodeList layerset = (NodeList) XMLUtils.xpath( meta, XPATH_LAYER, XPathConstants.NODESET, ArtifactNamespaceContext.INSTANCE); int size = layerset.getLength(); for (int i = 0; i < size; i++) { LayerInfo info = parseLayer(layerset.item(i)); if (info != null && !info.isEmpty() && !info.isBroken()) { layers.add(info); } else { logger.warn("Found broken LayerInfo object."); } } return (LayerInfo[]) layers.toArray(new LayerInfo[layers.size()]); } /** * Parses a node storing layer information and returns them. * * @param layer Node storing information about a layer. * @return a LayerInfo object. */ protected LayerInfo parseLayer(Node layer) { LayerInfo info = new LayerInfo(); String name = parseLayerAttr(layer, XPATH_LAYER_NAME); if (name != null && !name.equals("")) { info.setName(name); } String title = parseLayerAttr(layer, XPATH_LAYER_TITLE); if (title != null && !title.equals("")) { info.setTitle(title); } else { info.setTitle(name); } String model = parseLayerAttr(layer, XPATH_LAYER_MODEL); if (model != null && !model.equals("")) { info.setModel(model); } String type = parseLayerAttr(layer, XPATH_LAYER_TYPE); if (type != null && !type.equals("")) { info.setType(type); } String data = parseLayerAttr(layer, XPATH_LAYER_DATA); if (data != null && !data.equals("")) { info.setData(data); } String status = parseLayerAttr(layer, XPATH_LAYER_STATUS); if (status != null && !status.equals("")) { info.setStatus(status); } return info; } /** * Parses attributes in layer nodes. * * @param node A node containing layer information. * @param xpath XPath specifying an attribute. * @return Attribute as string. */ protected String parseLayerAttr(Node node, String xpath) { return (String) XMLUtils.xpath( node, xpath, XPathConstants.STRING, ArtifactNamespaceContext.INSTANCE); } /** * Creates a mapfile with the layer information stored in <i>layers</i>. * * @param layers Layer information. */ protected void writeMapfile(List layers) { String tmpMapName = "mapfile" + new Date().getTime(); int layersize = layers.size(); StringBuilder sb = new StringBuilder(); StringWriter sw = null; LayerInfo info = null; for (int i = 0; i < layersize; i++) { sw = new StringWriter(); info = (LayerInfo) layers.get(i); Template layerTemplate = getTemplateByName(info.getModel()); VelocityContext context = new VelocityContext(); context.put("info", info); try { layerTemplate.merge(context, sw); sb.append(sw.toString()); } catch (IOException ioe) { logger.warn("Error while filling layer template."); logger.warn(ioe, ioe); } } File map = getMapfile(); Writer writer = null; File tmp = null; try { tmp = new File(map.getParent(), tmpMapName); tmp.createNewFile(); writer = new FileWriter(tmp); VelocityContext context = new VelocityContext(); context.put("MAPSERVERURL", getMapServerUrl()); context.put("LAYERS", sb.toString()); Template mapTemplate = getMapfileTemplate(); if (mapTemplate == null) { logger.warn("No mapfile template found."); return; } mapTemplate.merge(context, writer); // we need to create a temporary mapfile first und rename it into // real mapfile because we don't run into race conditions on this // way. (iw) tmp.renameTo(map); } catch (FileNotFoundException fnfe) { logger.error(fnfe, fnfe); } catch (IOException ioe) { logger.error(ioe, ioe); } catch (Exception e) { logger.error(e, e); } finally { try { // close file writer if (writer != null) { writer.close(); } // remove temporary mapfile if an error occured and it still // exists if (tmp.exists()) { tmp.delete(); } } catch (IOException ioe) { logger.debug(ioe, ioe); } } } } // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :