Mercurial > dive4elements > gnv-client
diff gnv-artifacts/src/main/java/de/intevation/gnv/state/layer/LayerOutputState.java @ 657:af3f56758f59
merged gnv-artifacts/0.5
author | Thomas Arendsen Hein <thomas@intevation.de> |
---|---|
date | Fri, 28 Sep 2012 12:13:53 +0200 |
parents | 6eccb68a8b99 |
children | 199982e8866e |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gnv-artifacts/src/main/java/de/intevation/gnv/state/layer/LayerOutputState.java Fri Sep 28 12:13:53 2012 +0200 @@ -0,0 +1,412 @@ +/** + * + */ +package de.intevation.gnv.state.layer; + +import java.io.File; +import java.io.IOException; +import java.io.OutputStream; +import java.util.Collection; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; + +import org.apache.log4j.Logger; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; + +import com.vividsolutions.jts.geom.Geometry; +import com.vividsolutions.jts.io.ParseException; +import com.vividsolutions.jts.io.WKTReader; + +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.context.GNVArtifactContext; +import de.intevation.gnv.geobackend.base.Result; +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.raster.PaletteManager; +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.MetaWriter; +import de.intevation.gnv.utils.ShapeFileWriter; + +/** + * @author Tim Englich <tim.englich@intevation.de> + * + */ +public class LayerOutputState extends OutputStateBase { + + /** + * the logger, used to log exceptions and additonaly information + */ + private static Logger log = Logger.getLogger(LayerOutputState.class); + + /** + * The UID of this Class. + */ + private static final long serialVersionUID = 9180957321704424049L; + + // TODO: Replace + public static final String LAYER_MODEL = "layer"; + + /** + * The ID for the Query fetching the Layer from the DB + */ + private String dataQueryID = null; + + /** + * The ID for the Query fetching the Geometry from the DB + * which should be used to Clip the Layerdata + */ + private String geometryQueryID = null; + + /** + * The ID for the Value which will hold the Geometrie-Value + */ + private String geometryID = null; + + private Boolean shapeFileLock = new Boolean(true); + + private String shapeFilePath; + + private String geometryType = null; + + public static final String SHAPEFILE_NAME = "data.shp"; + + /** + * Constructor + */ + public LayerOutputState() { + super(); + } + + /** + * @see de.intevation.gnv.state.OutputState#out(org.w3c.dom.Document, + * java.util.Collection, java.io.OutputStream, + * java.lang.String, de.intevation.artifacts.CallContext) + */ + public void out(Document format, Collection<InputData> inputData, + OutputStream outputStream, String uuid, + CallContext callContext) throws StateException { + + log.debug("LayerOutputState.out"); + String outputMode = XMLUtils.xpathString( + format, XPATH_OUTPUT_MODE, ArtifactNamespaceContext.INSTANCE); + if (outputMode.equalsIgnoreCase("wms")) { + Collection<Result> data = this.fetchData(); + XMLUtils.toStream(this.getWMS(uuid, callContext, data),outputStream); + }else if (outputMode.equalsIgnoreCase("zip")){ + Collection<Result> data = this.fetchData(); + this.writeZip(uuid, callContext, outputStream, data); + } + } + + + /** + * Fetches the Data from the Databasebackend + * @return + */ + protected Collection<Result> fetchData(){ + log.debug("LayerOutputState.fetchData"); + // TODO PUT ALL in CACHE + Collection<Result> result = this.getData(this.queryID); + Collection<Result> data = null; + String geometryWKT = null; + if (result != null){ + QueryExecutor queryExecutor = QueryExecutorFactory.getInstance() + .getQueryExecutor(); + Iterator<Result> it = result.iterator(); + String[] queryValues = null; + if (it.hasNext()){ + Result resultValue = it.next(); + String table = resultValue.getString(0); + String where = resultValue.getString(1); + if (this.geometryID != null){ + InputData geometryInputData = + this.inputData.get(this.geometryID); + if (geometryInputData != null){ + + try { + Collection<Result> geometryData = queryExecutor + .executeQuery(this.geometryQueryID, + new String[]{geometryInputData.getValue()}); + Iterator<Result> git = geometryData.iterator(); + if (git.hasNext()){ + Result geometryValue = git.next(); + geometryWKT = geometryValue.getString(0); + } + } catch (QueryException e) { + log.error(e,e); + // TODO: what should happen?? + } + queryValues = new String[]{table, + where, + geometryWKT}; + }else{ + // TODO: Look into the presetting for an WKT + queryValues = new String[]{table,where}; + } + }else{ + // TODO: Look into the presetting for an WKT + queryValues = new String[]{table,where}; + + } + } + + try { + data = queryExecutor.executeQuery(dataQueryID, + queryValues); + if (data != null && geometryWKT != null){ + WKTReader wktReader = new WKTReader(); + Geometry border = wktReader.read(geometryWKT); + + Iterator<Result> dataIt = data.iterator(); + while (dataIt.hasNext()){ + // Trim the Geometries using the + // Geometry if on is available. + Result current = dataIt.next(); + String currentWKT = current.getString(0); + Geometry currentGeometry = null; + try { + currentGeometry = wktReader.read(currentWKT); + } catch (Exception e) { + log.error("Error parsing Geometry "+ currentWKT); + log.error(e,e); + } + + if (currentGeometry != null){ + Geometry newGeometry = currentGeometry.intersection(border); + current.addColumnValue(0, newGeometry.toText()); + } + } + } + } catch (QueryException e) { + log.error(e,e); + } catch (ParseException e){ + log.error(e,e); + } + } + return data; + } + + @Override + public void setup(Node configuration) { + log.debug("LayerOutputState.setup"); + super.setup(configuration); + this.dataQueryID = Config.getStringXPath(configuration, + "queryID-layerdata"); + this.geometryID = Config.getStringXPath(configuration, + "inputvalue-geometry"); + this.geometryQueryID = Config.getStringXPath(configuration, + "queryID-geometry"); + } + + protected String writeToShapeFile( + String uuid, + Collection<Result> data, + 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; + } + + File shapeFile = new File(shapeDir, SHAPEFILE_NAME); + if ((geometryType = ShapeFileWriter.writeDataToFile(shapeFile, "data", data)) == null){ + log.error("writing data into shapefile failed"); + return null; + } + + shapeFilePath = shapeDir.getAbsolutePath(); + success = true; + + callContext.afterCall(CallContext.STORE); + + return shapeFilePath; + } + finally { + if (!success && createdDir) { + FileUtils.deleteRecursive(shapeDir); + } + } + } + + protected void writeZip( + String uuid, + CallContext callContext, + OutputStream output, + Collection<Result> data + ) + throws StateException + { + try { + String p = getShapeFilePath(); + if (p != null) { + File dir = new File(p); + if (dir.isDirectory()) { + FileUtils.createZipArchive(dir, output); + } + } + else { + + if ((p = writeToShapeFile(uuid, data, callContext)) != null) { + FileUtils.createZipArchive(new File(p), output); + } + } + } + catch (IOException ioe) { + log.error(ioe.getLocalizedMessage(), ioe); + } + } + + public String getShapeFilePath() { + synchronized (shapeFileLock) { + return shapeFilePath; + } + } + + private static File shapefileDirectory(CallContext callContext) { + // TODO: Refactoring nessessary it should be used only one Shapefilepath + // for alle Modes. Code was taken from HorizontalCrossSectionMeshOutputState + 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; + } + + /** + * @see de.intevation.gnv.state.StateBase#endOfLife(java.lang.Object) + */ + @Override + 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 String resetShapeFilePath() { + synchronized (shapeFileLock) { + String path = shapeFilePath; + shapeFilePath = null; + geometryType = null; + return path; + } + } + protected Document getWMS(String uuid, + CallContext callContext, + Collection<Result> data) + 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 { + + if (data != null && + (path = writeToShapeFile(uuid, data, callContext)) != null) { + + String paramType = LAYER_MODEL+"_"+this.geometryType.toLowerCase(); + + Document meta = MetaWriter.writeLayerMeta(callContext, uuid, + path, paramType, + this.determineGeometryType()); + if (meta != null) { + MapfileGenerator.getInstance().update(); + return meta; + } + + pathElement.setTextContent(path); + } + } + + return document; + } + + private String determineGeometryType(){ + + String returnValue = this.geometryType.toLowerCase(); + + if (returnValue.equalsIgnoreCase("linestring")){ + returnValue = "Line"; + } + return returnValue; + } + + private static Map<Integer, PaletteManager> getPalettes( + CallContext callContext + ) { + //TODO: customize for product Layer + 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>(); + } + +}