diff gnv-artifacts/src/main/java/de/intevation/gnv/state/layer/LayerOutputState.java @ 859:3fbabd4803d7

ISSUE252 Make it possible to export more than one Layer gnv-artifacts/trunk@983 c6561f87-3c4e-4783-a992-168aeb5c3f6f
author Tim Englich <tim.englich@intevation.de>
date Mon, 26 Apr 2010 09:09:20 +0000
parents 164d102b0af5
children dfd02f8d3602
line wrap: on
line diff
--- a/gnv-artifacts/src/main/java/de/intevation/gnv/state/layer/LayerOutputState.java	Fri Apr 23 13:26:21 2010 +0000
+++ b/gnv-artifacts/src/main/java/de/intevation/gnv/state/layer/LayerOutputState.java	Mon Apr 26 09:09:20 2010 +0000
@@ -3,12 +3,12 @@
 import java.io.File;
 import java.io.IOException;
 import java.io.OutputStream;
+import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Iterator;
 
 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;
@@ -59,7 +59,7 @@
     /**
      * The Name of the Shapefile which will be generated.
      */
-    public static final String SHAPEFILE_NAME   = "data.shp";
+    public static final String SHAPEFILE_NAME   = "data";
 
     /**
      * The ID for the Query fetching the Layer from the DB
@@ -100,17 +100,6 @@
     private String shapeFilePath;
 
     /**
-     * The ID of the Template which should be used to generate the Layerentry
-     * in the Mapfile.
-     */
-    private String templateID = null;
-
-    /**
-     * The Kind of Geometry which should be used to generate the Shapefile.
-     */
-    private String geometryType = null;
-
-    /**
      * Constructor
      */
     public LayerOutputState() {
@@ -120,25 +109,27 @@
     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();
-            if (data != null && !data.isEmpty()){
+            
+            Collection<LayerMetaData> layerMetaData = 
+                                          this.getRequestedLayerMetadata();
+            if (layerMetaData != null && !layerMetaData.isEmpty()){
                 XMLUtils.toStream(this.getWMS(uuid, callContext,
-                                              data, geometryType,
-                                              inputData),
+                                              layerMetaData,inputData),
                                   outputStream);
             }else{
                 this.writeExceptionReport2Stream(outputStream);
             }
         }else if (outputMode.equalsIgnoreCase("zip")){
-            Collection<Result> data = this.fetchData();
-            if (data != null && !data.isEmpty()){
-                this.writeZip(uuid, callContext, outputStream,
-                              data,geometryType);
+            Collection<LayerMetaData> layerMetaData = 
+                this.getRequestedLayerMetadata();
+
+            if (layerMetaData != null && !layerMetaData.isEmpty()){
+                this.writeZip(uuid, callContext, 
+                              outputStream, layerMetaData);
             }else{
                 this.writeExceptionReport2Stream(outputStream);
             }
@@ -158,38 +149,35 @@
         XMLUtils.toStream(document,outputStream);
     }
 
-
     /**
-     * Fetches the Data from the Databasebackend.
-     *
-     * @return the resultdata.
+     * Returns the Metadata for the requested Layers for fetching the data 
+     * of the Layer and generating the Layer and WMS.
+     * @return the Metadata for the requested Layers
      */
-    protected Collection<Result> fetchData(){
-        log.debug("LayerOutputState.fetchData");
+    private Collection<LayerMetaData> getRequestedLayerMetadata(){
+        log.debug("LayerOutputState.getRequestedLayerMetadata");
         Collection<Result> result = this.getData(this.queryID);
-        Collection<Result> data = null;
-        String geometryWKT = null;
+        Collection<LayerMetaData> returnValue = null;
         if (result != null){
             QueryExecutor queryExecutor = QueryExecutorFactory.getInstance()
                                                               .getQueryExecutor();
             Iterator<Result> it = result.iterator();
-            String[] queryValues = null;
-            if (it.hasNext()){
+            returnValue = new ArrayList<LayerMetaData>(result.size());
+            while (it.hasNext()){
                 Result resultValue = it.next();
                 String table = resultValue.getString(0);
-
-                this.geometryType = this.getGeometryType(table, queryExecutor);
-
+                String geometryType = this.getGeometryType(table, queryExecutor);
                 String where = resultValue.getString(1);
                 String columns = this.fetchColumns(table);
-
-                templateID = resultValue.getString(2);
+                String templateID = resultValue.getString(2);
+                String[] queryValues = null;
+                String geometryWKT = null;
                 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()});
@@ -233,40 +221,54 @@
                         queryValues = new String[]{columns,table,where};
                     }
                 }
+                returnValue.add(new LayerMetaData(table, geometryType, 
+                                  where, columns, 
+                                  templateID, queryValues,
+                                  geometryWKT));
             }
-
-            try {
-                data  = queryExecutor.executeQuery(dataQueryID,
-                                                   queryValues);
-                if (data != null && geometryWKT != null){
-                    WKTReader wktReader = new WKTReader();
-                    Geometry border = wktReader.read(geometryWKT);
+        }
+        return returnValue;
+    }
 
-                    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());
-                        }
+    /**
+     * Fetches the Data from the Databasebackend.
+     *
+     * @return the resultdata.
+     */
+    protected Collection<Result> fetchData(LayerMetaData layerMetaData){
+        log.debug("LayerOutputState.fetchData");
+        Collection<Result> data = null;
+        QueryExecutor queryExecutor = QueryExecutorFactory.getInstance()
+                                                           .getQueryExecutor();
+        try {
+            data  = queryExecutor.executeQuery(dataQueryID,
+                                               layerMetaData.getQueryValues());
+            if (data != null && layerMetaData.getGeometryWKT() != null){
+                WKTReader wktReader = new WKTReader();
+                Geometry border = wktReader.read(layerMetaData.getGeometryWKT());
+                Iterator<Result> dataIt = data.iterator();
+                while (dataIt.hasNext()){
+                    // Trim the Geometries using the
+                    // Geometry if one 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);
             }
+        } catch (QueryException e) {
+            log.error(e,e);
+        } catch (ParseException e){
+            log.error(e,e);
         }
         return data;
     }
@@ -284,7 +286,6 @@
         String returnValue = null;
         String[] tables = tableName.toUpperCase().split(",");
         String[] filter = tables[0].split("\\.");
-
         try {
             Collection<Result> result =
                 queryExecutor.executeQuery(this.geometryTypeQueryID, filter);
@@ -316,7 +317,6 @@
         } catch (QueryException e) {
             log.error(e,e);
         }
-
         return returnValue;
     }
 
@@ -334,8 +334,7 @@
             String[] filter = tables[0].split("\\.");
             // Only use the first Table the second one will be ignored.
             QueryExecutor queryExecutor = QueryExecutorFactory.getInstance()
-            .getQueryExecutor();
-
+                                                            .getQueryExecutor();
             Collection<Result> columnData = queryExecutor.
                                                 executeQuery(this.columnQueryID,
                                                              filter);
@@ -353,7 +352,6 @@
                 }
                 returnValue = sb.toString();
             }
-
         } catch (QueryException e) {
             log.error(e,e);
         }
@@ -391,47 +389,57 @@
                                       String             uuid,
                                       Collection<Result> data,
                                       CallContext        callContext,
-                                      String geometryType
+                                      String geometryType,
+                                      int layerNumber
                                   ) {
-        File baseDir = shapefileDirectory(callContext);
-
-        File shapeDir = new File(baseDir, uuid);
         boolean success    = false;
-        boolean createdDir = false;
-
-        try {
-            synchronized (shapeFileLock) {
-                if (shapeDir.exists()) {
-                    FileUtils.deleteContent(shapeDir);
-                }
-                else if (!shapeDir.mkdirs()) {
-                    log.error("cannot create directory '"
-                        + shapeDir.getAbsolutePath() + "'");
+        if (data != null && !data.isEmpty()){
+            File shapeDir = new File(shapeFilePath);
+            try {
+                File shapeFile = new File(shapeDir, createShapeFileName(layerNumber));
+                if (!ShapeFileWriter.writeDataToFile(shapeFile, "data", data,geometryType)){
+                    log.error("writing data into shapefile failed");
                     return null;
                 }
-                createdDir = true;
-            }
-
-            File shapeFile = new File(shapeDir, SHAPEFILE_NAME);
-            if (!ShapeFileWriter.writeDataToFile(shapeFile, "data", data,geometryType)){
-                log.error("writing data into shapefile failed");
-                return null;
+                success = true;
+                callContext.afterCall(CallContext.STORE);
+                return shapeFilePath;
             }
-
-            shapeFilePath = shapeDir.getAbsolutePath();
-            success = true;
-
-            callContext.afterCall(CallContext.STORE);
-
-            return shapeFilePath;
-        }
-        finally {
-            if (!success && createdDir) {
-                FileUtils.deleteRecursive(shapeDir);
+            finally {
+                if (!success) {
+                    FileUtils.deleteRecursive(shapeDir);
+                }
             }
+        }else{
+            return null;
         }
     }
 
+    /**
+     * Check if the ShapeDir exists and if it exists delete all Contents
+     * in it. If it not exists the Director will be created.
+     * @param baseDir the BaseDirectory for all ShapeDirs
+     * @param uuid the UUID  which is used to create the Directory
+     * @return true if the directory exists or could be created. 
+     *         false if the directory could not be created.
+     */
+    private boolean createShapeDir(File baseDir, String uuid){
+        File shapeDir = new File(baseDir, uuid);
+        boolean createdDir = false;
+        synchronized (shapeFileLock) {
+            if (shapeDir.exists()) {
+                FileUtils.deleteContent(shapeDir); // TODO Place on getZip and getWMS
+            }
+            else if (!shapeDir.mkdirs()) {
+                log.error("cannot create directory '"
+                    + shapeDir.getAbsolutePath() + "'");
+                return false;
+            }
+            createdDir = true;
+        }
+        shapeFilePath = shapeDir.getAbsolutePath();
+        return createdDir;
+    }
 
     /**
      * Create a zip archive with the shapefiles of the given shapefiles path and
@@ -448,8 +456,7 @@
             String       uuid,
             CallContext  callContext,
             OutputStream output,
-            Collection<Result> data,
-            String geometryType
+            Collection<LayerMetaData> layerMetaData
         )
         throws StateException
         {
@@ -462,8 +469,18 @@
                     }
                 }
                 else {
-
-                    if ((p = writeToShapeFile(uuid, data, callContext,geometryType)) != null) {
+                    File baseDir = shapefileDirectory(callContext);
+                    if (!this.createShapeDir(baseDir, uuid)){
+                        return;
+                    }
+                    Iterator<LayerMetaData> it = layerMetaData.iterator();
+                    int i = 1;
+                    while(it.hasNext()){
+                        LayerMetaData lmd = it.next();
+                        Collection<Result> data = this.fetchData(lmd);
+                        p = writeToShapeFile(uuid, data, callContext,lmd.getGeometryType(),i++);
+                    }
+                    if (p != null) {
                         FileUtils.createZipArchive(new File(p), output);
                     }
                 }
@@ -484,10 +501,15 @@
         }
     }
 
-
+    /**
+     * Returns the basic-directory where the Shapefiles should be placed in.
+     * @param callContext the Context of this Call
+     * @return the Directory where the Shapefiles could be placed in.
+     *         (Please create an own directory in this dir and not put the
+     *          Files directly in it)
+     */
     private static File shapefileDirectory(CallContext callContext) {
-        // TODO: Refactoring nessessary it should be used only one Shapefilepath
-        //       for alle Modes. Code was taken from HorizontalCrossSectionMeshOutputState
+        // Code was taken from HorizontalCrossSectionMeshOutputState
         GNVArtifactContext context =
             (GNVArtifactContext)callContext.globalContext();
         File dir = (File)context.get(
@@ -501,25 +523,20 @@
     @Override
     public void endOfLife(Object globalContext) {
         super.endOfLife(globalContext);
-
         // do it in background
         new Thread() {
             @Override
             public void run() {
                 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);
                     }
@@ -540,7 +557,6 @@
         synchronized (shapeFileLock) {
             String path = shapeFilePath;
             shapeFilePath = null;
-            templateID = null;
             return path;
         }
     }
@@ -553,8 +569,8 @@
      *
      * @param uuid The UUID of the current artifact.
      * @param callContext The CallContext object.
-     * @param data A collection with some input data.
-     * @param geometryType The geometry type.
+     * @param layerMetaData The Metadata which is required to create the
+     *                      different Layers.
      * @param inputData the Parameters which are send by the out-Call.
      * @return a document with some meta information (shapefile path, geometry
      * type, time to live of the current artifact, etc).
@@ -562,72 +578,125 @@
      */
     protected Document getWMS(String uuid,
                               CallContext callContext,
-                              Collection<Result> data,
-                              String geometryType,
+                              Collection<LayerMetaData> layerMetaData,
                               Collection<InputData> inputData)
     throws StateException
     {
-        Document document = XMLUtils.newDocument();
+        String path = getShapeFilePath();
+        if (path != null &&  new File(path).isDirectory()){
+            return this.refreshMetaFile(layerMetaData, inputData, 
+                                        uuid, callContext);
+        }else{
+            Document document = XMLUtils.newDocument();
+            if (this.shapeFilePath == null){
+                File baseDir = shapefileDirectory(callContext);
+                if (!this.createShapeDir(baseDir, uuid)){
+                    // TODO Insert Error Report
+                    return document;
+                }
+            }
+            path = getShapeFilePath();
+            Iterator<LayerMetaData> it = layerMetaData.iterator();
+            Node meta = null;
+            int layerNumber = 0;
+            while (it.hasNext()){
+                LayerMetaData lmd = it.next();
+                layerNumber ++;
+                String geometryType = lmd.getGeometryType();
+                String templateId = lmd.getTemplateID();
+                ExclusiveExec.UniqueKey key = ExclusiveExec.INSTANCE.acquire(uuid);
+                try{
+                    Collection<Result> data = this.fetchData(lmd);
+                    if (data != null &&
+                        (this.writeToShapeFile(uuid, data, callContext,
+                                                 geometryType,layerNumber)) != null) {
+                        String paramType = findParameterTitle(geometryType,templateId);
+                        String    title      = getLayerTitle(inputData);
+                        if (title == null) {
+                            title = uuid+"_"+layerNumber;
+                        }else{
+                            title = title+"_"+layerNumber;
+                        }
+                        if (meta == null){
+                            meta = MetaWriter.writeLayerMeta(callContext,document);
+                        }
+                        MetaWriter.writeLayerMeta(callContext, document, 
+                                                  meta, uuid, paramType, 
+                                                  this.determineGeometryType(geometryType),
+                                                  createShapeFileName(layerNumber),
+                                                  title);
+                    }
+                    if (meta != null && !it.hasNext()) {
+                        MetaWriter.writeMetaFile(path,document);
+                        MapfileGenerator.getInstance().update();
+                        return document;
+                    }
+                }finally{
+                    ExclusiveExec.INSTANCE.release(key);
+                }
+            }
+            return document;
+        }
+    }
 
-        Element pathElement = document.createElement("path");
-        document.appendChild(pathElement);
+    /**
+     * Creates the name of the Shapefile
+     * @param layerNumber the Number of the Layer
+     * @return the create name of the Shapefile.
+     */
+    private String createShapeFileName(int layerNumber) {
+        return SHAPEFILE_NAME+"_"+layerNumber+".shp";
+    }
 
-        String path = getShapeFilePath();
-
-        if (path != null && new File(path).isDirectory()) {
+    /**
+     * Method that refreshes the Metadatafile for publishing the WMS
+     * Without generating the Data ones again.
+     * @param layerMetaData the Metadata which is required to create the Layers
+     * @param inputData the Inputdata which was sent by the Client
+     * @param uuid the uuid of the Artifact
+     * @param callContext the context of this Call
+     * @return a refreshed Metadata-Document
+     */
+    private Document refreshMetaFile(Collection<LayerMetaData> layerMetaData,
+                                     Collection<InputData> inputData,
+                                     String uuid,
+                                     CallContext callContext){
+        Document document = XMLUtils.newDocument();
+        Node meta = null;
+        int layerNumber = 0;
+        Iterator<LayerMetaData> it = layerMetaData.iterator();
+        while (it.hasNext()){
+            LayerMetaData lmd = it.next();
+            layerNumber ++;
+            String geometryType = lmd.getGeometryType();
+            String templateId = lmd.getTemplateID();
             String title = getLayerTitle(inputData);
             if (title == null) {
-                title = uuid;
+                title = uuid+"_"+layerNumber;
+            }else{
+                title = title+"_"+layerNumber;
             }
-
             callContext.putContextValue(
                 MetaWriter.CONTEXT_LAYER_TITLE, title);
-
-            String paramType = findParameterTitle(geometryType);
-
+            String paramType = findParameterTitle(geometryType,templateId);
             if (log.isDebugEnabled()) {
                 log.debug("Layer title: " + title);
                 log.debug("Layer type: " + paramType);
             }
-
-            Document meta = MetaWriter.writeLayerMeta(callContext, uuid,
-                                                        path, paramType,
-                                                        this.determineGeometryType(geometryType),
-                                                        SHAPEFILE_NAME,
-                                                        title);
-            if (meta != null) {
-                MapfileGenerator.getInstance().update();
-                return meta;
+            if (meta == null){
+                meta = MetaWriter.writeLayerMeta(callContext,document);
             }
-
-            pathElement.setTextContent(path);
-        }
-        else {
-            ExclusiveExec.UniqueKey key = ExclusiveExec.INSTANCE.acquire(uuid);
-            try{
-                if (data != null &&
-                    (path = writeToShapeFile(uuid, data, callContext,geometryType)) != null) {
-                    String paramType = findParameterTitle(geometryType);
-                    String    title      = getLayerTitle(inputData);
-                    if (title == null) {
-                        title = uuid;
-                    }
-                    Document meta = MetaWriter.writeLayerMeta(callContext, uuid,
-                                                              path, paramType,
-                                                              this.determineGeometryType(geometryType),
-                                                              SHAPEFILE_NAME,
-                                                              title);
-                    if (meta != null) {
-                        MapfileGenerator.getInstance().update();
-                        return meta;
-                    }
-                    pathElement.setTextContent(path);
-                }
-            }finally{
-                ExclusiveExec.INSTANCE.release(key);
+            MetaWriter.writeLayerMeta(callContext, document, 
+                                      meta, uuid, paramType, 
+                                      this.determineGeometryType(geometryType),
+                                      createShapeFileName(layerNumber),
+                                      title);
+            if (meta != null && !it.hasNext()) {
+                MetaWriter.writeMetaFile(getShapeFilePath(),document);
+                MapfileGenerator.getInstance().update();
+                return document;
             }
         }
-
         return document;
     }
 
@@ -636,9 +705,8 @@
      * @param geometryType
      * @return
      */
-    private String findParameterTitle(String geometryType) {
+    private String findParameterTitle(String geometryType, String templateID) {
         String paramType = LAYER_MODEL+"_"+templateID;
-
         if (!MapfileGenerator.getInstance().templateExists(paramType)){
             // If the template doesn't exist the Defaulttemplates will be used.
             paramType = LAYER_MODEL+"_"+
@@ -672,9 +740,7 @@
      * @return a valid geometry type fpr the template mechanism.
      */
     private String determineGeometryType(String geometryType){
-
         String returnValue = geometryType.toLowerCase();
-
         if (returnValue.equalsIgnoreCase("linestring")){
             returnValue = "Line";
         }else if (returnValue.equalsIgnoreCase("multilinestring")){
@@ -694,9 +760,7 @@
      * @return a default geometry fitting to the original geometry type.
      */
     private String determineDefaultTemplateName(String geometryType){
-
         String returnValue = geometryType.toLowerCase();
-
         if (returnValue.equalsIgnoreCase("multilinestring")){
             returnValue ="linestring";
         }else if (returnValue.equalsIgnoreCase("multipolygon")){

http://dive4elements.wald.intevation.org