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>();
+        }
+
+}

http://dive4elements.wald.intevation.org