changeset 649:4fc97074eb90

Added Support for writing Shapefiles and Export them as an Zipfile for the Product Layer. gnv-artifacts/trunk@738 c6561f87-3c4e-4783-a992-168aeb5c3f6f
author Tim Englich <tim.englich@intevation.de>
date Fri, 05 Mar 2010 12:35:24 +0000
parents 7c67ff162e87
children 1946c4e9a878
files gnv-artifacts/ChangeLog gnv-artifacts/doc/conf/conf.xml gnv-artifacts/doc/conf/products/layer/conf.xml gnv-artifacts/doc/conf/queries.properties gnv-artifacts/src/main/java/de/intevation/gnv/state/layer/LayerOutputState.java gnv-artifacts/src/main/java/de/intevation/gnv/utils/ShapeFileWriter.java gnv-artifacts/src/main/resources/lang/artifactMessages.properties gnv-artifacts/src/main/resources/lang/artifactMessages_de.properties gnv-artifacts/src/main/resources/lang/artifactMessages_de_DE.properties gnv-artifacts/src/main/resources/lang/artifactMessages_en.properties
diffstat 10 files changed, 431 insertions(+), 27 deletions(-) [+]
line wrap: on
line diff
--- a/gnv-artifacts/ChangeLog	Fri Mar 05 09:13:17 2010 +0000
+++ b/gnv-artifacts/ChangeLog	Fri Mar 05 12:35:24 2010 +0000
@@ -1,5 +1,31 @@
 2010-03-05  Tim Englich  <tim.englich@intevation.de>
 
+	* doc/conf/queries.properties: 
+	  Added some more Queries which are required to serve the Requests of the 
+	  Product Layer.
+	
+	* doc/conf/conf.xml: 
+	  Changed the Sourceid of the FIS Contis because of Changes in the Database.
+	
+	* doc/conf/products/layer/conf.xml: 
+	  Completed the Configuration for the Product Layer.
+	  Added more Configurationdetails to the OutputStates.
+	* src/main/resources/lang/artifactMessages*.properties:
+	  Added the required ressources for the Product Layer and the FIS Contis and 
+	  Nauthis into the Propertiesfiles.
+	
+	* src/main/java/de/intevation/gnv/utils/ShapeFileWriter.java (writeDataToFile): 
+	  Added an Method for writing g an Shapefile using an Collection of Results.
+	  this Method must be extended that it could use the Result-object in an 
+	  generic Way.
+	  At this Moment it is only be Possible to write the Geometry into the 
+	  Shapefile if it is given at the first Position of an Result.
+	  All other Attributevalues will be ignored and not written into the Shapefile.
+	
+	* src/main/java/de/intevation/gnv/state/layer/LayerOutputState.java: 
+	  Added Support for writing Shapefiles and Export them as an Zipfile.
+
+2010-03-05  Tim Englich  <tim.englich@intevation.de>
 	* doc/conf/products/verticalprofile/conf_instantaneouspoint.xml: 
 	  ISSUE 191: Pdf, svg and png are now available.
 
--- a/gnv-artifacts/doc/conf/conf.xml	Fri Mar 05 09:13:17 2010 +0000
+++ b/gnv-artifacts/doc/conf/conf.xml	Fri Mar 05 12:35:24 2010 +0000
@@ -381,7 +381,7 @@
                     <artifact-factory name="layer" description="Artiefactfactory for Instantiating the Artifact for the Product Layer"
                              ttl="300000" artifact="de.intevation.gnv.layer.LayerArtifact">de.intevation.gnv.artifacts.GNVArtifactFactory</artifact-factory>
                     <parameters>
-                        <parameter name="sourceid" value="Contis%"/>
+                        <parameter name="sourceid" value="contis%"/>
                         <parameter name="fisname" value="fis_contis"/>
                     </parameters>
                 </product>
--- a/gnv-artifacts/doc/conf/products/layer/conf.xml	Fri Mar 05 09:13:17 2010 +0000
+++ b/gnv-artifacts/doc/conf/products/layer/conf.xml	Fri Mar 05 12:35:24 2010 +0000
@@ -54,8 +54,21 @@
          
         <transition transition="de.intevation.gnv.transition.DefaultTransition">
             <from state="layer_without_geom"/>
-            <to state="layer_calculate_results"/>
+            <to state="layer_calculate_results_without_geom"/>
         </transition>
+        
+        <state id="layer_calculate_results_without_geom" description="layer_calculate_results" state="de.intevation.gnv.state.layer.LayerOutputState">
+            <queryID>layer_request_data</queryID>
+            <queryID-layerdata>layer_data</queryID-layerdata>
+            <inputvalues>
+               <inputvalue name="sourceid" type="String" multiselect="false" usedinquery="0"/>
+               <inputvalue name="layerid" type="Integer" multiselect="false" usedinquery="1"/>
+            </inputvalues>
+            <outputsModes>
+                <outputsMode name="zip" description="Export als ZIP-Archiv" mime-type="application/zip"/>
+                <outputsMode name="wms" description="WMS-Layer bereitstellen" mime-type="text/url"/>
+            </outputsModes>
+        </state>
          
           <state id="layer" description="layer" state="de.intevation.gnv.state.DefaultState">
              <queryID>layer</queryID>
@@ -76,10 +89,13 @@
          
          <state id="layer_calculate_results" description="layer_calculate_results" state="de.intevation.gnv.state.layer.LayerOutputState">
             <queryID>layer_request_data</queryID>
-            <queryID-layerdata>layer_data</queryID-layerdata>
+            <queryID-layerdata>layer_data_with_geom</queryID-layerdata>
+            <queryID-geometry>geometry_for_subareafilter</queryID-geometry>
+            <inputvalue-geometry>subareaid</inputvalue-geometry>
             <inputvalues>
                <inputvalue name="sourceid" type="String" multiselect="false" usedinquery="0"/>
-               <inputvalue name="layerid" type="Integer" multiselect="false" usedinquery="0"/>
+               <inputvalue name="layerid" type="Integer" multiselect="false" usedinquery="1"/>
+               <inputvalue name="subareaid" type="Integer" multiselect="false" usedinquery="0"/>
             </inputvalues>
             <outputsModes>
                 <outputsMode name="zip" description="Export als ZIP-Archiv" mime-type="application/zip"/>
--- a/gnv-artifacts/doc/conf/queries.properties	Fri Mar 05 09:13:17 2010 +0000
+++ b/gnv-artifacts/doc/conf/queries.properties	Fri Mar 05 12:35:24 2010 +0000
@@ -1221,7 +1221,7 @@
 #############################################
 #############################################
 
-layer = SELECT ID_LAYER KEY, \
+layer = SELECT ROW_ID KEY, \
         TITLE || '-' || LAYER_NAME VALUE \
     FROM MEDIAN.LAYER_HAS_SUBTYPES \
     WHERE ID_FEATURECLASS LIKE ? \
@@ -1230,10 +1230,20 @@
 layer_request_data = SELECT ID_FEATURECLASS, \
         QUERY_STRING, \
         TITLE, \
-        LAYERNAME \
+        LAYER_NAME \
     FROM MEDIAN.LAYER_HAS_SUBTYPES \
-    WHERE ID_LAYER = ? 
+    WHERE ROW_ID = ? 
 
 layer_data = SELECT ST_ASTEXT(SHAPE) \
     FROM ? \
     WHERE ?
+    
+layer_data_with_geom = SELECT ST_ASTEXT(SHAPE) \
+    FROM ? \
+    WHERE ? AND \
+          INTERSECTS(SHAPE,"?")
+    
+geometry_for_subareafilter=SELECT st_astext(SHAPE) \
+    FROM MEDIAN.FEATUREAREA \
+    WHERE (FEATURETYPE = 7 OR FEATURETYPE = 8) AND \
+           FEATURECODE = ?
--- a/gnv-artifacts/src/main/java/de/intevation/gnv/state/layer/LayerOutputState.java	Fri Mar 05 09:13:17 2010 +0000
+++ b/gnv-artifacts/src/main/java/de/intevation/gnv/state/layer/LayerOutputState.java	Fri Mar 05 12:35:24 2010 +0000
@@ -3,6 +3,8 @@
  */
 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.Iterator;
@@ -11,14 +13,25 @@
 import org.w3c.dom.Document;
 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.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.ShapeFileWriter;
 
 /**
  * @author Tim Englich <tim.englich@intevation.de>
@@ -40,6 +53,24 @@
      * 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;
+    
+    public static final String SHAPEFILE_NAME   = "data.shp";
+    
     /**
      * Constructor
      */
@@ -64,29 +95,94 @@
             // TODO USE ME
         }else if (outputMode.equalsIgnoreCase("zip")){
             Collection<Result> data = this.fetchData();
-            // TODO USE ME
+            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 table = null;
-            String where = null;
+            String[] queryValues = null;
             if (it.hasNext()){
                 Result resultValue = it.next();
-                table = resultValue.getString(0);
-                where = resultValue.getString(1);
-                // TODO ADD SpatialFilter if Geometry is available
+                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};
+                    
+                }
             }
             
-            data = null; // TODO Fetch the Data for the Layer and Trim the Geometries
-                         //      using the Geometry if on is available.
+            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;
     }
@@ -95,7 +191,151 @@
     public void setup(Node configuration) {
         log.debug("LayerOutputState.setup");
         super.setup(configuration);
-        this.dataQueryID = Config.getStringXPath(configuration,"queryID-layerdata");
+        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 (!ShapeFileWriter.writeDataToFile(shapeFile, "data", data)){
+                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;
+            return path;
+        }
+    }
+    
 
 }
--- a/gnv-artifacts/src/main/java/de/intevation/gnv/utils/ShapeFileWriter.java	Fri Mar 05 09:13:17 2010 +0000
+++ b/gnv-artifacts/src/main/java/de/intevation/gnv/utils/ShapeFileWriter.java	Fri Mar 05 12:35:24 2010 +0000
@@ -1,41 +1,39 @@
 package de.intevation.gnv.utils;
 
-import com.vividsolutions.jts.geom.MultiLineString;
-import com.vividsolutions.jts.geom.MultiPolygon;
-
 import java.io.File;
 import java.io.IOException;
 import java.io.Serializable;
-
 import java.net.MalformedURLException;
-
+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.geotools.data.DataStoreFactorySpi;
 import org.geotools.data.DataUtilities;
 import org.geotools.data.DefaultTransaction;
 import org.geotools.data.FeatureStore;
 import org.geotools.data.Transaction;
-
 import org.geotools.data.shapefile.ShapefileDataStore;
 import org.geotools.data.shapefile.ShapefileDataStoreFactory;
-
 import org.geotools.feature.FeatureCollection;
 import org.geotools.feature.FeatureCollections;
 import org.geotools.feature.SchemaException;
-
 import org.geotools.feature.simple.SimpleFeatureBuilder;
-
 import org.geotools.referencing.crs.DefaultGeographicCRS;
-
 import org.opengis.feature.simple.SimpleFeature;
 import org.opengis.feature.simple.SimpleFeatureType;
 
+import com.vividsolutions.jts.geom.Geometry;
+import com.vividsolutions.jts.geom.MultiLineString;
+import com.vividsolutions.jts.geom.MultiPolygon;
+import com.vividsolutions.jts.io.ParseException;
+import com.vividsolutions.jts.io.WKTReader;
+
+import de.intevation.gnv.geobackend.base.Result;
+
 /**
  * @author Sascha L. Teichmann (sascha.teichmann@intevation.de)
  */
@@ -179,6 +177,104 @@
             "polygons");
     }
 
+    
+    public static boolean writeDataToFile(File shapeFile,
+                                          String name,
+                                          Collection<Result> data){
+        WKTReader wktReader = new WKTReader();
+        
+        Map<String, Serializable> params = new HashMap<String, Serializable>();
+
+        try {
+            params.put("url", shapeFile.toURI().toURL());
+        }
+        catch (MalformedURLException mue) {
+            log.error(mue.getLocalizedMessage(), mue);
+            return false;
+        }
+
+        params.put("create spatial index", Boolean.TRUE);
+
+
+        if (name == null) {
+            name = shapeFile.getName();
+        }
+
+        SimpleFeatureType type = null;
+        SimpleFeatureBuilder featureBuilder = null;
+        FeatureCollection<SimpleFeatureType, SimpleFeature> collection = 
+            FeatureCollections.newCollection();
+        
+        for (Result result: data) {
+            try {
+                Geometry g = wktReader.read(result.getString(0));
+                if (type == null){
+                    try { 
+                        type = DataUtilities.createType(
+                            name,
+                            "geom:"+g.getGeometryType()+":srid=4326");
+                        // TODO add other AttributeTypes
+                    }
+                    catch (SchemaException se) {
+                        log.error(se.getLocalizedMessage(), se);
+                        return false;
+                    }
+                    featureBuilder = new SimpleFeatureBuilder(type);
+                }
+                featureBuilder.add(g);
+                SimpleFeature feature = featureBuilder.buildFeature(null);
+                collection.add(feature);
+            } catch (ParseException e) {
+                log.error(e,e);
+            } catch (java.lang.IllegalArgumentException e){
+                log.error("cannot create geometry for "+result.getString(0));
+            }
+        }
+
+        DataStoreFactorySpi dataStoreFactory = new ShapefileDataStoreFactory();
+
+        Transaction transaction = null;
+
+        boolean success = false;
+        try {
+            ShapefileDataStore newDataStore =
+                (ShapefileDataStore)dataStoreFactory.createNewDataStore(params);
+
+            newDataStore.createSchema(type);
+            newDataStore.forceSchemaCRS(DefaultGeographicCRS.WGS84);
+
+            transaction = new DefaultTransaction("create");
+
+            String typeName = newDataStore.getTypeNames()[0];
+
+            FeatureStore<SimpleFeatureType, SimpleFeature> featureStore =
+                (FeatureStore<SimpleFeatureType, SimpleFeature>)
+                    newDataStore.getFeatureSource(typeName);
+
+            featureStore.setTransaction(transaction);
+
+            featureStore.addFeatures(collection);
+            transaction.commit();
+            success = true;
+        } 
+        catch (IOException ioe) {
+            log.error(ioe.getLocalizedMessage(), ioe);
+        }
+        finally {
+            if (transaction != null) {
+                if (!success) {
+                    try { transaction.rollback(); }
+                    catch (IOException ioe) {}
+                }
+                try { transaction.close(); }
+                catch (IOException ioe) {}
+            }
+        }
+
+        return success;
+        
+    }
+    
     public static boolean writeMultiPolygonsToFile(
         File                       shapeFile,
         Integer                    parameterId,
--- a/gnv-artifacts/src/main/resources/lang/artifactMessages.properties	Fri Mar 05 09:13:17 2010 +0000
+++ b/gnv-artifacts/src/main/resources/lang/artifactMessages.properties	Fri Mar 05 12:35:24 2010 +0000
@@ -14,6 +14,8 @@
 fis_seacat = SeaCat
 fis_currentmeter = Current Meter
 fis_icestations = Ice Station Report
+fis_nauthis = Nauthis
+fis_contis=Contis
 
 meshid= Mesh
 fis = Data set
@@ -24,6 +26,7 @@
 horizontalProfileCross = Horizontales Schnittprofil
 horizontalCrossSection = Horizontal cross-section
 verticalcrosssection = Vertical cross-section
+layer = Layer
 featureid = Station
 mesh_coordinate = Geographic position (e.g. 56n30 6e20)
 mesh_linestring = Line (WKT)
@@ -35,6 +38,7 @@
 maxdepthid = Highest Layer
 parameterid = Parameter
 yearid = Year
+layerid = Layer
 timeinterval = Time period
 minvalue = from
 maxvalue = to
--- a/gnv-artifacts/src/main/resources/lang/artifactMessages_de.properties	Fri Mar 05 09:13:17 2010 +0000
+++ b/gnv-artifacts/src/main/resources/lang/artifactMessages_de.properties	Fri Mar 05 12:35:24 2010 +0000
@@ -14,6 +14,8 @@
 fis_seacat = SeaCat
 fis_currentmeter = Strommesser
 fis_icestations = Eismeldungen
+fis_nauthis = Nauthis
+fis_contis=Contis
 
 fis = Fachinformationssystem
 product= Produkt
@@ -23,6 +25,7 @@
 horizontalProfileCross = Horizontales Schnittprofil
 horizontalCrossSection = Horizontalschnitt
 verticalcrosssection = Profilschnitt
+layer = Layer
 featureid = Station
 meshid= Datengitter
 mesh_coordinate = Geographische Position (z.B. 56n30 6e20)
@@ -35,6 +38,7 @@
 maxdepthid = Obere Grenzschicht
 parameterid = Parameter
 yearid = Jahr
+layerid = Layer
 timeinterval = Zeitfenster
 minvalue = von
 maxvalue = bis
--- a/gnv-artifacts/src/main/resources/lang/artifactMessages_de_DE.properties	Fri Mar 05 09:13:17 2010 +0000
+++ b/gnv-artifacts/src/main/resources/lang/artifactMessages_de_DE.properties	Fri Mar 05 12:35:24 2010 +0000
@@ -14,6 +14,8 @@
 fis_seacat = SeaCat
 fis_currentmeter = Strommesser
 fis_icestations = Eismeldungen
+fis_nauthis = Nauthis
+fis_contis=Contis
 
 fis= Fachinformationssystem
 product= Produkt
@@ -23,6 +25,7 @@
 horizontalProfileCross = Horizontales Schnittprofil
 horizontalCrossSection = Horizontalschnitt
 verticalcrosssection = Profilschnitt
+layer = Layer
 featureid = Station
 meshid= Datengitter
 mesh_coordinate = Geographische Position (z.B. 56n30 6e20)
@@ -35,6 +38,7 @@
 maxdepthid = Obere Grenzschicht
 parameterid = Parameter
 yearid = Jahr
+layerid = Layer
 timeinterval = Zeitfenster
 minvalue = von
 maxvalue = bis
--- a/gnv-artifacts/src/main/resources/lang/artifactMessages_en.properties	Fri Mar 05 09:13:17 2010 +0000
+++ b/gnv-artifacts/src/main/resources/lang/artifactMessages_en.properties	Fri Mar 05 12:35:24 2010 +0000
@@ -14,6 +14,8 @@
 fis_seacat = SeaCat
 fis_currentmeter = Current Meter
 fis_icestations = Ice Station Report
+fis_nauthis = Nauthis
+fis_contis=Contis
 
 meshid= Mesh
 fis = Data set
@@ -24,6 +26,7 @@
 horizontalProfileCross = Horizontales Schnittprofil
 horizontalCrossSection = Horizontal cross-section
 verticalcrosssection = Vertical cross-section
+layer = Layer
 featureid = Station
 mesh_coordinate = Geographic position (e.g. 56n30 6e20)
 mesh_linestring = Line (WKT)
@@ -35,6 +38,7 @@
 maxdepthid = Highest Layer
 parameterid = Parameter
 yearid = Year
+layerid = Layer
 timeinterval = Time period
 minvalue = from
 maxvalue = to

http://dive4elements.wald.intevation.org