Mercurial > dive4elements > gnv-client
view gnv-artifacts/src/main/java/de/intevation/gnv/state/profile/horizontalcrosssection/HorizontalCrossSectionMeshOutputState.java @ 631:f4331a0df032
Chart and histogram output are working without using a cache.
gnv-artifacts/trunk@710 c6561f87-3c4e-4783-a992-168aeb5c3f6f
author | Ingo Weinzierl <ingo.weinzierl@intevation.de> |
---|---|
date | Thu, 25 Feb 2010 08:23:46 +0000 |
parents | 65f09139e9b3 |
children | 8d2bd52f05e3 |
line wrap: on
line source
package de.intevation.gnv.state.profile.horizontalcrosssection; import com.vividsolutions.jts.geom.Coordinate; import com.vividsolutions.jts.geom.Envelope; import com.vividsolutions.jts.geom.MultiLineString; import com.vividsolutions.jts.geom.MultiPolygon; import com.vividsolutions.jts.geom.Polygon; import de.intevation.artifactdatabase.Config; import de.intevation.artifactdatabase.XMLUtils; import de.intevation.artifacts.ArtifactNamespaceContext; import de.intevation.artifacts.CallContext; import de.intevation.gnv.artifacts.cache.CacheFactory; import de.intevation.gnv.artifacts.context.GNVArtifactContext; import de.intevation.gnv.geobackend.base.Result; import de.intevation.gnv.geobackend.base.ResultDescriptor; import de.intevation.gnv.geobackend.base.query.QueryExecutor; import de.intevation.gnv.geobackend.base.query.QueryExecutorFactory; import de.intevation.gnv.geobackend.base.query.exception.QueryException; import de.intevation.gnv.geobackend.sde.datasources.RasterObject; import de.intevation.gnv.math.AreaInterpolation; import de.intevation.gnv.math.AttributedPoint2ds; import de.intevation.gnv.math.Point2d; import de.intevation.gnv.math.QueriedXYDepth; import de.intevation.gnv.raster.ExternalIndexConverter; import de.intevation.gnv.raster.IsoAttributeGenerator; import de.intevation.gnv.raster.JTSMultiLineStringProducer; import de.intevation.gnv.raster.JTSMultiPolygonProducer; import de.intevation.gnv.raster.Palette; import de.intevation.gnv.raster.PaletteManager; import de.intevation.gnv.raster.Raster; import de.intevation.gnv.raster.Vectorizer; import de.intevation.gnv.state.InputData; import de.intevation.gnv.state.OutputStateBase; import de.intevation.gnv.state.exception.StateException; import de.intevation.gnv.utils.FileUtils; import de.intevation.gnv.utils.MapfileGenerator; import de.intevation.gnv.utils.Pair; import de.intevation.gnv.utils.ShapeFileWriter; import de.intevation.gnv.utils.StringUtils; import de.intevation.gnv.utils.WKTUtils; import de.intevation.gnv.wms.LayerInfo; import java.awt.Dimension; import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; import java.util.ArrayList; import java.util.Collection; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; import org.apache.log4j.Logger; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; /** * @author Tim Englich (tim.englich@intevation.de) * @author Sascha L. Teichmann (sascha.teichmann@intevation.de) * @author Ingo Weinzierl (ingo.weinzierl@intevation.de) */ public class HorizontalCrossSectionMeshOutputState extends OutputStateBase { private static Logger log = Logger .getLogger(HorizontalCrossSectionMeshOutputState.class); /** * The UID of this Class */ private static final long serialVersionUID = 3233620652465061860L; public static final boolean USE_INDEX_BUFFER = Boolean.getBoolean("gnv.horizontal.cross.section.mesh.index.buffer"); public static final String META_FILE_NAME = "meta.xml"; public static final String ISOLINES_NAME = "isolines.shp"; public static final String POLYGON_NAME = "polygons.shp"; public static final String LAYER_MODEL = "horizontalcrosssection"; private String ijkQueryID; private Boolean shapeFileLock = new Boolean(true); private String shapeFilePath; /** * Constructor */ public HorizontalCrossSectionMeshOutputState() { } public void initialize(String uuid, CallContext callContext) throws StateException { super.initialize(uuid, callContext); if (log.isDebugEnabled()) { log.debug("initialize output state " + uuid); } // fill the cache getResult(uuid, callContext); } public String getShapeFilePath() { synchronized (shapeFileLock) { return shapeFilePath; } } public void setShapeFilePath(String shapeFilePath) { synchronized (shapeFileLock) { this.shapeFilePath = shapeFilePath; } } public String resetShapeFilePath() { synchronized (shapeFileLock) { String path = shapeFilePath; shapeFilePath = null; return path; } } public void endOfLife(Object globalContext) { super.endOfLife(globalContext); // do it in background new Thread() { public void run() { // TODO: Do the un-publishing WMS stuff. String path = resetShapeFilePath(); if (path == null) { return; } File dir = new File(path); for (int i = 0; i < 10; ++i) { if (!dir.exists() || FileUtils.deleteRecursive(dir)) { MapfileGenerator.getInstance().update(); return; } try { Thread.sleep(10000L); } catch (InterruptedException ie) { } } log.error("failed to remove directory '" + path + "'"); } // run }.start(); } public void out( Document format, Collection<InputData> inputData, OutputStream outputStream, String uuid, CallContext callContext ) throws StateException { String outputMode = XMLUtils.xpathString( format, XPATH_OUTPUT_MODE, ArtifactNamespaceContext.INSTANCE); if (outputMode == null) { throw new StateException("cannot find outputMode or mime"); } outputMode = outputMode.toLowerCase(); if (log.isDebugEnabled()) { log.debug("---- asking for: " + outputMode); } if ("zip".equals(outputMode)) { writeZip(uuid, callContext, outputStream); } else if ("wms".equals(outputMode)) { XMLUtils.toStream( getWMS(uuid, callContext), outputStream); } else if ("statistics".equals(outputMode)) { // TODO: REMOVE THIS! try { outputStream.write("<fake/>\n".getBytes()); } catch (IOException ioe) {} } else { throw new StateException("unsupported output mode"); } } protected void writeZip( String uuid, CallContext callContext, OutputStream output ) throws StateException { try { String p = getShapeFilePath(); if (p != null) { File dir = new File(p); if (dir.isDirectory()) { FileUtils.createZipArchive(dir, output); } } else { AttributedPoint2ds result = getResult(uuid, callContext); if (result != null && (p = writeToShapeFile(uuid, result, callContext)) != null) { FileUtils.createZipArchive(new File(p), output); } } } catch (IOException ioe) { log.error(ioe.getLocalizedMessage(), ioe); } } protected Document getWMS(String uuid, CallContext callContext) throws StateException { // TODO: Do the real WMS publishing here! Document document = XMLUtils.newDocument(); Element pathElement = document.createElement("path"); document.appendChild(pathElement); String path = getShapeFilePath(); if (path != null && new File(path).isDirectory()) { pathElement.setTextContent(path); } else { AttributedPoint2ds result = getResult(uuid, callContext); if (result != null && (path = writeToShapeFile(uuid, result, callContext)) != null) { Document meta = null; if ((meta = writeMeta(callContext, uuid, path)) != null) { MapfileGenerator.getInstance().update(); return meta; } pathElement.setTextContent(path); } } return document; } protected String writeToShapeFile( String uuid, AttributedPoint2ds result, CallContext callContext ) { File baseDir = shapefileDirectory(callContext); File shapeDir = new File(baseDir, uuid); boolean success = false; boolean createdDir = false; try { synchronized (shapeFileLock) { int count = 0; while (shapeDir.exists()) { shapeDir = new File(baseDir, uuid + "-" + count); ++count; } if (!shapeDir.mkdirs()) { log.error("cannot create directory '" + shapeDir.getAbsolutePath() + "'"); return null; } createdDir = true; } Map<Integer, MultiPolygon> polygons = result.getPolygons(); List<Pair<Object, MultiLineString>> isolines = result.getLineStrings(); File polygonsFile = new File(shapeDir, POLYGON_NAME); File isolinesFile = new File(shapeDir, ISOLINES_NAME); if (!ShapeFileWriter.writeMultiPolygonsToFile( polygonsFile, (Integer)result.getAttribute("parameter"), (Integer)result.getAttribute("layer"), (Date) result.getAttribute("date"), polygons) ) { log.error("writing polygons failed"); return null; } if (!ShapeFileWriter.writeMultiLineStringsToFile( isolinesFile, (Integer)result.getAttribute("parameter"), (Integer)result.getAttribute("layer"), (Date) result.getAttribute("date"), isolines) ) { log.error("writing isolines failed"); return null; } shapeFilePath = shapeDir.getAbsolutePath(); success = true; callContext.afterCall(CallContext.STORE); return shapeFilePath; } finally { if (!success && createdDir) { FileUtils.deleteRecursive(shapeDir); } } } protected Document writeMeta(CallContext context, String uuid, String path){ InputData inputParam = inputData.get("parameterid"); Map<Integer, PaletteManager> paletteManagers = getPalettes(context); String paramType = null; if (inputParam == null || paletteManagers == null) { log.warn("Parameter-id not found."); paramType = LAYER_MODEL; } else { Integer parameterId = Integer.parseInt(inputParam.getValue()); PaletteManager paletteManager = paletteManagers.get(parameterId); paramType = LAYER_MODEL + "_" + paletteManager.getName(); } Document meta = XMLUtils.newDocument(); XMLUtils.ElementCreator creator = new XMLUtils.ElementCreator( meta, ArtifactNamespaceContext.NAMESPACE_URI, ArtifactNamespaceContext.NAMESPACE_PREFIX); Element root = creator.create("meta"); meta.appendChild(root); writePolygonMeta(context, meta, root, uuid, path, paramType); writeIsolineMeta(context, meta, root, uuid, path, paramType); try { File metaFile = new File(path, META_FILE_NAME); if (!metaFile.createNewFile() || !metaFile.canWrite()) { log.error("Error while writing meta file: "+metaFile.toString()); return null; } OutputStream out = null; boolean success = false; try { out = new FileOutputStream(metaFile); success = XMLUtils.toStream(meta, out); } finally { if (out != null) { try { out.close(); } catch (IOException ioe) {} } } if (!success && metaFile.exists()) { metaFile.delete(); } return success ? meta : null; } catch (FileNotFoundException fnfe) { log.error(fnfe); } catch (IOException ioe) { log.error(ioe, ioe); } return meta; } protected void writePolygonMeta( CallContext context, Document document, Element meta, String uuid, String path, String paramType ) { XMLUtils.ElementCreator creator = new XMLUtils.ElementCreator( document, ArtifactNamespaceContext.NAMESPACE_URI, ArtifactNamespaceContext.NAMESPACE_PREFIX); Element layer = creator.create(LayerInfo.LAYER); Element model = creator.create(LayerInfo.LAYER_MODEL); Element name = creator.create(LayerInfo.LAYER_NAME); Element type = creator.create(LayerInfo.LAYER_TYPE); Element status = creator.create(LayerInfo.LAYER_STATUS); Element data = creator.create(LayerInfo.LAYER_DATA); model.setTextContent(paramType); name.setTextContent(uuid); type.setTextContent("POLYGON"); status.setTextContent("DEFAULT"); data.setTextContent(POLYGON_NAME); layer.appendChild(model); layer.appendChild(name); layer.appendChild(type); layer.appendChild(status); layer.appendChild(data); meta.appendChild(layer); } protected void writeIsolineMeta( CallContext context, Document document, Element meta, String uuid, String path, String paramType ) { XMLUtils.ElementCreator creator = new XMLUtils.ElementCreator( document, ArtifactNamespaceContext.NAMESPACE_URI, ArtifactNamespaceContext.NAMESPACE_PREFIX); Element layer = creator.create(LayerInfo.LAYER); Element model = creator.create(LayerInfo.LAYER_MODEL); Element name = creator.create(LayerInfo.LAYER_NAME); Element type = creator.create(LayerInfo.LAYER_TYPE); Element status = creator.create(LayerInfo.LAYER_STATUS); Element data = creator.create(LayerInfo.LAYER_DATA); model.setTextContent(paramType+"_isolines"); name.setTextContent(uuid); type.setTextContent("LINE"); status.setTextContent("DEFAULT"); data.setTextContent(ISOLINES_NAME); layer.appendChild(model); layer.appendChild(name); layer.appendChild(type); layer.appendChild(status); layer.appendChild(data); meta.appendChild(layer); } protected AttributedPoint2ds getResult(String uuid, CallContext callContext) throws StateException { CacheFactory cf = CacheFactory.getInstance(); String key = uuid + super.getID(); if (cf.isInitialized()) { net.sf.ehcache.Element value = cf.getCache().get(key); if (value != null) { return (AttributedPoint2ds)value.getObjectValue(); } } AttributedPoint2ds result = produceResult(callContext); if (result != null && cf.isInitialized()) { cf.getCache().put(new net.sf.ehcache.Element(key, result)); } return result; } protected AttributedPoint2ds produceResult(CallContext callContext) throws StateException { InputData meshPolygon = inputData.get("mesh_polygon"); InputData meshId = inputData.get("meshid"); if (meshPolygon == null) { log.error("mesh_polygon is not defined"); throw new StateException("missing mesh_linestring"); } if (meshId == null) { log.error("meshid is not defined"); throw new StateException("missing meshid"); } Polygon p = WKTUtils.toPolygon(meshPolygon.getValue()); if (p == null) { log.error("no valid polygon"); throw new StateException("no valid polygon"); } try { Envelope env = p.getEnvelopeInternal(); String additionWhere; if (USE_INDEX_BUFFER) { Coordinate [] coords = new Coordinate [] { new Coordinate(env.getMinX(), env.getMinY()), new Coordinate(env.getMinX(), env.getMaxY()), new Coordinate(env.getMaxX(), env.getMaxY()), new Coordinate(env.getMaxX(), env.getMinY()) }; additionWhere = WKTUtils.worldEnvelopeCoordinatesToIndex( coords, meshId.getValue(), ijkQueryID); } else { additionWhere = WKTUtils.TRUE_EXPRESSION; } String[] addedFilterValues = StringUtils.append( generateFilterValuesFromInputData(), additionWhere); QueryExecutor queryExecutor = QueryExecutorFactory .getInstance() .getQueryExecutor(); return process( env, p, callContext, preProcess( queryExecutor.executeQuery( queryID, addedFilterValues))); } catch (QueryException e) { log.error(e,e); } throw new StateException("no result produced"); } public AttributedPoint2ds preProcess(Collection<Result> results) { boolean debug = log.isDebugEnabled(); if (debug) { log.debug("--- preProcess: " + results.size() + " results"); } AttributedPoint2ds ap2ds = new AttributedPoint2ds(); ArrayList<Point2d> points = new ArrayList<Point2d>(results.size()); int sIdx = -1; int iIdx = -1; int jIdx = -1; int vIdx = -1; boolean firstWarn = true; for (Result result: results) { if (sIdx == -1) { ResultDescriptor rd = result.getResultDescriptor(); sIdx = rd.getColumnIndex("SHAPE"); iIdx = rd.getColumnIndex("IPOSITION"); jIdx = rd.getColumnIndex("JPOSITION"); vIdx = rd.getColumnIndex("YORDINATE"); int kIdx = rd.getColumnIndex("KPOSITION"); int tIdx = rd.getColumnIndex("TIMEVALUE"); int pIdx = rd.getColumnIndex("PARAMETERID"); if (sIdx == -1 || iIdx == -1 || jIdx == -1 || kIdx == -1 || vIdx == -1 || tIdx == -1 || pIdx == -1 ) { log.error("missing column in result set"); return null; } ap2ds.setAttribute("date", result.getDate(tIdx)); ap2ds.setAttribute("parameter", result.getInteger(pIdx)); ap2ds.setAttribute("layer", result.getInteger(kIdx)); } Coordinate coord = WKTUtils.toCoordinate(result.getString(sIdx)); if (coord == null) { if (firstWarn) { firstWarn = false; log.warn("cannot fetch coordinate from result"); } continue; } double v = result.getDouble(vIdx); int i = result.getInteger(iIdx); int j = result.getInteger(jIdx); Point2d p2d = new Point2d(coord.x, coord.y, v, i, j); points.add(p2d); } ap2ds.setPoints(points); return ap2ds; } public AttributedPoint2ds process( Envelope boundingBox, Polygon polygon, CallContext callContext, AttributedPoint2ds input ) { if (input == null) { log.error("no data to interpolate"); return null; } Integer parameterId = (Integer)input.getAttribute("parameter"); // XXX: hardcoded if (parameterId == null) { log.error("missing parameter id"); return null; } Map<Integer, PaletteManager> paletteManagers = getPalettes(callContext); PaletteManager paletteManager = paletteManagers.get(parameterId); if (paletteManager == null) { log.error("no palette found for parameter id " + parameterId); return null; } boolean debug = log.isDebugEnabled(); if (debug) { log.debug("interpolation"); } AreaInterpolation interpolation = new AreaInterpolation(); int numSamples = numSamples(callContext); int groundInterpolation = getGroundInterpolation(callContext); int extrapolationRounds = extrapolationRounds(callContext); if (!interpolation.interpolate( input.getPoints(), boundingBox, new Dimension(numSamples, numSamples), new QueriedXYDepth(groundInterpolation), extrapolationRounds )) { log.error("interpolation failed"); return null; } // Do the post processing Raster raster = new Raster( interpolation.getRaster(), numSamples); // TODO: Filter operations. if (debug) { log.debug("to indexed raster"); } // scan for regions with base palette Palette basePalette = paletteManager.getBase(); int [] intRaster = raster.toIndexed(basePalette); // produce JFreeChart compatible polygons if (debug) { log.debug("vectorize indexed raster"); } // produce JTS compatible polygons JTSMultiPolygonProducer jtsmpp = new JTSMultiPolygonProducer( polygon, boundingBox.getMinX(), boundingBox.getMinY(), boundingBox.getMaxX(), boundingBox.getMaxY()); int numRegions = new Vectorizer(intRaster, numSamples) .process(jtsmpp); Map<Integer, MultiPolygon> polygons = jtsmpp.getMultiPolygons( new ExternalIndexConverter(basePalette)); jtsmpp.clear(); jtsmpp = null; // help gc int numColors = polygons.size(); if (debug) { log.debug("number of regions: " + numRegions); log.debug("number of colors: " + numColors); } // generate iso lines int numIso; if (numColors < 5) { numIso = 5; } else if (numColors < 10) { numIso = 2; } else { numIso = 0; } Palette isoPalette; if (numIso == 0) { // same palette isoPalette = basePalette; /* intRaster = intRaster; */ } else { isoPalette = paletteManager.getLevel(numIso); intRaster = raster.toIndexed(isoPalette); } JTSMultiLineStringProducer jtslsp = new JTSMultiLineStringProducer( polygon, boundingBox.getMinX(), boundingBox.getMinY(), boundingBox.getMaxX(), boundingBox.getMaxY()); numRegions = new Vectorizer(false, intRaster, numSamples) .process(jtslsp); IsoAttributeGenerator iag = new IsoAttributeGenerator(isoPalette); List<Pair<Object, MultiLineString>> lineStrings = jtslsp.getMultiLineStrings(iag); jtslsp.clear(); jtslsp = null; // help gc input.setInterpolation(interpolation); input.setPolygons(polygons); input.setLineStrings(lineStrings); return input; } @Override public void setup(Node configuration) { super.setup(configuration); this.ijkQueryID = Config.getStringXPath(configuration,"queryID-ijk"); } private static int numSamples(CallContext callContext) { GNVArtifactContext context = (GNVArtifactContext)callContext.globalContext(); Integer samples = (Integer)context.get( GNVArtifactContext.HORIZONTAL_CROSS_SECTION_SAMPLES_KEY); return samples != null ? samples.intValue() : GNVArtifactContext.DEFAULT_HORIZONTAL_CROSS_SECTION_SAMPLES; } private static int extrapolationRounds(CallContext callContext) { GNVArtifactContext context = (GNVArtifactContext)callContext.globalContext(); Integer extrapolationRounds = (Integer)context.get( GNVArtifactContext.HORIZONTAL_CROSS_SECTION_EXTRAPOLATION_ROUNDS_KEY); return extrapolationRounds != null ? extrapolationRounds.intValue() : GNVArtifactContext.DEFAULT_HORIZONTAL_CROSS_SECTION_EXTRAPOLATION_ROUNDS; } private static File shapefileDirectory(CallContext callContext) { GNVArtifactContext context = (GNVArtifactContext)callContext.globalContext(); File dir = (File)context.get( GNVArtifactContext.HORIZONTAL_CROSS_SECTION_RESULT_SHAPEFILE_PATH_KEY); return dir != null ? dir : GNVArtifactContext.DEFAULT_HORIZONTAL_CROSS_SECTION_PROFILE_SHAPEFILE_PATH; } private static int getGroundInterpolation(CallContext callContext) { GNVArtifactContext context = (GNVArtifactContext)callContext.globalContext(); String interpolation = (String)context.get( GNVArtifactContext.HORIZONTAL_CROSS_SECTION_GROUND_INTERPOLATION_KEY); return RasterObject.getInterpolationType(interpolation); } private static Map<Integer, PaletteManager> getPalettes( CallContext callContext ) { GNVArtifactContext context = (GNVArtifactContext)callContext.globalContext(); Map<Integer, PaletteManager> palettes = (Map<Integer, PaletteManager>)context.get( GNVArtifactContext.PALETTES_KEY); return palettes != null ? palettes : new HashMap<Integer, PaletteManager>(); } } // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :