Mercurial > dive4elements > river
view flys-artifacts/src/main/java/de/intevation/flys/utils/MapfileGenerator.java @ 4031:e4e345d81a65
issue889/2
author | Felix Wolfsteller <felix.wolfsteller@intevation.de> |
---|---|
date | Thu, 04 Oct 2012 14:54:44 +0200 |
parents | 1b41dc00b1f7 |
children | 3dc26ec2558d |
line wrap: on
line source
package de.intevation.flys.utils; import de.intevation.artifacts.CallContext; import de.intevation.artifacts.common.utils.Config; import de.intevation.flys.artifacts.FLYSArtifact; import de.intevation.flys.artifacts.model.LayerInfo; import de.intevation.flys.artifacts.model.map.WMSDBLayerFacet; import de.intevation.flys.artifacts.model.map.WMSLayerFacet; import de.intevation.flys.artifacts.model.map.WSPLGENLayerFacet; import de.intevation.flys.artifacts.resources.Resources; import java.io.File; import java.io.FileNotFoundException; import java.io.FileWriter; import java.io.FilenameFilter; import java.io.IOException; import java.io.Writer; import java.util.ArrayList; import java.util.Date; import java.util.List; import org.apache.log4j.Logger; import org.apache.velocity.Template; import org.apache.velocity.VelocityContext; import org.apache.velocity.app.VelocityEngine; import org.geotools.data.shapefile.ShpFiles; import org.geotools.data.shapefile.shp.ShapefileHeader; import org.geotools.data.shapefile.shp.ShapefileReader; /** * 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 { public static final String WSPLGEN_RESULT_SHAPE = "wsplgen.shp"; public static final String WSPLGEN_LINES_SHAPE = "barrier_lines.shp"; public static final String WSPLGEN_POLYGONS_SHAPE = "barrier_polygons.shp"; public static final String WSPLGEN_USER_SHAPE = "user-rgd.shp"; public static final String WSPLGEN_LAYER_TEMPLATE = "wsplgen_layer.vm"; public static final String SHP_LAYER_TEMPLATE = "shapefile_layer.vm"; public static final String DB_LAYER_TEMPLATE = "db_layer.vm"; public static final String MS_WSPLGEN_PREFIX = "wsplgen-"; public static final String MS_BARRIERS_PREFIX = "barriers-"; public static final String MS_LINE_PREFIX = "lines-"; public static final String MS_POLYGONS_PREFIX = "polygons-"; public static final String MS_LAYER_PREFIX = "ms_layer-"; public static final String MS_USERSHAPE_PREFIX = "user-"; 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 File shapefileDirectory; private String mapServerUrl; private String templatePath; private String velocityLogfile; private VelocityEngine velocityEngine; private final 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) { throw new Error("MapfileGenerator.main() is CURRENTLY NOT IMPLEMENTED!"); } /** * 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."); } catch (FileNotFoundException fnfe) { logger.debug("Error while mapfile creation: " + fnfe.getMessage()); } catch (IOException ioe) { logger.error(ioe, ioe); } 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() throws FileNotFoundException, IOException { File[] userDirs = getUserDirs(); List<String> layers = parseLayers(userDirs); logger.info("Found " + layers.size() + " layers for user mapfile."); 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, FLYSUtils.getXPathString(FLYSUtils.XPATH_VELOCITY_LOGFILE)); engine.setProperty( "resource.loader", "file"); engine.setProperty( "file.resource.loader.path", FLYSUtils.getXPathString(FLYSUtils.XPATH_MAPSERVER_TEMPLATE_PATH)); engine.init(); } protected VelocityContext getVelocityContext() { VelocityContext context = new VelocityContext(); try { context.put("MAPSERVERURL", FLYSUtils.getXPathString(FLYSUtils.XPATH_MAPSERVER_URL)); context.put("SHAPEFILEPATH", getShapefileBaseDir().getCanonicalPath()); context.put("CONFIGDIR", Config.getConfigDirectory().getCanonicalPath()); } catch (FileNotFoundException fnfe) { // this is bad } catch (IOException ioe) { // this is also bad } return context; } /** * 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 = FLYSUtils.getXPathString( FLYSUtils.XPATH_MAPFILE_TEMPLATE); return getTemplateByName(mapfileName); } /** * Returns the base directory storing the shapefiles. * * @return the shapefile base directory. * * @throws FileNotFoundException if no shapefile path is found or * configured. */ public File getShapefileBaseDir() throws FileNotFoundException, IOException { if (shapefileDirectory == null) { String path = FLYSUtils.getXPathString( FLYSUtils.XPATH_SHAPEFILE_DIR); if (path != null) { shapefileDirectory = new File(path); } if (shapefileDirectory == null) { throw new FileNotFoundException("No shapefile directory given"); } if (!shapefileDirectory.exists()) { shapefileDirectory.mkdirs(); } } return shapefileDirectory; } protected File[] getUserDirs() throws FileNotFoundException, IOException { File baseDir = getShapefileBaseDir(); File[] artifactDirs = baseDir.listFiles(); // TODO ONLY RETURN DIRECTORIES OF THE SPECIFIED USER return artifactDirs; } protected List<String> parseLayers(File[] dirs) { List<String> layers = new ArrayList<String>(); for (File dir: dirs) { File[] layerFiles = dir.listFiles(new FilenameFilter() { @Override public boolean accept(File directory, String name) { return name.startsWith(MS_LAYER_PREFIX); } }); for (File layer: layerFiles) { try { layers.add(layer.getCanonicalPath()); } catch (IOException ioe) { logger.warn(ioe, ioe); } } } return layers; } /** * Creates a layer file used for Mapserver's mapfile which represents the * floodmap. * * @param flys The FLYSArtifact that owns <i>wms</i>. * @param wms The WMSLayerFacet that contains information for the layer. */ public void createUeskLayer( FLYSArtifact flys, WSPLGENLayerFacet wms, String style, CallContext context ) throws FileNotFoundException, IOException { logger.debug("createUeskLayer"); LayerInfo layerinfo = new LayerInfo(); layerinfo.setName(MS_WSPLGEN_PREFIX + flys.identifier()); layerinfo.setType("POLYGON"); layerinfo.setDirectory(flys.identifier()); layerinfo.setData(WSPLGEN_RESULT_SHAPE); layerinfo.setTitle(Resources.getMsg(Resources.getLocale(context.getMeta()), "floodmap.uesk", "Floodmap")); layerinfo.setStyle(style); layerinfo.setSrid(wms.getSrid()); String name = MS_LAYER_PREFIX + wms.getName(); Template template = getTemplateByName(WSPLGEN_LAYER_TEMPLATE); if (template == null) { logger.warn("Template '" + WSPLGEN_LAYER_TEMPLATE + "' found."); return; } try { File dir = new File(getShapefileBaseDir(), flys.identifier()); writeLayer(layerinfo, dir, name, template); } catch (FileNotFoundException fnfe) { logger.error(fnfe, fnfe); logger.warn("Unable to write layer: " + name); } } /** * Creates a layer file used for Mapserver's mapfile which represents the * user defined barriers. * * @param flys The FLYSArtifact that owns <i>wms</i>. * @param wms The WMSLayerFacet that contains information for the layer. */ public void createBarriersLayer(FLYSArtifact flys, WMSLayerFacet wms) throws FileNotFoundException, IOException { logger.debug("createBarriersLayer"); //String uuid = flys.identifier(); //File dir = new File(getShapefileBaseDir(), uuid); createBarriersLineLayer(flys, wms); createBarriersPolygonLayer(flys, wms); } protected void createBarriersLineLayer( FLYSArtifact flys, WMSLayerFacet wms ) throws FileNotFoundException, IOException { String uuid = flys.identifier(); String group = MS_BARRIERS_PREFIX + uuid; String groupTitle = "I18N_BARRIERS_TITLE"; File dir = new File(getShapefileBaseDir(), uuid); File test = new File(dir, WSPLGEN_LINES_SHAPE); if (!test.exists() || !test.canRead()) { logger.debug("No barrier line layer existing."); return; } LayerInfo lineInfo = new LayerInfo(); lineInfo.setName(MS_LINE_PREFIX + uuid); lineInfo.setType("LINE"); lineInfo.setDirectory(uuid); lineInfo.setData(WSPLGEN_LINES_SHAPE); lineInfo.setTitle("I18N_LINE_SHAPE"); lineInfo.setGroup(group); lineInfo.setGroupTitle(groupTitle); lineInfo.setSrid(wms.getSrid()); String nameLines = MS_LAYER_PREFIX + wms.getName() + "-lines"; Template tpl = getTemplateByName(SHP_LAYER_TEMPLATE); if (tpl == null) { logger.warn("Template '" + SHP_LAYER_TEMPLATE + "' found."); return; } try { writeLayer(lineInfo, dir, nameLines, tpl); } catch (FileNotFoundException fnfe) { logger.error(fnfe, fnfe); logger.warn("Unable to write layer: " + nameLines); } } protected void createBarriersPolygonLayer( FLYSArtifact flys, WMSLayerFacet wms ) throws FileNotFoundException, IOException { String uuid = flys.identifier(); String group = uuid + MS_BARRIERS_PREFIX; String groupTitle = "I18N_BARRIERS_TITLE"; File dir = new File(getShapefileBaseDir(), uuid); File test = new File(dir, WSPLGEN_POLYGONS_SHAPE); if (!test.exists() || !test.canRead()) { logger.debug("No barrier line layer existing."); return; } LayerInfo polygonInfo = new LayerInfo(); polygonInfo.setName(MS_POLYGONS_PREFIX + uuid); polygonInfo.setType("POLYGON"); polygonInfo.setDirectory(uuid); polygonInfo.setData(WSPLGEN_POLYGONS_SHAPE); polygonInfo.setTitle("I18N_POLYGON_SHAPE"); polygonInfo.setGroup(group); polygonInfo.setGroupTitle(groupTitle); polygonInfo.setSrid(wms.getSrid()); String namePolygons = MS_LAYER_PREFIX + wms.getName() + "-polygons"; Template tpl = getTemplateByName(SHP_LAYER_TEMPLATE); if (tpl == null) { logger.warn("Template '" + SHP_LAYER_TEMPLATE + "' found."); return; } try { writeLayer(polygonInfo, dir, namePolygons, tpl); } catch (FileNotFoundException fnfe) { logger.error(fnfe, fnfe); logger.warn("Unable to write layer: " + namePolygons); } } /** * Creates a layer file used for Mapserver's mapfile which represents the * shape files uploaded by the user. * * @param flys The FLYSArtifact that owns <i>wms</i>. * @param wms The WMSLayerFacet that contains information for the layer. */ public void createUserShapeLayer(FLYSArtifact flys, WMSLayerFacet wms) throws FileNotFoundException, IOException { logger.debug("createUserShapeLayer"); String uuid = flys.identifier(); File dir = new File(getShapefileBaseDir(), uuid); File test = new File(dir, WSPLGEN_USER_SHAPE); if (!test.exists() || !test.canRead()) { logger.debug("No user layer existing."); return; } File userShape = new File(dir, WSPLGEN_USER_SHAPE); ShpFiles sf = new ShpFiles(userShape); ShapefileReader sfr = new ShapefileReader(sf, true, false, null); ShapefileHeader sfh = sfr.getHeader(); String group = uuid + MS_USERSHAPE_PREFIX; String groupTitle = "I18N_USER_SHAPE_TITLE"; LayerInfo info = new LayerInfo(); info.setName(MS_USERSHAPE_PREFIX + uuid); if (sfh.getShapeType().isLineType()) { info.setType("LINE"); } else if (sfh.getShapeType().isPolygonType()) { info.setType("POLYGON"); } else { return; } info.setDirectory(uuid); info.setData(WSPLGEN_USER_SHAPE); info.setTitle("I18N_USER_SHAPE"); info.setGroup(group); info.setGroupTitle(groupTitle); info.setSrid(wms.getSrid()); String nameUser = MS_LAYER_PREFIX + wms.getName(); Template tpl = getTemplateByName(SHP_LAYER_TEMPLATE); if (tpl == null) { logger.warn("Template '" + SHP_LAYER_TEMPLATE + "' found."); return; } try { writeLayer(info, dir, nameUser, tpl); } catch (FileNotFoundException fnfe) { logger.error(fnfe, fnfe); logger.warn("Unable to write layer: " + nameUser); } } /** * Creates a layer file used for Mapserver's mapfile which represents * geometries from database. * * @param flys The FLYSArtifact that owns <i>wms</i>. * @param wms The WMSLayerFacet that contains information for the layer. */ public void createDatabaseLayer( FLYSArtifact flys, WMSDBLayerFacet wms, String style ) throws FileNotFoundException, IOException { logger.debug("createDatabaseLayer"); LayerInfo layerinfo = new LayerInfo(); layerinfo.setName(wms.getName() + "-" + flys.identifier()); layerinfo.setType(wms.getGeometryType()); layerinfo.setFilter(wms.getFilter()); layerinfo.setData(wms.getData()); layerinfo.setTitle(wms.getDescription()); layerinfo.setStyle(style); if(wms.getExtent() != null) { layerinfo.setExtent(GeometryUtils.jtsBoundsToOLBounds(wms.getExtent())); } layerinfo.setConnection(wms.getConnection()); layerinfo.setConnectionType(wms.getConnectionType()); layerinfo.setLabelItem(wms.getLabelItem()); layerinfo.setSrid(wms.getSrid()); String name = MS_LAYER_PREFIX + wms.getName(); Template template = getTemplateByName(DB_LAYER_TEMPLATE); if (template == null) { logger.warn("Template '" + DB_LAYER_TEMPLATE + "' found."); return; } try { File dir = new File(getShapefileBaseDir(), flys.identifier()); writeLayer(layerinfo, dir, name, template); } catch (FileNotFoundException fnfe) { logger.error(fnfe, fnfe); logger.warn("Unable to write layer: " + name); } } /** * Creates a layer snippet which might be included in the mapfile. * * @param layerinfo A LayerInfo object that contains all necessary * information to build a Mapserver LAYER section. * @param dir The base dir for the LAYER snippet. * @param filename The name of the file that is written. * @param tpl The Velocity template which is used to create the LAYER * section. */ protected void writeLayer( LayerInfo layerinfo, File dir, String filename, Template tpl ) throws FileNotFoundException { if (logger.isDebugEnabled()) { logger.debug("Write layer for:"); logger.debug(" directory: " + dir.getName()); logger.debug(" name: " + filename); } File layer = new File(dir, filename); Writer writer = null; try { writer = new FileWriter(layer); VelocityContext context = getVelocityContext(); context.put("LAYER", layerinfo); tpl.merge(context, writer); } catch (FileNotFoundException fnfe) { logger.error(fnfe, fnfe); } catch (IOException ioe) { logger.error(ioe, ioe); } catch (Exception e) { logger.error(e, e); } finally { try { if (writer != null) { writer.close(); } } catch (IOException ioe) { logger.debug(ioe, ioe); } } } /** * Creates a mapfile with the layer information stored in <i>layers</i>. * * @param layers Layer information. */ protected void writeMapfile(List<String> layers) { String tmpMapName = "mapfile" + new Date().getTime(); File mapfile = new File( FLYSUtils.getXPathString(FLYSUtils.XPATH_MAPFILE_PATH)); File tmp = null; Writer writer = null; try { tmp = new File(mapfile.getParent(), tmpMapName); tmp.createNewFile(); writer = new FileWriter(tmp); VelocityContext context = getVelocityContext(); context.put("LAYERS", layers); 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(mapfile); } catch (FileNotFoundException fnfe) { logger.error(fnfe, fnfe); } catch (IOException ioe) { logger.error(ioe, ioe); } catch (Exception e) { logger.error(e, e); } finally { try { if (writer != null) { writer.close(); } 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 :