Index: trunk/docs/install/installation.rst
===================================================================
--- trunk/docs/install/installation.rst	(revision 889)
+++ trunk/docs/install/installation.rst	(revision 917)
@@ -147,4 +147,37 @@
     <http://zoo-project.org/trac/browser/trunk/zoo-project/zoo-kernel/sql/schema.sql#L34>`_.
 
+Metadata Database (Optional)
+*****************************
+
+.. _zoo_create_metadb:
+
+It is possible to use a PostgreSQL database to store metadata
+information about WPS Services. This support is optional and require
+to be activated by using the ``--with-metadb=yes`` option.
+
+To create the database for storing the metadata informations about the
+WPS Services, you may use the following command:
+
+.. code::
+
+    createdb zoo_metadb
+    psql zoo_metadb -f zoo-project/zoo-kernel/sql/zoo_collectiondb.sql
+
+In case you want to convert an existing zcfg file then, you can use
+the ``zcfg2sql`` tool from the command line. It can be found in
+``thirds/zcfg2sql`` and can be build simply by running the ``make``
+command. After compilation you only need to give it the path of the
+zcfg file you want to obtain the SQL queries required to store the
+metadata informations in the database rather than in zcfg file.
+
+For instance you may use the following command:
+
+.. code::
+
+    #Direct import in the zoo_metadb database
+    ./zcfg2sql /Path/To/MyZCFGs/myService.zcfg | psql zoo_metadb
+    #Create a SQL file for a futur import
+    ./zcfg2sql /Path/To/MyZCFGs/myService.zcfg > myService.sql
+
 
 
@@ -154,5 +187,5 @@
 If ``yaml.h`` file is not found in your ``/usr/include`` directory and
 ``libyaml.so`` is not found in ``/usr/lib``, a ``--with-yaml`` option
-can be used to specify its location. For instance, if the headeer file
+can be used to specify its location. For instance, if the header file
 lies in ``/usr/local/include`` and the shared library is located in
 ``/usr/local/lib``, you may use the following command:
Index: trunk/docs/kernel/configuration.rst
===================================================================
--- trunk/docs/kernel/configuration.rst	(revision 889)
+++ trunk/docs/kernel/configuration.rst	(revision 917)
@@ -94,9 +94,18 @@
    service providers, e.g., shared libraries with service implementations 
    (the ``serviceProvider`` parameter in the service configuration (.zcfg) file).   
+ * ``memory``: (Optional) can take the value ``load`` to ensure that
+   the value field of the inputs data will be filled by the ZOO-Kernel
+   or ``protected`` to have only the ``cache_file`` filled.
+
 
 .. warning:: 
   The ``libPath`` parameter is currently only recognized by services implemented
   in C/C++ or PHP, and may be moved to another section in future versions.
-  
+
+
+.. warning:: 
+  Depending on the ``memory`` parameter the WPS Service will receive
+  different fields (``value`` or ``cache_file``).
+   
 In case you have activated the MapServer support, please refer to
 :ref:`this specific section <kernel-mapserver-main.cfg>`. 
@@ -264,4 +273,20 @@
     hosts=localhost,127.0.0.1
 
+Optionaly, you can also define the shared url(s), meaning that even if
+the ressource requires authentication to be accessed, this
+authentifcation won't be used to define the name for storing the
+file. Hence, two user with different authentication will use the same
+file as it is considerated as shared. You can find bellow a sample
+security section containing the shared parameter. In this example,
+every requests to access the coverage using the url defined in the
+shared parameter (``myHost/cgi-bin/WCS_Server``) will be shared
+between users.
+
+.. code::
+
+    [security]
+    attributes=Authorization,Cookie,User-Agent
+    hosts=localhost,127.0.0.1
+    shared=myHost/cgi-bin/WCS_Server
 
 .. _zoo_activate_db_backend:
@@ -300,4 +325,38 @@
 to setup the database.
 
+
+Database section
+...............................
+
+The database section allows to configure the ZOO-Kernel to access the
+metadata information about WPS Services by using a PostgreSQL database
+in addition to the zcfg files.
+
+.. code-block:: guess
+
+	[metadb]
+	dbname=zoo_metadb
+	port=5432
+	user=username
+	host=127.0.0.1
+	type=PG
+
+This will generate strings to be passed to GDAL to connect the
+database server:
+
+.. code-block:: guess
+   
+    <type>:host=<host> port=<port>  user=<user> dbname=<dbname>
+
+
+With the previous database section, it will give the following:
+
+.. code-block:: guess
+
+    PG:"dbname=zoo_metadb host=127.0.0.1 port=5432 user=username"
+
+Please refer to this `section <zoo_create_metadb>`_ to learn how
+to setup the database.
+
 Include section
 ...............................
Index: trunk/docs/kernel/hpc.rst
===================================================================
--- trunk/docs/kernel/hpc.rst	(revision 917)
+++ trunk/docs/kernel/hpc.rst	(revision 917)
@@ -0,0 +1,339 @@
+.. _kernel-hpc:
+    
+Optional HPC support
+======================
+
+The optional ZOO-Kernel HPC support gives you the opportunity to use
+OGC WPS for invoking remote execution of OTB applications. The current
+implementation rely on `OpenSSH <https://www.openssh.com/>`_ and the
+`Slurm <http://slurm.schedmd.com/>`_  scheduler. 
+
+.. note:: 
+
+   |slurm| `Slurm <http://slurm.schedmd.com/>`_ is an acronym for Simple Linux Utility for Resource Management. Learn more on official `website <https://slurm.schedmd.com/overview.html>`__.
+
+For executing an OGC WPS Service using this HPC support, one should
+use the OGC WPS version 2.0.0 and asynchornous request. Any tentative
+to execute synchronously a HPC service will fail with the message "The
+synchronous mode is not supported by this type of service". The
+ZOO-Kernel is not the only responsible for the execution and will wait
+for the execution on the HPC server to end before being able to
+continue its execution. Also, transfering the data from the WPS server
+to the cluster and downloading the data produced by the execution will
+take time. Hence, when OGC WPS Client will request for GetCapabilities
+or DescribeProcess only the "async-execute" mode will be present in
+the jobControlOptions attribute for the HPC services.
+
+You can see in the sequence diagram below the interactions between
+the OGC WPS Server (ZOO-Kernel), the mail daemon (running on the OGC
+WPS server), the Callback Service and, the HPC Server during an
+execution of a HPC Service. The dashed lines represent the behavior in
+case the optional callback service invocation has been activated. These 
+invocations are made asynchronously for lowering their impact over the
+whole process in case of failure of the callback service for instance.
+
+By now, the callback service is not a WPS service but an independent server.
+
+|hpc_support|
+
+.. |slurm| image:: https://slurm.schedmd.com/slurm_logo.png
+       :height: 100px
+       :width: 100px
+       :scale: 45%
+       :alt: Slurm logo
+
+.. |hpc_support| image:: ../_static/hpc_schema.svg
+       :scale: 65%
+       :alt: HPC Support schema
+
+
+Installation and configuration
+------------------------------
+
+Follow the step described below in order to activate the ZOO-Project optional HPC support.
+
+Prerequisites
+.....................
+
+   * latest `ZOO-Kernel
+     <http://zoo-project.org/trac/browser/trunk/zoo-project/zoo-kernel>`_
+     trunk version
+   * `libssh2 <https://www.libssh2.org/>`_
+   * `MapServer <http://www.mapserver.org>`_
+   * an access to a server with `Slurm  <http://slurm.schedmd.com>`_
+     and `OrfeoToolBox <https://www.orfeo-toolbox.org>`_.
+
+Installation steps
+...........................
+
+ZOO-Kernel
+****************************
+
+Compile ZOO-Kernel using the configuration options as shown below:
+
+.. code-block:: guess
+
+     cd zoo-kernel
+     autoconf
+     ./configure  --with-hpc=yes --with-ssh2=/usr --with-mapserver=/usr --with-ms-version=7
+     make
+     sudo make install
+
+Optionally, you can ask your ZOO-Kernel to invoke a callback service
+which is responsible to record execution history and data
+produced. In such a case you can add the ``--with-callback=yes``
+option to the configure command. 
+
+.. note::
+
+   In case you need other languages to be activated, such as Python
+   for exemple, please use the corresponding option(s).
+
+FinalizeHPC WPS Service
+****************************
+
+For being informed that the remote OTB application ends on the
+cluster, one should invoke the FinalizeHPC service. It is responsible
+to connect using SSH to the HPC server to run an ``sacct`` command for
+extracting detailled informations about the sbatch that has been
+run. If the ``sacct`` command succeed, and the service is no more
+running on the cluster, then the informations are stored in a local
+conf file containing a ``[henv]`` section definition, the service
+connect to unix domain socket (opened by the ZOO-Kernel that has
+initially schedduled the service through Slurm) to inform about the
+end of the service run on the cluster. This makes the initial
+ZOO-Kernel to continue its execution by downloading output data
+produced over the execution of the OTB application on the cluster. So,
+this service should be build and deployed on your WPS server. You can
+use the following commands to do so. 
+
+.. code-block:: guess
+
+     cd zoo-service/utils/hpc
+     make
+     cp cgi-env/* /usr/lib/cgi-bin
+     mkdir -p /var/data/xslt/
+     cp xslt/updateExecute.xsl /var/data/xslt/
+     
+You should also copy the 
+.. note::
+
+   FinalizeHPC should be called from a daemon, responsible for reading
+   mails sent by the cluster to the WPS server.
+
+
+Configuration steps
+...............................
+
+Main configuration file
+****************************
+
+When HPC support is activated, you can use different HPC configuration
+by adding ``confId`` to your usual ``serviceType=HPC`` in your zcfg
+file. For being able to find which configuration a service should
+use, the ZOO-Kernel require to know what are the options for creating
+the relevant sbatch.
+
+Also, you can define multiple configuration to run the OTB application
+on the cluster(s) depending on the size of the inputs. You should
+define in the section corresponding to your ``ServiceType`` the
+treshold for both raster (``preview_max_pixels``) and vector
+(``preview_max_features``) input. In case the raster or the vector
+dataset is upper the defined limit, then the ``fullres_conf`` will
+be used, in other case the ``preview_conf`` will be.
+
+For each of this configurations, you will have define the parameters
+to connect the HPC server, by providing ``ssh_host``, ``ssh_port``,
+``ssh_user`` and, ``ssh_key``. Also, you should set where the input
+data will be stored on the HPC server, by defining
+``remote_data_path`` (the default directory to store data),
+``remote_presistent_data_path`` (the directory to store data
+considerated as shared data, see below)  and, ``remote_work_path`` the
+directory used to store the SBATCH script created locally then,
+uploaded by the ZOO-Kernel.
+
+Also, there are multiple options you can use to run your applications
+using  SBATCH. You can define them using ``jobscript_header``,
+``jobscript_body`` and ``jobscript_footer`` or by using
+``sbatch_options_<SBATCH_OPTION>`` where ``<SBATCH_OPTION>`` should be
+replaced by a real option name, like ``workdir`` in the following
+example. For creating the SBATCH file, the ZOO-Kernel create a file
+starting with the content of the file pointed by ``jobscript_header``
+(if any, a default header is set in other case), then, any option
+defined in ``sbatch_options_*`` and a specific one: ``job-name``,
+then, ``jobscript_body`` is added (if any, usually to load required
+modules), then the ZOO-Kernel add the invocation of the OTB
+application then, optionally the ``jobscript_footer`` is added, if
+any.
+
+Finally, ``remote_command_opt`` should contains all the informations
+you want to be extracted by the ``sacct`` command run by the
+FinalizeHPC service. ``billing_nb_cpu`` is used for billing purpose to
+define a cost for using a specific option (preview or fullres).
+
+In addition to the specific ``HPC_<ID>`` section and the corresponding
+fullres and preview ones, you should define in the ``[security]``
+section using the ``shared`` parameter to set the URLs from where the
+downloaded data should be considerated as shared, meaning that even if
+this ressources requires authentication to be accessed, any
+authenticated user will be allowed to access the cache file even if
+it was created by somebody else. Also, this shared cache won't contain
+any authentication informations in the cache file name as it is
+usually the case.
+
+.. code-block:: guess
+
+     [HPC_Sample]
+     preview_max_pixels=820800
+     preview_max_features=100000
+     preview_conf=hpc-config-2
+     fullres_conf=hpc-config-1
+     
+     [hpc-config-1]
+     ssh_host=mycluster.org
+     ssh_port=22
+     ssh_user=cUser
+     ssh_key=/var/www/.ssh/id_rsa.pub
+     remote_data_path=/home/cUser/wps_executions/data
+     remote_persitent_data_path=/home/cUser/wps_executions/datap
+     remote_work_path=/home/cUser/wps_executions/script
+     jobscript_header=/usr/lib/cgi-bin/config-hpc1_header.txt
+     jobscript_body=/usr/lib/cgi-bin/config-hpc1_body.txt
+     sbatch_options_workdir=/home/cUser/wps_executions/script
+     sbatch_substr=Submitted batch job 
+     billing_nb_cpu=1
+     remote_command_opt=AllocCPUS,AllocGRES,AllocNodes,AllocTRES,Account,AssocID,AveCPU,AveCPUFreq,AveDiskRead,AveDiskWrite,AvePages,AveRSS,AveVMSize,BlockID,Cluster,Comment,ConsumedEnergy,ConsumedEnergyRaw,CPUTime,CPUTimeRAW,DerivedExitCode,Elapsed,Eligible,End,ExitCode,GID,Group,JobID,JobIDRaw,JobName,Layout,MaxDiskRead,MaxDiskReadNode,MaxDiskReadTask,MaxDiskWrite,MaxDiskWriteNode,MaxDiskWriteTask,MaxPages,MaxPagesNode,MaxPagesTask,MaxRSS,MaxRSSNode,MaxRSSTask,MaxVMSize,MaxVMSizeNode,MaxVMSizeTask,MinCPU,MinCPUNode,MinCPUTask,NCPUS,NNodes,NodeList,NTasks,Priority,Partition,QOS,QOSRAW,ReqCPUFreq,ReqCPUFreqMin,ReqCPUFreqMax,ReqCPUFreqGov,ReqCPUS,ReqGRES,ReqMem,ReqNodes,ReqTRES,Reservation,ReservationId,Reserved,ResvCPU,ResvCPURAW,Start,State,Submit,Suspended,SystemCPU,Timelimit,TotalCPU,UID,User,UserCPU,WCKey,WCKeyID
+     
+     [hpc-config-2]
+     ssh_host=mycluster.org
+     ssh_port=22
+     ssh_user=cUser
+     ssh_key=/var/www/.ssh/id_rsa.pub
+     remote_data_path=/home/cUser/wps_executions/data
+     remote_persitent_data_path=/home/cUser/wps_executions/datap
+     remote_work_path=/home/cUser/wps_executions/script
+     jobscript_header=/usr/lib/cgi-bin/config-hpc2_header.txt
+     jobscript_body=/usr/lib/cgi-bin/config-hpc2_body.txt
+     sbatch_options_workdir=/home/cUser/wps_executions/script
+     sbatch_substr=Submitted batch job 
+     billing_nb_cpu=4
+     remote_command_opt=AllocCPUS,AllocGRES,AllocNodes,AllocTRES,Account,AssocID,AveCPU,AveCPUFreq,AveDiskRead,AveDiskWrite,AvePages,AveRSS,AveVMSize,BlockID,Cluster,Comment,ConsumedEnergy,ConsumedEnergyRaw,CPUTime,CPUTimeRAW,DerivedExitCode,Elapsed,Eligible,End,ExitCode,GID,Group,JobID,JobIDRaw,JobName,Layout,MaxDiskRead,MaxDiskReadNode,MaxDiskReadTask,MaxDiskWrite,MaxDiskWriteNode,MaxDiskWriteTask,MaxPages,MaxPagesNode,MaxPagesTask,MaxRSS,MaxRSSNode,MaxRSSTask,MaxVMSize,MaxVMSizeNode,MaxVMSizeTask,MinCPU,MinCPUNode,MinCPUTask,NCPUS,NNodes,NodeList,NTasks,Priority,Partition,QOS,QOSRAW,ReqCPUFreq,ReqCPUFreqMin,ReqCPUFreqMax,ReqCPUFreqGov,ReqCPUS,ReqGRES,ReqMem,ReqNodes,ReqTRES,Reservation,ReservationId,Reserved,ResvCPU,ResvCPURAW,Start,State,Submit,Suspended,SystemCPU,Timelimit,TotalCPU,UID,User,UserCPU,WCKey,WCKeyID
+     
+     [security]
+     attributes=Cookie,Cookies
+     hosts=*
+     shared=myhost.net/WCS
+
+You can see below an example of ``jobscript_header`` file.
+
+.. code-block:: guess
+
+     #!/bin/sh
+     #SBATCH --ntasks=1
+     #SBATCH --ntasks-per-node=1
+     #SBATCH --exclusive
+     #SBATCH --distribution=block:block
+     #SBATCH --partition=partName
+     #SBATCH --mail-type=END              # Mail events (NONE, BEGIN, END, FAIL, ALL)
+     #SBATCH --mail-user=user@wps_server.net   # Where to send mail
+
+You can see below an example of ``jobscript_body`` file.
+
+
+.. code-block:: guess
+
+     # Load all the modules
+     module load cv-standard
+     module load cmake/3.6.0
+     module load gcc/4.9.3
+     module load use.own
+     module load OTB/6.1-serial-24threads
+
+In casse you have activated the callback service, then you should also
+have a ``[callback]`` section, in which you will define ``url`` to
+invoke the callback service, ``prohibited`` to list the services that
+should not require invocation of the callback sercvice if any and,
+``template`` pointing to the local ``updateExecute.xsl`` file used to
+replace any inputs provided by value to the reference to the locally
+published OGC WFS/WCS web services. This execute request is provided
+to the callback service.
+
+.. code-block:: guess
+
+     [callback]
+     url=http://myhost.net:port/callbackUpdate/
+     prohibited=FinalizeHPC,Xml2Pdf,DeleteData
+     template=/home/cUser/wps_dir/updateExecute.xsl
+
+
+OGC WPS Services metadata
+****************************
+
+To produce the zcfg files corresponding to the metadata definition of
+the WPS services, you can use the otb2zcfg tool to produce them. You
+will need to replace ``serviceType=OTB`` by ``serviceType=HPC`` and,
+optionally, add one line containing ``confId=HPC_Sample`` for
+instance.
+
+Please refer to `otb2zcfg
+<./orfeotoolbox.html#services-configuration-file>`_ documentation to
+know how to use this tool.
+
+Using the HPC support, when you define one output, there will be
+automatically 1 to 3 inner outputs created for the defined output:
+
+download_link
+   URL to download to generated output 
+
+wms_link
+   URL to access the OGC WMS for this output (only in case
+   `useMapserver=true`)
+
+wcs_link/wfs_link
+   URL to access the OGC WCS or WFS for this output (only in case
+   `useMapserver=true`) 
+
+You can see below an example of Output node resulting of the
+definition of one output named out and typed as geographic imagery.
+
+
+.. code-block:: guess
+
+      <wps:Output>
+        <ows:Title>Outputed Image</ows:Title>
+        <ows:Abstract>Image produced by the application</ows:Abstract>
+        <ows:Identifier>out</ows:Identifier>
+        <wps:Output>
+          <ows:Title>Download link</ows:Title>
+          <ows:Abstract>The download link</ows:Abstract>
+          <ows:Identifier>download_link</ows:Identifier>
+          <wps:ComplexData>
+            <wps:Format default="true" mimeType="image/tiff"/>
+            <wps:Format mimeType="image/tiff"/>
+          </wps:ComplexData>
+        </wps:Output>
+        <wps:Output>
+          <ows:Title>WMS link</ows:Title>
+          <ows:Abstract>The WMS link</ows:Abstract>
+          <ows:Identifier>wms_link</ows:Identifier>
+          <wps:ComplexData>
+            <wps:Format default="true" mimeType="image/tiff"/>
+            <wps:Format mimeType="image/tiff"/>
+          </wps:ComplexData>
+        </wps:Output>
+        <wps:Output>
+          <ows:Title>WCS link</ows:Title>
+          <ows:Abstract>The WCS link</ows:Abstract>
+          <ows:Identifier>wcs_link</ows:Identifier>
+          <wps:ComplexData>
+            <wps:Format default="true" mimeType="image/tiff"/>
+            <wps:Format mimeType="image/tiff"/>
+          </wps:ComplexData>
+        </wps:Output>
+      </wps:Output>
+
+   
+
+
+
+
Index: trunk/docs/kernel/index.rst
===================================================================
--- trunk/docs/kernel/index.rst	(revision 889)
+++ trunk/docs/kernel/index.rst	(revision 917)
@@ -14,3 +14,3 @@
    orfeotoolbox
    sagagis
-
+   hpc
Index: trunk/docs/kernel/mapserver.rst
===================================================================
--- trunk/docs/kernel/mapserver.rst	(revision 889)
+++ trunk/docs/kernel/mapserver.rst	(revision 917)
@@ -73,11 +73,11 @@
    * `MapServer <http://mapserver/org>`__ version >= 6.0.1
 
-First download the lastest zoo-kernel by checking out the svn. Use the following command from do the directory where your previously checked out (in this example we will use ``<PREV_SVN_CO>`` to design this directory).
-
-.. code-block:: guess
-
-    cd <PREV_SVN_CO>
-    svn checkout http://svn.zoo-project.org/svn/trunk/zoo-kernel zoo-kernel-ms
-
+First download the lastest zoo-kernel by checking out the svn. Use the following command from do the directory where your previously checked out (in this example we will use ``$PREV_SVN_CO`` to design this directory).
+
+.. code-block:: guess
+
+    svn checkout http://svn.zoo-project.org/svn/trunk/ $PREV_SVN_CO
+    cd $PREV_SVN_CO
+    
 Then uncompress the MapServer archive (ie. ``mapserver-6.0.1.tar.bz2``) into ``/tmp/zoo-ms-src``, and compile it using the following command:
 
@@ -92,18 +92,13 @@
      cp mapserv /usr/lib/cgi-bin
 
-Once done, compile ZOO-Kernel with MapServer support from the ``<PREV_SVN_CO>`` directory, using the following command:
-
-.. code-block:: guess
-
-     cd zoo-kernel-ms
+Once done, compile ZOO-Kernel with MapServer support from the ``$PREV_SVN_CO`` directory, using the following command:
+
+.. code-block:: guess
+
+     cd zoo-kernel
      autoconf
      ./configure --with-python --with-mapserver=/tmp/zoo-ms-src/mapserver-6.0.1
      make
-
-You can then copy the new ZOO-Kernel to ``/usr/lib/cgi-bin`` directory, as follow:
-
-.. code-block:: guess
-
-     cp zoo_loader.cgi /usr/lib/cgi-bin
+     sudo make install
 
 
@@ -119,4 +114,14 @@
       dataPath = /var/www/temp/
       mapserverAddress=http://localhost/cgi-bin/mapserv
+
+You can also add the following lines to the ``[main]`` section, in case
+you want to use a default style for Polygon, Lines and Points vector
+layer.
+
+.. code-block:: guess
+
+      msStylePoly=STYLE COLOR 202 109 19 OUTLINECOLOR 105 105 105 WIDTH 3 END
+      msStyleLine=STYLE OUTLINECOLOR 202 109 19 WIDTH 3 END
+      msStylePoint=STYLE COLOR 202 109 19 OUTLINECOLOR 105 105 105 SYMBOL 0 SIZE 14 END
 
 The ``dataPath`` directory is mandatory and must belong to the Apache user.
@@ -175,4 +180,10 @@
 *************
 
+You have different options to define the style of the layer created
+using the data returned by your service.
+
+msStyle
++++++++
+
 The optional ``msStyle`` parameter can also be used to define a custom MapServer style block (used for vector datasource only), as follow:
 
@@ -181,9 +192,88 @@
      msStyle = STYLE COLOR 125 0 105 OUTLINECOLOR 0 0 0 WIDTH 3 END
 
-If a WPS service outputs a one band raster file, then it is possible to add a ``msClassify`` parameter and set it to ``true`` in the output ComplexData ``<Default>`` or ``<Supported>`` nodes of its ``zcfg`` file. This allows ZOO-Kernel to use its own default style definitions in order to classify the raster using equivalent intervals. 
-
-.. code-block:: guess
-
-     msClassify = ....
+msClassify
+++++++++++
+
+If a WPS service outputs a one band raster file, then it is possible
+to add a ``msClassify`` parameter and set it to ``true`` in the output
+ComplexData ``<Default>`` or ``<Supported>`` nodes of its zcfg
+file. This allows ZOO-Kernel to use its own default style definitions
+in order to classify the raster using equivalent intervals.  
+
+.. code-block:: guess
+
+     msClassify = true
+
+
+msInclude
++++++++++
+
+In case you want to use another layer which use the result of your
+service, for instance to produce a `heatmap
+<https://mapserver.org/output/kerneldensity.html>`_, then you can use
+the 
+``msInclude`` and ``msLayer`` options in the output ``ComplexData``
+``<Default>`` or ``<Supported>`` nodes of its zcfg file. You can see below an
+example of use of this two options with the associated mapfile.
+
+.. code-block:: guess
+
+     msInclude = /var/data/template.map
+     msLayer = heatmap
+
+You can find below a sample ``/var/data/template.map``:
+
+.. code-block:: guess
+
+     MAP
+       SIZE 1000 500
+       EXTENT -180 -90 180 90
+       NAME "test heat"
+       IMAGETYPE "png"
+
+       WEB
+         METADATA
+           "ows_srs" "epsg:4326  epsg:3857 epsg:900913"
+           "ows_enable_request" "*"
+	 END # METADATA
+       END # WEB
+       
+       PROJECTION
+         "+init=epsg:4326"
+       END # PROJECTION
+
+       LAYER
+         NAME "heatmap" # Corresponding to the msLayer defined
+	 TYPE raster
+	 CONNECTIONTYPE kerneldensity
+	 CONNECTION "Result"
+	 STATUS on
+	 PROCESSING "RANGE_COLORSPACE=HSL"
+	 PROCESSING "KERNELDENSITY_RADIUS=20"
+	 PROCESSING "KERNELDENSITY_COMPUTE_BORDERS=ON"
+	 PROCESSING "KERNELDENSITY_NORMALIZATION=AUTO"
+	 OFFSITE 0 0 0
+	 CLASS
+	   STYLE
+	     COLORRANGE  "#0000ff00"  "#0000ffff"
+	     DATARANGE 0 32
+	   END # STYLE
+	   STYLE
+	     COLORRANGE  "#0000ffff"  "#ff0000ff"
+	     DATARANGE 32 255
+	   END # STYLE
+	 END # CLASS
+       END # LAYER
+       
+       LAYER
+         NAME "points"
+	 STATUS on
+	 TYPE POINT
+	 #DATA "/Library/WebServer/cache//ef76ee6642c1ea704e847e28120ba1ca.zca"
+       END # LAYER
+     END # MAPFILE
+
+
+
 
 Example
@@ -216,5 +306,5 @@
      useMapserver = true
      asReference = true
-     msClassify = ....
+     msClassify = true
     </Supported>
 
Index: trunk/docs/kernel/sagagis.rst
===================================================================
--- trunk/docs/kernel/sagagis.rst	(revision 889)
+++ trunk/docs/kernel/sagagis.rst	(revision 917)
@@ -4,9 +4,9 @@
 ======================
 
-`SAGA GIS <http://orfeo-toolbox.org/otb/>`_ provides a comprehensive set of geoscientific methods and spatial algorithms. The optional SAGA GIS support is available since `ZOO-Project 1.5 <http://zoo-project.org>`__. It allows to execute the `SAGA Modules <http://www.saga-gis.org/saga_module_doc/2.1.4/index.html>`_ directly as ZOO WPS Services thanks to a :ref:`kernel_index` specific internal mechanism which is detailed in this section.
+`SAGA GIS <http://www.saga-gis.org/>`_ provides a comprehensive set of geoscientific methods and spatial algorithms. The optional SAGA GIS support is available since `ZOO-Project 1.5 <http://zoo-project.org>`__. It allows to execute the `SAGA Modules <http://www.saga-gis.org/saga_module_doc/2.1.4/index.html>`_ directly as ZOO WPS Services thanks to a :ref:`kernel_index` specific internal mechanism which is detailed in this section.
 
 .. note:: 
 
-   |saga| `SAGA GIS <https://www.orfeo-toolbox.org>`__ is the System for Automated Geoscientific Analyses. Learn more on official `website <http://www.saga-gis.org/en/index.html>`__.
+   |saga| `SAGA GIS <http://www.saga-gis.org/>`__ is the System for Automated Geoscientific Analyses. Learn more on official `website <http://www.saga-gis.org/en/index.html>`__.
  
 
@@ -27,19 +27,10 @@
 
    * latest `ZOO-Kernel <http://zoo-project.org/trac/browser/trunk/zoo-project/zoo-kernel>`_ trunk version
-   * SAGA GIS (`SAGA-GIS 2.1.4  <http://saga-gis.org>`_ )
-   * libLAS-1.2 (`LibLAS-1.2  <https://github.com/libLAS/libLAS-1.2>`_ )
+   * `SAGA GIS  <http://saga-gis.org>`_  (7.2.0)
 
 Installation steps
 ...........................
 
-.. Note:: These installation steps were successfully tested on Ubuntu 14.4 LTS 
-
-Download lastest ZOO-Kernel code from SVN.
-
-.. code-block:: guess
-
-    svn checkout http://svn.zoo-project.org/svn/trunk/zoo-kernel zoo-kernel
-
-Then compile ZOO-Kernel using the needed configuration options as shown bellow:
+Compile ZOO-Kernel using the configuration options as shown bellow:
 
 .. code-block:: guess
@@ -47,9 +38,14 @@
      cd zoo-kernel
      autoconf
-     ./configure  --with-saga=/usr/local/
+     ./configure  --with-saga=/usr/local/ --with-saga-version=7
      make
 
-And copy the newly created zoo_loader.cgi to ``/usr/lib/cgi-bin`` :
-
+And copy the newly created zoo_loader.cgi to ``/usr/lib/cgi-bin``.
+     
+.. note::
+   
+    The ``--with-saga-version`` option let you set the major
+    version number of SAGA-GIS.  
+     
 .. code-block:: guess
 
@@ -62,6 +58,8 @@
 ****************************
 
-Building the `saga2zcfg
-<http://zoo-project.org/trac/browser/trunk/thirds/otb2zcfg >`_ utility is required to activate the available SAGA-GIS Modules as WPS Services. This can be done using the following command:
+Building the
+`saga2zcfg <http://zoo-project.org/trac/browser/trunk/thirds/saga2zcfg>`_
+utility is required to activate the available SAGA-GIS Modules as WPS
+Services. This can be done using the following command: 
 
 .. code-block:: guess
Index: trunk/docs/services/howtos.rst
===================================================================
--- trunk/docs/services/howtos.rst	(revision 889)
+++ trunk/docs/services/howtos.rst	(revision 917)
@@ -439,2 +439,76 @@
   }
 
+
+R
+----------
+
+ZOO API
+*********
+
+For using the R language from the ZOO-Project, you have first to copy
+``minimal.r`` in the same directory as the ZOO-Kernel.
+
+The ZOO-API is available from a R script and provide access to a
+global zoo environment which contains both static variables and also
+the dictionaries for outputs and conf:
+
+:int zoo[["SERVICE_SUCCEEDED"]]:
+   Value to return in case your service end successfully.
+:int zoo[["SERVICE_FAILED"]]:
+   Value to retrun in case of failure.
+
+The ZOO-API provides the following functions:
+
+:string ZOOTranslate(String s):
+   This function call the internal ZOO-Kernel function responsible for
+   searching a translation of ``s`` in the zoo-services dictionary.
+
+:void ZOOUpdateStatus(ZMaps conf,String pourcent):
+   This function call the updateStatus ZOO-Kernel function responsible
+   for updating the status of the running service (only usefull when
+   the service has been called asynchronously).
+
+
+R ZCFG requirements
+**********************************
+
+.. Note:: For each Service provided by your ZOO R Services Provider,
+	  the ZCFG File must be named the same as the R function name
+	  (it is case-sensitive).
+
+The ZCFG file should contain the following :
+
+serviceType
+   R 
+serviceProvider
+    The name of the R file to use as a ZOO Service Provider. For instance, if your
+    script, located in the same directory as your ZOO Kernel, was named ``my_module.r`` then
+    you should use ``my_module.r``.
+
+
+R Data Structure used
+********************************
+
+The three parameters of the function are passed to the R function as
+R dictionaries.
+
+The specificity of the R language make that it was easier to use
+global variales than passing parameters by reference as we do in
+other progamming languages. It is the reason why you will have to
+access outpus by using the global variable as for the main
+configuration dictionary. 
+
+Sample ZOO R Services Provider
+******************************************
+
+.. code-block:: javascript
+
+    source("minimal.r")
+		
+    hellor <- function(a,b,c) {
+        # Set the result
+        zoo[["outputs"]][["Result"]][["value"]] <<- ZOOTranslate(paste("Hello",b[["S"]][["value"]],"from the R World!",sep=" "))
+        # Return SERVICE_SUCCEEDEED
+        return(zoo[["SERVICE_SUCCEEDEED"]])
+    }
+
Index: trunk/thirds/otb2zcfg/otb2zcfg.cxx
===================================================================
--- trunk/thirds/otb2zcfg/otb2zcfg.cxx	(revision 889)
+++ trunk/thirds/otb2zcfg/otb2zcfg.cxx	(revision 917)
@@ -97,23 +97,58 @@
   std::cout << "    </Supported>" << std::endl;
   std::cout << "    <Supported>" << std::endl;
+  std::cout << "     mimeType = application/json" << std::endl;
+  std::cout << "     encoding = utf-8" << std::endl;
+  std::cout << "    </Supported>" << std::endl;
+  std::cout << "    <Supported>" << std::endl;
   std::cout << "     mimeType = application/zip" << std::endl;
   std::cout << "    </Supported>" << std::endl;
 }
 
-void printOutputImage(){
+void printOutputImage(ImagePixelType pt){
   std::cout << "   <LiteralData>" << std::endl;
   std::cout << "    dataType = string" << std::endl;
   std::cout << "    <Default>" << std::endl;
-  std::cout << "     value = float" << std::endl;
-  std::cout << "     AllowedValues = uint8,uint16,int16n,int32,int32,float,double" << std::endl;
+  // Check for the default pixel type
+  switch(pt){
+  case ImagePixelType_uint8:
+    std::cout << "     value = uint8" << std::endl;
+    break;
+  case ImagePixelType_int16:
+    std::cout << "     value = int16" << std::endl;
+    break;
+  case ImagePixelType_uint16:
+    std::cout << "     value = uint16" << std::endl;
+    break;
+  case ImagePixelType_int32:
+    std::cout << "     value = int32" << std::endl;
+    break;
+  case ImagePixelType_uint32:
+    std::cout << "     value = uint8" << std::endl;
+    break;
+  case ImagePixelType_double:
+    std::cout << "     value = uint8" << std::endl;
+    break;
+  default:
+    std::cout << "     value = float" << std::endl;
+    break;
+  }
+  std::cout << "     AllowedValues = uint8,uint16,int16,int32,int32,float,double" << std::endl;
   std::cout << "    </Default>" << std::endl;
   std::cout << "   </LiteralData>" << std::endl;
 }
 
-void printOutputComplexImage(){
+void printOutputComplexImage(ComplexImagePixelType pt){
   std::cout << "   <LiteralData>" << std::endl;
   std::cout << "    dataType = string" << std::endl;
   std::cout << "    <Default>" << std::endl;
-  std::cout << "     value = cfloat" << std::endl;
+  // Check for the default pixel type
+  switch(pt){
+  case ComplexImagePixelType_double:
+    std::cout << "     value = cdouble" << std::endl;
+    break;
+  default:
+    std::cout << "     value = cfloat" << std::endl;
+    break;
+  }
   std::cout << "     AllowedValues = cfloat,cdouble" << std::endl;
   std::cout << "    </Default>" << std::endl;
@@ -242,9 +277,10 @@
 	  }
 	  else{
-	    if(type == ParameterType_OutputImage)
-	      printOutputImage();
+	    if(type == ParameterType_OutputImage){
+	      printOutputImage(m_Application->GetParameterOutputImagePixelType(paramKey));
+	    }
 	    else{
 	      if(type == ParameterType_ComplexOutputImage){
-		printOutputComplexImage();
+		printOutputComplexImage(m_Application->GetParameterComplexOutputImagePixelType(paramKey));
 	      }else{
 		std::cout << "   <ComplexData>" << std::endl;
@@ -312,4 +348,5 @@
 	  std::string s=m_Application->GetParameterDescription(paramKey);
 	  if(s.length()>0){
+	    s=ReplaceAll(ReplaceAll(s,std::string("\n"),std::string("")),std::string("\t"),std::string(""));
 	    std::cout << "   Title = " << s << std::endl;
 	    std::cout << "   Abstract = " << s << std::endl;
Index: trunk/thirds/saga2zcfg/saga2zcfg.c
===================================================================
--- trunk/thirds/saga2zcfg/saga2zcfg.c	(revision 889)
+++ trunk/thirds/saga2zcfg/saga2zcfg.c	(revision 917)
@@ -5,5 +5,5 @@
 
 #include <api_core.h>
-#include <module_library.h>
+#include <saga_api.h>
 
 int Callback(TSG_UI_Callback_ID ID, CSG_UI_Parameter &Param_1, CSG_UI_Parameter &Param_2){
@@ -144,22 +144,41 @@
   static bool g_bShow_Messages = false;
   SG_Set_UI_Callback(Get_Callback());
+#if SAGA_MAJOR_VERSION == 2
   int n = SG_Get_Module_Library_Manager().Add_Directory(wxT(MODULE_LIBRARY_PATH),false);
-  if( SG_Get_Module_Library_Manager().Get_Count() <= 0 ){
+  if( SG_Get_Module_Library_Manager().Get_Count() <= 0 )
+#else
+  int n = SG_Get_Tool_Library_Manager().Add_Directory(wxT(MODULE_LIBRARY_PATH),false);
+  if( SG_Get_Tool_Library_Manager().Get_Count() <= 0 )
+#endif
+  {
     fprintf(stderr,"could not load any tool library");
     return -2;
   }
 
-  for(int i=0;i<SG_Get_Module_Library_Manager().Get_Count();i++){
+#if SAGA_MAJOR_VERSION == 2
+  for(int i=0;i<SG_Get_Module_Library_Manager().Get_Count();i++)
+#else
+  for(int i=0;i<SG_Get_Tool_Library_Manager().Get_Count();i++)
+#endif
+    {
     
+#if SAGA_MAJOR_VERSION == 2
     CSG_Module_Library * library=SG_Get_Module_Library_Manager().Get_Library(i);
+#else
+    CSG_Tool_Library * library=SG_Get_Tool_Library_Manager().Get_Library(i);
+#endif
     int lc=library->Get_Count();
     if(!library->Get_Library_Name().Contains("io_")) {
 
       for(int j=0;j<lc;j++){
+#if SAGA_MAJOR_VERSION == 2
 	CSG_Module * module=library->Get_Module(j);
+#else
+	CSG_Tool * module=library->Get_Tool(j);
+#endif
 	if(module!=NULL && !module->needs_GUI() /*&& !module->is_Interactive()*/ ){
 
 	  mkdir(library->Get_Library_Name().b_str(),0755);
-
+	  
 	  FILE *stdout1=fopen((library->Get_Library_Name()+"/"+module->Get_ID()+".zcfg").b_str(),"w+");
 	  fprintf(stdout1,"[%d]\n",j);
@@ -203,4 +222,12 @@
 	      
 	    }
+	    else if(CSG_String(param->Get_Type_Identifier()).is_Same_As(CSG_String("date"),true)){
+	      printBasicMetadata(stdout1,param,false,true,true);
+	      fprintf(stdout1,"  <LiteralData>\n");
+	      fprintf(stdout1,"   dataType = date\n");
+	      fprintf(stdout1,"   <Default/>\n");
+	      fprintf(stdout1,"  </LiteralData>\n");
+	      
+	    }
 	    else if(CSG_String(param->Get_Type_Identifier()).is_Same_As(CSG_String("range"),true)){
 
@@ -212,5 +239,9 @@
 	      CSG_Parameter_Range *range=param->asRange();
 	      fprintf(stdout1,"   <Default>\n");
+#if SAGA_MAJOR_VERSION == 2
 	      fprintf(stdout1,"    value = %f\n",((CSG_Parameter_Range*)param->Get_Data())->Get_LoVal());
+#else
+	      //fprintf(stdout1,"    value = %f\n",((CSG_Parameter_Range*)param->asDataObject())->Get_Min());	      
+#endif
 	      fprintf(stdout1,"   </Default>\n");
 	      fprintf(stdout1,"  </LiteralData>\n");
@@ -220,5 +251,9 @@
 	      fprintf(stdout1,"   dataType = float\n");
 	      fprintf(stdout1,"   <Default>\n");
+#if SAGA_MAJOR_VERSION == 2
 	      fprintf(stdout1,"    value = %f\n",((CSG_Parameter_Range*)param->Get_Data())->Get_HiVal());
+#else
+	      //fprintf(stdout1,"    value = %f\n",((CSG_Parameter_Range*)param->asDataObject())->Get_Max());	      
+#endif
 	      fprintf(stdout1,"   </Default>\n");
 	      fprintf(stdout1,"  </LiteralData>\n");
@@ -280,7 +315,13 @@
 		fprintf(stdout1,"   dataType = string\n");
 		fprintf(stdout1,"   <Default>\n");
+#if SAGA_MAJOR_VERSION == 2
 		if( !param->Get_Data()->Get_Default().is_Empty() ){
 		  fprintf(stdout1,"    value = %s\n",param->Get_Data()->Get_Default().b_str());
 		}
+#else
+		if( !param->Get_Default().is_Empty() ){
+		  fprintf(stdout1,"    value = %s\n",param->Get_Default().b_str());
+		}
+#endif
 		fprintf(stdout1,"   </Default>\n");
 		fprintf(stdout1,"  </LiteralData>\n");
@@ -299,7 +340,13 @@
 
 		fprintf(stdout1,"   <Default>\n");
+#if SAGA_MAJOR_VERSION == 2
 		if( !param->Get_Data()->Get_Default().is_Empty() ){
 		  fprintf(stdout1,"    value = %s\n",param->Get_Data()->Get_Default().b_str());
 		}
+#else
+		if( !param->Get_Default().is_Empty() ){
+		  fprintf(stdout1,"    value = %s\n",param->Get_Default().b_str());
+		}
+#endif
 		if(param->asValue()->has_Minimum() && param->asValue()->has_Maximum()){
 		  fprintf(stdout1,"    rangeMin = %f\n",param->asValue()->Get_Minimum());
@@ -314,7 +361,13 @@
 		fprintf(stdout1,"   dataType = bool\n");
 		fprintf(stdout1,"   <Default>\n");
+#if SAGA_MAJOR_VERSION == 2
 		if( !param->Get_Data()->Get_Default().is_Empty() ){
 		  fprintf(stdout1,"    value = %s\n",(param->Get_Data()->Get_Default().Contains("0")?"false":"true"));
 		}
+#else
+		if( !param->Get_Default().is_Empty() ){
+		  fprintf(stdout1,"    value = %s\n",(param->Get_Default().Contains("0")?"false":"true"));
+		}
+#endif
 		fprintf(stdout1,"   </Default>\n");
 		fprintf(stdout1,"  </LiteralData>\n");	
@@ -337,7 +390,13 @@
 		  }
 		  fprintf(stdout1,"   <Default>\n");
+#if SAGA_MAJOR_VERSION == 2
 		  if( !param->Get_Data()->Get_Default().is_Empty() ){
 		    fprintf(stdout1,"    value = %s\n",CSG_String(choice->Get_Item(atoi(param->Get_Data()->Get_Default()))).b_str());
 		  }
+#else
+		  if( !param->Get_Default().is_Empty() ){
+		    fprintf(stdout1,"    value = %s\n",CSG_String(choice->Get_Item(atoi(param->Get_Default()))).b_str());
+		  }		  
+#endif
 		  fprintf(stdout1,"   </Default>\n");
 		  fprintf(stdout1,"  </LiteralData>\n");
Index: trunk/thirds/zcfg2sql/Makefile
===================================================================
--- trunk/thirds/zcfg2sql/Makefile	(revision 917)
+++ trunk/thirds/zcfg2sql/Makefile	(revision 917)
@@ -0,0 +1,16 @@
+ZRPATH=../../zoo-project
+include ${ZRPATH}/zoo-kernel/ZOOMakefile.opts
+LCFLAGS=${CFLAGS} ${ZOO_CFLAGS} ${XML2CFLAGS} ${GDAL_CFLAGS} ${PYTHONCFLAGS} -DLINUX_FREE_ISSUE #-DDEBUG
+CC=gcc
+
+ifeq (${CALLBACK_FILE},service_callback.o)
+CALLBACK_FILES=${ZRPATH}/zoo-kernel/${CALLBACK_FILE} ${ZRPATH}/zoo-kernel/ulinet.o ${ZRPATH}/zoo-kernel/caching.o
+else
+CALLBACK_FILES=
+endif
+zcfg2sql: zcfg2sql.c
+	g++ -g -O2 ${JSCFLAGS} ${RUBYCFLAGS} ${XML2CFLAGS} ${LCFLAGS} -c zcfg2sql.c  -fno-common -DPIC -o zcfg2sql.o
+	g++  ${XML2CFLAGS} ${LCFLAGS} zcfg2sql.o ${CALLBACK_FILES} ${ZRPATH}/zoo-kernel/server_internal.o ${ZRPATH}/zoo-kernel/service_internal.o ${ZRPATH}/zoo-kernel/${MS_FILE} ${ZRPATH}/zoo-kernel/response_print.o ${ZRPATH}/zoo-kernel/lex.cr.o ${ZRPATH}/zoo-kernel/lex.sr.o ${ZRPATH}/zoo-kernel/service_conf.tab.o ${ZRPATH}/zoo-kernel/main_conf_read.tab.o  ${ZRPATH}/zoo-kernel/${YAML_FILE} -o zcfg2sql -L${ZRPATH}/zoo-kernel/ ${LDFLAGS}
+
+clean:
+	rm -f zcfg2sql
Index: trunk/thirds/zcfg2sql/zcfg2sql.c
===================================================================
--- trunk/thirds/zcfg2sql/zcfg2sql.c	(revision 917)
+++ trunk/thirds/zcfg2sql/zcfg2sql.c	(revision 917)
@@ -0,0 +1,494 @@
+/*
+ * Author : Gérald FENOY
+ *
+ *  Copyright (c) 2017-2019 GeoLabs SARL. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "service.h"
+
+extern int getServiceFromFile (maps *, const char *, service **);
+
+/**
+ * Dump an elements on stderr using the SQL syntaxe
+ *
+ * @param e the elements to dump
+ */
+void dumpElementsAsSQL(const char* type,elements* e,int index,int level,FILE* f){
+  elements* tmp=e;
+  int i;
+  while(tmp!=NULL){
+    fprintf(f,"--\n-- %s %s \n--\n",type,tmp->name);
+    map* mcurs=tmp->content;
+    iotype* tmpio=tmp->defaults;
+    int ioc=0;
+    if(tmp->format!=NULL){
+      //fprintf(stderr,"%s:\n",tmp->format);
+      if(strncmp(tmp->format,"Complex",7)==0){
+	while(tmpio!=NULL){
+	  map* values[3]={
+	    getMap(tmpio->content,"mimeType"),
+	    getMap(tmpio->content,"encoding"),
+	    getMap(tmpio->content,"schema")
+	  };
+	  char cond[3][256]={
+	    "mime_type is NULL",
+	    "encoding is NULL",
+	    "schema is NULL"
+	  };
+	  char *condNames[3]={
+	    "mime_type",
+	    "encoding",
+	    "schema"
+	  };
+	  for(i=0;i<3;i++)
+	    if(values[i]!=NULL){
+	      sprintf(cond[i],"%s='%s'",condNames[i],values[i]->value);
+	    }
+	  fprintf(f,"INSERT INTO CollectionDB.ows_Format"
+		  " (def,primitive_format_id) VALUES \n(true,");
+	  fprintf(f,"(SELECT id from CollectionDB.PrimitiveFormats"
+		  " WHERE %s AND %s AND %s));\n",cond[0],cond[1],cond[2]);
+	  fprintf(f,"INSERT INTO CollectionDB.ows_DataDescription (format_id)"
+		  " VALUES ((SELECT last_value FROM CollectionDB.ows_Format_id_seq));\n");
+	  tmpio=tmpio->next;
+	  ioc++;
+	}
+      }else{
+	if(strncmp(tmp->format,"Literal",7)==0){
+	  while(tmpio!=NULL){
+	    map* values[4]={
+	      getMap(tmpio->content,"dataType"),
+	      getMap(tmpio->content,"value"),
+	      getMap(tmpio->content,"uom"),
+	      getMap(tmpio->content,"AllowedValues")
+	    };
+	    char *fields[20]={
+	      "default_value",
+	      "def"
+	    };
+	    fprintf(f,"INSERT INTO CollectionDB.LiteralDataDomain"
+		    " (def,data_type_id) VALUES \n(true,");
+	    fprintf(f,"(SELECT id from CollectionDB.PrimitiveDatatypes"
+		    " where name = '%s'));\n",values[0]->value);
+	    if(values[1]!=NULL)
+	      fprintf(f,"UPDATE CollectionDB.LiteralDataDomain \n"
+		      "set %s = $q$%s$q$ \n WHERE id = \n"
+		      "  ((SELECT last_value FROM CollectionDB.ows_DataDescription_id_seq));\n ",
+		      fields[0],values[1]->value);
+	    if(values[2]!=NULL)
+	      fprintf(f,"UPDATE CollectionDB.LiteralDataDomain \n"
+		      "set uom = (SELECT id from CollectionDB.PrimitiveUOM WHERE uom=$q$%s$q$) \n WHERE id = \n"
+		      "  (SELECT last_value FROM CollectionDB.ows_DataDescription_id_seq);\n ",
+		      values[2]->value);
+	    if(values[3]!=NULL){
+	      char *tmp=strtok(values[3]->value,",");
+	      while(tmp!=NULL){
+		fprintf(f,"INSERT INTO CollectionDB.AllowedValues (allowed_value) VALUES ('%s');\n",tmp);
+		fprintf(f,"INSERT INTO CollectionDB.AllowedValuesAssignment"
+			" (allowed_value_id,literal_data_domain_id) VALUES "
+			"((SELECT last_value FROM CollectionDB.AllowedValues_id_seq),"
+			"(SELECT last_value FROM CollectionDB.ows_DataDescription_id_seq));\n",tmp);
+		tmp=strtok(NULL,",");
+	      }
+	    }
+	    tmpio=tmpio->next;
+	    ioc++;
+	  }	  
+	}
+      }
+
+    }
+    
+    map* values[4]={
+      getMap(tmp->content,"Title"),
+      getMap(tmp->content,"Abstract"),
+      getMap(tmp->content,"minOccurs"),
+      getMap(tmp->content,"maxOccurs")
+    };
+    char *toto=",min_occurs,max_occurs";
+    if(strcmp(type,"Input")==0){
+      fprintf(f,"INSERT INTO CollectionDB.ows_Input "
+	      "(identifier,title,abstract,min_occurs,max_occurs)"
+	      " VALUES "
+	      "($q$%s$q$,\n$q$%s$q$,\n$q$%s$q$,\n%s,\n%s);\n",
+	      tmp->name,
+	      values[0]->value,
+	      values[1]->value,
+	      values[2]->value,
+	      values[3]->value
+	      );
+      if(tmp->format!=NULL)
+	fprintf(f,"INSERT INTO CollectionDB.InputDataDescriptionAssignment"
+		" (input_id,data_description_id) VALUES "
+		"((select last_value as id "
+	        "from CollectionDB.Descriptions_id_seq),"
+		"(select last_value "
+		"from CollectionDB.ows_DataDescription_id_seq));\n");
+      if(level==0)
+	fprintf(f,"INSERT INTO CollectionDB.ProcessInputAssignment"
+		"(process_id,input_id)"
+		" VALUES"
+		"((select id from pid),"
+		"(select last_value as id from CollectionDB.Descriptions_id_seq));\n");
+      else
+	fprintf(f,"INSERT INTO CollectionDB.InputInputAssignment"
+		"(parent_input,child_input)"
+		" VALUES"
+		"((select id from cid_%d),"
+		"(select last_value as id from CollectionDB.Descriptions_id_seq));\n",level-1);
+    }
+    else{
+      fprintf(f,"INSERT INTO CollectionDB.ows_Output\n"
+	      "\t(identifier,title,abstract)\n"
+	      "\t VALUES \n"
+	      "($q$%s$q$,$q$%s$q$,$q$%s$q$);\n",
+	      tmp->name,
+	      values[0]->value,
+	      values[1]->value
+	      );
+      if(tmp->format!=NULL)
+	fprintf(f,"INSERT INTO CollectionDB.OutputDataDescriptionAssignment"
+		" (output_id,data_description_id) VALUES "
+		"((select last_value as id "
+	        "from CollectionDB.Descriptions_id_seq),"
+		"(select last_value "
+		"from CollectionDB.ows_DataDescription_id_seq));\n");
+      if(level==0)
+	fprintf(f,"INSERT INTO CollectionDB.ProcessOutputAssignment"
+		"(process_id,output_id)"
+		" VALUES"
+		"((select id from pid),"
+		"(select last_value as id from CollectionDB.Descriptions_id_seq));\n");
+      else
+	fprintf(f,"INSERT INTO CollectionDB.OutputOutputAssignment"
+		"(parent_output,child_output)"
+		" VALUES"
+		"((select id from cid_%d),"
+		"(select last_value as id from CollectionDB.Descriptions_id_seq));\n",level-1);
+    }
+
+    map* mcurs1=tmp->metadata;
+    if(mcurs1!=NULL){
+      while(mcurs1!=NULL){
+	if(strncasecmp(mcurs1->name,"title",5)==0){
+	  fprintf(stdout,"INSERT INTO CollectionDB.ows_Metadata (title) "
+		  "VALUES ($q$%s$q$);\n",mcurs->value);
+	tryagain0:
+	  if(mcurs1->next!=NULL){
+	    if(strncasecmp(mcurs->next->name,"role",4)==0){
+	      fprintf(stdout,"UPDATE CollectionDB.ows_Metadata set role = \n"
+		      "$q$%s$q$ where id=(SELECT last_value FROM CollectionDB.ows_Metadata_id_seq);\n",mcurs1->next->value);
+	      mcurs1=mcurs1->next;
+	      goto tryagain0;
+	    }
+	    else{
+	      if(strncasecmp(mcurs1->next->name,"href",4)==0){
+		fprintf(stdout,"UPDATE CollectionDB.ows_Metadata set href = \n"
+			"$q$%s$q$ where id=(SELECT last_value FROM CollectionDB.ows_Metadata_id_seq);\n",mcurs1->next->value);
+		mcurs1=mcurs1->next;
+		goto tryagain0;
+	      }
+	    }
+	  }
+	  fprintf(stdout,"INSERT INTO CollectionDB.DescriptionsMetadataAssignment (descriptions_id,metadata_id) "
+		  "VALUES ((select last_value as id from CollectionDB.Descriptions_id_seq),"
+		  "(SELECT last_value FROM CollectionDB.ows_Metadata_id_seq));\n");	  
+	}
+	mcurs1=mcurs1->next;
+      }
+    }
+    mcurs=tmp->additional_parameters;
+    if(mcurs!=NULL){
+      while(mcurs!=NULL){
+	if(strncasecmp(mcurs->name,"title",5)==0){
+	  fprintf(stdout,"INSERT INTO CollectionDB.ows_AdditionalParameters (title) "
+		  "VALUES ($q$%s$q$);\n",mcurs->value);
+	tryagain:
+	  if(mcurs->next!=NULL){
+	    if(strncasecmp(mcurs->next->name,"role",4)==0){
+	      fprintf(stdout,"UPDATE CollectionDB.ows_AdditionalParameters set role = \n"
+		      "$q$%s$q$ where id=(SELECT last_value FROM CollectionDB.ows_AdditionalParameters_id_seq);\n",mcurs->next->value);
+	      mcurs=mcurs->next;
+	      goto tryagain;
+	    }
+	    else{
+	      if(strncasecmp(mcurs->next->name,"href",4)==0){
+		fprintf(stdout,"UPDATE CollectionDB.ows_AdditionalParameters set href = \n"
+			"$q$%s$q$ where id=(SELECT last_value FROM CollectionDB.ows_AdditionalParameters_id_seq);\n",mcurs->next->value);
+		mcurs=mcurs->next;
+		goto tryagain;
+	      }
+	    }
+	  }
+	  fprintf(stdout,"INSERT INTO CollectionDB.DescriptionsAdditionalParametersAssignment (descriptions_id,additional_parameters_id) "
+		  "VALUES ((select last_value as id from CollectionDB.Descriptions_id_seq),"
+		  "(SELECT last_value FROM CollectionDB.ows_AdditionalParameters_id_seq));\n");	  
+	}else{
+	  fprintf(stdout,"INSERT INTO CollectionDB.ows_AdditionalParameter (key,value,additional_parameters_id) "
+		  "VALUES ($q$%s$q$,$q$%s$q$,"
+		  "(SELECT last_value FROM CollectionDB.ows_AdditionalParameters_id_seq));\n",mcurs->name,mcurs->value);	  
+	}
+	mcurs=mcurs->next;
+      }
+    }
+
+    if(tmp->format!=NULL){
+      tmpio=tmp->supported;
+      if(strncmp(tmp->format,"Complex",7)==0){
+	while(tmpio!=NULL){
+	  map* values[3]={
+	    getMap(tmpio->content,"mimeType"),
+	    getMap(tmpio->content,"encoding"),
+	    getMap(tmpio->content,"schema")
+	  };
+	  char cond[3][256]={
+	    "mime_type is NULL",	    
+	    "encoding is NULL",
+	    "schema is NULL",
+	  };
+	  char *condNames[3]={
+	    "mime_type",
+	    "encoding",
+	    "schema"
+	  };
+	  for(i=0;i<3;i++)
+	    if(values[i]!=NULL){
+	      sprintf(cond[i],"%s='%s'",condNames[i],values[i]->value);
+	    }
+	  fprintf(f,"INSERT INTO CollectionDB.ows_Format"
+		  " (def,primitive_format_id) VALUES \n(false,");
+	  fprintf(f,"(SELECT id from CollectionDB.PrimitiveFormats"
+		  " WHERE %s AND %s AND %s));\n",cond[0],cond[1],cond[2]);
+	  fprintf(f,"INSERT INTO CollectionDB.ows_DataDescription (format_id)"
+		  " VALUES ((SELECT last_value FROM CollectionDB.ows_Format_id_seq));\n");
+	  fprintf(f,"INSERT INTO CollectionDB.%sDataDescriptionAssignment"
+		  " (%s_id,data_description_id) VALUES "
+		  "((select last_value as id "
+		  "from CollectionDB.Descriptions_id_seq),"
+		  "(select last_value "
+		  "from CollectionDB.ows_DataDescription_id_seq));\n",
+		  type,type);	  
+	  tmpio=tmpio->next;
+	  ioc++;
+	}
+      }else{
+	if(strncmp(tmp->format,"Literal",7)==0){
+	  while(tmpio!=NULL){
+	    map* values[4]={
+	      getMap(tmpio->content,"dataType"),
+	      getMap(tmpio->content,"value"),
+	      getMap(tmpio->content,"uom"),
+	      getMap(tmpio->content,"AllowedValues")
+	    };
+	    map* values0[4]={
+	      getMap(tmp->defaults->content,"dataType"),
+	      getMap(tmp->defaults->content,"value"),
+	      getMap(tmp->defaults->content,"uom"),
+	      getMap(tmp->defaults->content,"AllowedValues")
+	    };
+	    char *fields[20]={
+	      "default_value",
+	      "def"
+	    };
+	    fprintf(f,"INSERT INTO CollectionDB.LiteralDataDomain"
+		    " (def,data_type_id) VALUES \n(false,");
+	    if(values[0]!=NULL)
+	      fprintf(f,"(SELECT id from CollectionDB.PrimitiveDatatypes"
+		      " where name = '%s'));\n",values[0]->value);
+	    else
+	      fprintf(f,"(SELECT id from CollectionDB.PrimitiveDatatypes"
+		      " where name = '%s'));\n",values0[0]->value);
+	    if(values[1]!=NULL)
+	      fprintf(f,"UPDATE CollectionDB.LiteralDataDomain \n"
+		      "set %s = $q$%s$q$ \n WHERE id = \n"
+		      "  ((SELECT last_value FROM CollectionDB.ows_DataDescription_id_seq));\n ",
+		      fields[0],values[1]->value);
+	    if(values[2]!=NULL)
+	      fprintf(f,"UPDATE CollectionDB.LiteralDataDomain \n"
+		      "set uom = (SELECT id from CollectionDB.PrimitiveUOM WHERE uom=$q$%s$q$) \n WHERE id = \n"
+		      "  (SELECT last_value FROM CollectionDB.ows_DataDescription_id_seq);\n ",
+		      values[2]->value);
+	    if(type!=NULL)
+	    fprintf(f,"INSERT INTO CollectionDB.%sDataDescriptionAssignment"
+		    " (%s_id,data_description_id) VALUES "
+		    "((select last_value "
+		    "from CollectionDB.Descriptions_id_seq),"
+		    "(select last_value "
+		    "from CollectionDB.ows_DataDescription_id_seq));\n",
+		    type,type);	  
+	    tmpio=tmpio->next;
+	    ioc++;
+	  }	  
+	}
+      }
+    }
+
+    if(tmp->format==NULL){
+      fprintf(f,"--\n-- Child %d \n--\n",level);
+      fprintf(f,"CREATE TEMPORARY TABLE cid_%d AS (select last_value as id from CollectionDB.Descriptions_id_seq) ;\n",level);
+      if(tmp->child!=NULL)
+	dumpElementsAsSQL(type,tmp->child,0,level+1,f);
+      fprintf(f,"DROP TABLE cid_%d;\n",level);
+      fprintf(f,"--\n-- End Child %d \n--\n",level);
+    }
+    tmp=tmp->next;
+  }
+}
+
+
+int main(int argc, char *argv[]) {
+  service* s=NULL;
+  maps *m=NULL;
+  char conf_file[1024];
+  snprintf(conf_file,1024,"%s",argv[1]);
+  s=(service*)malloc(SERVICE_SIZE);
+  if(s == NULL){
+    fprintf(stderr,"Unable to allocate memory");
+    return -1;
+  }
+  int t=getServiceFromFile(m,conf_file,&s);
+
+  fprintf(stdout,"--\n-- Load from %s %d \n--",__FILE__,__LINE__);
+  int i;
+  fprintf(stdout,"--\n-- Service %s\n--\n",s->name);
+  if(s->content!=NULL){
+    map* values[4]={
+      getMap(s->content,"Title"),
+      getMap(s->content,"Abstract"),
+      getMap(s->content,"serviceProvider"),
+      getMap(s->content,"serviceType")
+    };
+    fprintf(stdout,"INSERT INTO CollectionDB.zoo_DeploymentMetadata\n"
+	    "(executable_name,service_type_id)\n"
+	    "\nVALUES\n"
+	    "($q$%s$q$,\n(SELECT id from CollectionDB.zoo_ServiceTypes WHERE service_type=$q$%s$q$));\n\n",
+	    values[2]->value,
+	    values[3]->value);
+    fprintf(stdout,"INSERT INTO CollectionDB.zoo_PrivateMetadata"
+	    "(id) VALUES (default);\n"); 
+    fprintf(stdout,"INSERT INTO CollectionDB.PrivateMetadataDeploymentMetadataAssignment"
+	    "(private_metadata_id,deployment_metadata_id) VALUES \n"
+	    "((SELECT last_value FROM CollectionDB.zoo_PrivateMetadata_id_seq),\n"
+	    "(SELECT last_value FROM CollectionDB.zoo_DeploymentMetadata_id_seq));\n");
+    fprintf(stdout,"INSERT INTO CollectionDB.ows_Process\n"
+	    "(identifier,title,abstract,private_metadata_id,"
+	    "availability)\n"
+	    "\nVALUES\n"
+	    "($q$%s$q$,\n$q$%s$q$,\n$q$%s$q$,(SELECT last_value FROM CollectionDB.PrivateMetadataDeploymentMetadataAssignment_id_seq),\ntrue);\n\n",
+	    s->name,
+	    values[0]->value,
+	    values[1]->value);
+    fprintf(stdout,"CREATE TEMPORARY TABLE pid AS "
+	    "(select last_value as id from CollectionDB.Descriptions_id_seq);\n");
+    map* mcurs=s->content;
+    //dumpMap(mcurs);
+    mcurs=s->metadata;
+    if(mcurs!=NULL){
+      while(mcurs!=NULL){
+	if(strncasecmp(mcurs->name,"title",5)==0){
+	  fprintf(stdout,"INSERT INTO CollectionDB.ows_Metadata (title) "
+		  "VALUES ($q$%s$q$);\n",mcurs->value);
+	tryagain0:
+	  if(mcurs->next!=NULL){
+	    if(strncasecmp(mcurs->next->name,"role",4)==0){
+	      fprintf(stdout,"UPDATE CollectionDB.ows_Metadata set role = \n"
+		      "$q$%s$q$ where id=(SELECT last_value FROM CollectionDB.ows_Metadata_id_seq);\n",mcurs->next->value);
+	      mcurs=mcurs->next;
+	      goto tryagain0;
+	    }
+	    else{
+	      if(strncasecmp(mcurs->next->name,"href",4)==0){
+		fprintf(stdout,"UPDATE CollectionDB.ows_Metadata set href = \n"
+			"$q$%s$q$ where id=(SELECT last_value FROM CollectionDB.ows_Metadata_id_seq);\n",mcurs->next->value);
+		mcurs=mcurs->next;
+		goto tryagain0;
+	      }
+	    }
+	  }
+	  fprintf(stdout,"INSERT INTO CollectionDB.DescriptionsMetadataAssignment (descriptions_id,metadata_id) "
+		  "VALUES ((select last_value as id from CollectionDB.Descriptions_id_seq),"
+		  "(SELECT last_value FROM CollectionDB.ows_Metadata_id_seq));\n");	  
+	}
+	mcurs=mcurs->next;
+      }
+    }
+    mcurs=s->additional_parameters;
+    if(mcurs!=NULL){
+      while(mcurs!=NULL){
+	if(strncasecmp(mcurs->name,"title",5)==0){
+	  fprintf(stdout,"INSERT INTO CollectionDB.ows_AdditionalParameters (title) "
+		  "VALUES ($q$%s$q$);\n",mcurs->value);
+	tryagain:
+	  if(mcurs->next!=NULL){
+	    if(strncasecmp(mcurs->next->name,"role",4)==0){
+	      fprintf(stdout,"UPDATE CollectionDB.ows_AdditionalParameters set role = \n"
+		      "$q$%s$q$ where id=(SELECT last_value FROM CollectionDB.ows_AdditionalParameters_id_seq);\n",mcurs->next->value);
+	      mcurs=mcurs->next;
+	      goto tryagain;
+	    }
+	    else{
+	      if(strncasecmp(mcurs->next->name,"href",4)==0){
+		fprintf(stdout,"UPDATE CollectionDB.ows_AdditionalParameters set href = \n"
+			"$q$%s$q$ where id=(SELECT last_value FROM CollectionDB.ows_AdditionalParameters_id_seq);\n",mcurs->next->value);
+		mcurs=mcurs->next;
+		goto tryagain;
+	      }
+	    }
+	  }
+	  fprintf(stdout,"INSERT INTO CollectionDB.DescriptionsAdditionalParametersAssignment (descriptions_id,additional_parameters_id) "
+		  "VALUES ((select last_value as id from CollectionDB.Descriptions_id_seq),"
+		  "(SELECT last_value FROM CollectionDB.ows_AdditionalParameters_id_seq));\n");	  
+	}else{
+	  fprintf(stdout,"INSERT INTO CollectionDB.ows_AdditionalParameter (key,value,additional_parameters_id) "
+		  "VALUES ($q$%s$q$,$q$%s$q$,"
+		  "(SELECT last_value FROM CollectionDB.ows_AdditionalParameters_id_seq));\n",mcurs->name,mcurs->value);	  
+	}
+	mcurs=mcurs->next;
+      }
+    }
+    
+  }
+  if(s->inputs!=NULL){
+    //fprintf(stderr,"\ninputs:\n");
+    dumpElementsAsSQL("Input",s->inputs,0,0,stdout);
+  }
+  if(s->outputs!=NULL){
+    //fprintf(stderr,"\noutputs:\n");
+    dumpElementsAsSQL("Output",s->outputs,0,0,stdout);
+  }
+  fprintf(stdout,"--\n-- Load from %s %d \n--",__FILE__,__LINE__);
+
+  
+  
+  /*fprintf(stderr,"--\n-- Load from %s %d \n--",__FILE__,__LINE__);
+  fflush(stderr);
+  printf("--\n-- Load from %s %d \n--",__FILE__,__LINE__);
+  if(t>=0){
+    fprintf(stderr,"--\n-- Service %s\n--",s->name);
+    fflush(stderr);
+    dumpServiceAsSQL(s); 
+    fprintf(stderr,"--\n-- Service %s\n--",s->name);
+    fflush(stderr);
+  }
+  */
+  fflush(stderr);
+  return 0;
+}
Index: trunk/zoo-project/HISTORY.txt
===================================================================
--- trunk/zoo-project/HISTORY.txt	(revision 889)
+++ trunk/zoo-project/HISTORY.txt	(revision 917)
@@ -1,3 +1,48 @@
 Version 1.7.0-dev
+  * Fix issue with UOM definitions in zcfg2sql
+  * Make callback and HPC support independent from each other
+  * Update SAGA-GIS support to version 7.2.0
+  * Add support for custom MapServer style definition for raster output
+  * Fix returned bbox definition #170 
+  * Store semaphore status in lenv section for future deletion 
+  * Update Windows support to newer compiler
+  * Fix issue with UpdateStatus function from the Mono ZOO-API
+  * Add logging functionality and other utility functions to the C-API
+  * Return an exception for every output for which nb_pixel or
+  nb_features is 0 
+  * Add a shared key to the security section to differentiate the
+  referenced data 
+  * Add MapServer output style definition depending on the geometry
+  type 
+  * Add ogr.tindex service
+  * Add support for literaldata input arrays and to call services
+  asyncrhonously from the JavaScript ZOO-API   
+  * Expose a sleep function to the JavaScript ZOO-API
+  * Provide FinalizeHPC and FinalizeHPC1 services using scontrol and
+  sacct respectively  
+  * Store md5sum of the cached file (so, local to the WPS server) to
+  compare before uploading (if different md5sum) on the HPC server 
+  * Add support for R language
+  * Add support for using "file://"  for referenced data input
+  * Add an optional ecookie key for returning third-party cookies
+  * Fix issue when parsing BoundingBox input #163 
+  * Add memory key to the main section to force the ZOO-Kernel to load
+  data into memory or use local file 
+  * Add the dialect input to the ogr2ogr service
+  * Store the list of generated mapfiles in a file (cf DeleteData service)
+  * Define the correct MS_IMAGEMODE in the generated mapfile 
+  * Option to use MapServer support to publish heatmap
+  * Add status_code key to the lenv for setting Status HTTP response header 
+  * Add the Creation Option inputs to the Gdal_Dem service
+  * Add prohibited key in the callback section to define a list of
+  services not requiring any invocation
+  * Produce zcfg for OTB applications using the correct default pixel type
+  * Add asynchronous callback invocation to send information about
+  the ongoing services to a third-party software
+  * Add mapsToJson, mapsToJson, and elementsToJson to the API 
+  * Provide a zcfg2sql tool to convert a zcfg metadata file to SQL script
+  * Add support to store service metadata information into a database
+  * Add HPC Support for remote execution of SBATCH scripts through Slurm
+  * Add cookie reference to _HINTERNET
   * Support headers for GET requests from the js ZOO-API 
   * Pass all headers listed in the attributes parameter from the
Index: trunk/zoo-project/zoo-api/js/ZOO-api.js
===================================================================
--- trunk/zoo-project/zoo-api/js/ZOO-api.js	(revision 889)
+++ trunk/zoo-project/zoo-api/js/ZOO-api.js	(revision 917)
@@ -3686,12 +3686,32 @@
 	}
 	var builder = this.parseData[data.localName().toLowerCase()];
-	if (builder)
+	if (builder){
 	  res.push(builder.apply(this,[data]));
+	}
 	else
 	  res.push(null);
+	data=null;
       }
       return res.length>1?res:res[0];
-    } else
-      return null;
+    }
+    else{
+      var hasPercentCompleted=true;
+      var status = node.*::Status.*::ProcessStarted;
+      var msg = node.*::Status.*::ProcessStarted.*::*[0];
+      if(!status || !msg){
+        status = node.*::Status.*::ProcessAccepted;
+	msg = node.*::Status.*::ProcessAccepted.*::*[0];
+	msg=msg.toString();
+        hasPercentCompleted=false;
+      }else
+	  msg=msg.toString();
+      if(status!=null && node.@statusLocation){
+        var res={"status": node.@statusLocation.toXMLString(), "message": msg};
+	if(hasPercentCompleted)
+	  res["percentCompleted"]=status.@percentCompleted.toXMLString();
+        return res;
+      }else
+	return null;
+    }
   },
   /**
@@ -3748,6 +3768,8 @@
      * {Object} A WPS reference response.
      */
-    'reference': function(node) {
-      var result = {type:'reference',value:node.@href};
+    'reference': function(lnode) {
+      var lhref=lnode.@href;
+      var lmimeType=lnode.@mimeType;
+      var result = {type:'reference',value:lhref.toXMLString(),mimeType:lmimeType.toXMLString()};
       return result;
     }
@@ -6147,4 +6169,9 @@
   identifier: null,
   /**
+   * Property: async
+   * {Bool} Define if the process should run asyncrhonously (true) or not (false, default).
+   */
+  async: null,
+  /**
    * Constructor: ZOO.Process
    * Create a new Process
@@ -6158,4 +6185,5 @@
     this.url = url;
     this.identifier = identifier;
+    this.async = (arguments.length>2?arguments[2]:false);
   },
   /**
@@ -6173,10 +6201,10 @@
     if (this.identifier == null)
       return null;
-    var body = new XML('<wps:Execute service="WPS" version="1.0.0" xmlns:wps="'+this.namespaces['wps']+'" xmlns:ows="'+this.namespaces['ows']+'" xmlns:xlink="'+this.namespaces['xlink']+'" xmlns:xsi="'+this.namespaces['xsi']+'" xsi:schemaLocation="'+this.schemaLocation+'"><ows:Identifier>'+this.identifier+'</ows:Identifier>'+this.buildDataInputsNode(inputs)+this.buildDataOutputsNode(outputs)+'</wps:Execute>');
+      var body = new XML('<wps:Execute service="WPS" version="1.0.0" xmlns:wps="'+this.namespaces['wps']+'" xmlns:ows="'+this.namespaces['ows']+'" xmlns:xlink="'+this.namespaces['xlink']+'" xmlns:xsi="'+this.namespaces['xsi']+'" xsi:schemaLocation="'+this.schemaLocation+'"><ows:Identifier>'+this.identifier+'</ows:Identifier>'+this.buildDataInputsNode(inputs)+this.buildDataOutputsNode(outputs)+'</wps:Execute>');
     body = body.toXMLString();
     var headers=['Content-Type: text/xml; charset=UTF-8'];
-      if(arguments.length>2){
-	headers[headers.length]=arguments[2];
-      }
+    if(arguments.length>2){
+      headers[headers.length]=arguments[2];
+    }
     var response = ZOO.Request.Post(this.url,body,headers);
     return response;
@@ -6195,5 +6223,10 @@
      */
     'ResponseDocument': function(identifier,obj) {
-      var output = new XML('<wps:ResponseForm xmlns:wps="'+this.namespaces['wps']+'"><wps:ResponseDocument><wps:Output'+(obj["mimeType"]?' mimeType="'+obj["mimeType"]+'" ':'')+(obj["encoding"]?' encoding="'+obj["encoding"]+'" ':'')+(obj["asReference"]?' asReference="'+obj["asReference"]+'" ':'')+'><ows:Identifier xmlns:ows="'+this.namespaces['ows']+'">'+identifier+'</ows:Identifier></wps:Output></wps:ResponseDocument></wps:ResponseForm>');
+      var output = new XML('<wps:Output xmlns:wps="'+this.namespaces['wps']+'" '+(obj["mimeType"]?' mimeType="'+obj["mimeType"]+'" ':'')+(obj["encoding"]?' encoding="'+obj["encoding"]+'" ':'')+(obj["asReference"]?' asReference="'+obj["asReference"]+'" ':'')+'><ows:Identifier xmlns:ows="'+this.namespaces['ows']+'">'+identifier+'</ows:Identifier></wps:Output>');
+      output = output.toXMLString();
+      return output;
+    },
+    'RawDataOutput': function(identifier,obj) {
+      var output = new XML('<wps:RawDataOutput xmlns:wps="'+this.namespaces['wps']+'" '+(obj["mimeType"]?' mimeType="'+obj["mimeType"]+'" ':'')+(obj["encoding"]?' encoding="'+obj["encoding"]+'" ':'')+'><ows:Identifier xmlns:ows="'+this.namespaces['ows']+'">'+identifier+'</ows:Identifier></wps:RawDataOutput>');
       if (obj.encoding)
         output.*::Data.*::ComplexData.@encoding = obj.encoding;
@@ -6202,13 +6235,4 @@
       output = output.toXMLString();
       return output;
-    },
-    'RawDataOutput': function(identifier,obj) {
-      var output = new XML('<wps:ResponseForm xmlns:wps="'+this.namespaces['wps']+'"><wps:RawDataOutput '+(obj["mimeType"]?' mimeType="'+obj["mimeType"]+'" ':'')+(obj["encoding"]?' encoding="'+obj["encoding"]+'" ':'')+'><ows:Identifier xmlns:ows="'+this.namespaces['ows']+'">'+identifier+'</ows:Identifier></wps:RawDataOutput></wps:ResponseForm>');
-      if (obj.encoding)
-        output.*::Data.*::ComplexData.@encoding = obj.encoding;
-      if (obj.schema)
-        output.*::Data.*::ComplexData.@schema = obj.schema;
-      output = output.toXMLString();
-      return output;
     }
 
@@ -6231,9 +6255,9 @@
      */
     'complex': function(identifier,data) {
-      var input = new XML('<wps:Input xmlns:wps="'+this.namespaces['wps']+'"><ows:Identifier xmlns:ows="'+this.namespaces['ows']+'">'+identifier+'</ows:Identifier>'+(data.value?'<wps:Data><wps:ComplexData><![CDATA['+data.value+']]></wps:ComplexData></wps:Data>':(data.xlink?'<wps:Reference xmlns:xlink="'+this.namespaces['xlink']+'" xlink:href="'+data.xlink+'" mimeType="'+data.mimeType+'" />':''))+'</wps:Input>');
+      var input = new XML('<wps:Input xmlns:wps="'+this.namespaces['wps']+'"><ows:Identifier xmlns:ows="'+this.namespaces['ows']+'">'+identifier+'</ows:Identifier>'+(data.value?'<wps:Data><wps:ComplexData '+(data.mimeType?'mimeType="'+data.mimeType+'"':"")+'><![CDATA['+data.value+']]></wps:ComplexData></wps:Data>':(data.xlink?'<wps:Reference xmlns:xlink="'+this.namespaces['xlink']+'" xlink:href="'+data.xlink+'" mimeType="'+data.mimeType+'" />':''))+'</wps:Input>');
       if(data.xlink)
-	input.*::Reference.@mimeType = data.mimetype ? data.mimetype : 'application/json';
+        input.*::Reference.@mimeType = data.mimetype ? data.mimetype : 'application/json';
       else
-	input.*::Data.*::ComplexData.@mimeType = data.mimetype ? data.mimetype : 'application/json';
+        input.*::Data.*::ComplexData.@mimeType = data.mimetype ? data.mimetype : 'application/json';
       if (data.encoding)
         input.*::Data.*::ComplexData.@encoding = data.encoding;
@@ -6241,5 +6265,8 @@
         input.*::Data.*::ComplexData.@schema = data.schema;
       input = input.toXMLString();
-      return input;
+      if(data.value)
+        return (('<wps:Input xmlns:wps="'+this.namespaces['wps']+'"><ows:Identifier xmlns:ows="'+this.namespaces['ows']+'">'+identifier+'</ows:Identifier>'+(data.value?'<wps:Data><wps:ComplexData '+(data.mimeType?'mimeType="'+data.mimeType+'"':"")+'><![CDATA['+data.value+']]></wps:ComplexData></wps:Data>':(data.xlink?'<wps:Reference xmlns:xlink="'+this.namespaces['xlink']+'" xlink:href="'+data.xlink+'" mimeType="'+data.mimeType+'" />':''))+'</wps:Input>'));
+      else
+        return input;
     },
     /**
@@ -6269,25 +6296,24 @@
      */
     'literal': function(identifier,data) {
-	if(data && !eval(data["isArray"])){
-	    var input = new XML('<wps:Input xmlns:wps="'+this.namespaces['wps']+'"><ows:Identifier xmlns:ows="'+this.namespaces['ows']+'">'+identifier+'</ows:Identifier><wps:Data><wps:LiteralData>'+data.value+'</wps:LiteralData></wps:Data></wps:Input>');
-      if (data.type)
-        input.*::Data.*::LiteralData.@dataType = data.type;
-      if (data.uom)
-        input.*::Data.*::LiteralData.@uom = data.uom;
-      input = input.toXMLString();
-      return input;
-	}else if(data){
-	    var inputf="";
-	    for(i=0;i<parseInt(data["length"]);i++){
-		var input = new XML('<wps:Input xmlns:wps="'+this.namespaces['wps']+'"><ows:Identifier xmlns:ows="'+this.namespaces['ows']+'">'+identifier+'</ows:Identifier><wps:Data><wps:LiteralData>'+data.value[i]+'</wps:LiteralData></wps:Data></wps:Input>');
-		if (data.type)
-		    input.*::Data.*::LiteralData.@dataType = data.type;
-		if (data.uom)
-		    input.*::Data.*::LiteralData.@uom = data.uom;
-		inputf += input.toXMLString();
-	    }
-	    return inputf;
+      if(data && !eval(data["isArray"])){
+        var input = new XML('<wps:Input xmlns:wps="'+this.namespaces['wps']+'"><ows:Identifier xmlns:ows="'+this.namespaces['ows']+'">'+identifier+'</ows:Identifier><wps:Data><wps:LiteralData>'+data.value+'</wps:LiteralData></wps:Data></wps:Input>');
+        if (data.type)
+	  input.*::Data.*::LiteralData.@dataType = data.type;
+        if (data.uom)
+	  input.*::Data.*::LiteralData.@uom = data.uom;
+        input = input.toXMLString();
+        return input;
+      }else if(data){
+        var inputf="";
+        for(i=0;i<parseInt(data["length"]);i++){
+	  var input = new XML('<wps:Input xmlns:wps="'+this.namespaces['wps']+'"><ows:Identifier xmlns:ows="'+this.namespaces['ows']+'">'+identifier+'</ows:Identifier><wps:Data><wps:LiteralData>'+data.value[i]+'</wps:LiteralData></wps:Data></wps:Input>');
+	  if (data.type)
+	    input.*::Data.*::LiteralData.@dataType = data.type;
+	  if (data.uom)
+	    input.*::Data.*::LiteralData.@uom = data.uom;
+	  inputf += input.toXMLString();
 	}
-	
+        return inputf;
+      }	
     }
   },
@@ -6318,11 +6344,28 @@
 
   buildDataOutputsNode:function(outputs){
-    var data, builder, outputsArray=[];
+    var data, builder, outputsArray=[[],[]];
     for (var attr in outputs) {
       data = outputs[attr];
       builder = this.buildOutput[data.type];
-      outputsArray.push(builder.apply(this,[attr,data]));
-    }
-    return outputsArray.join('\n');
+      if(data.type=="ResponseDocument")
+        outputsArray[0].push(builder.apply(this,[attr,data]));
+      else
+        outputsArray[1].push(builder.apply(this,[attr,data]));	    
+    }
+    var responseDocuments=(outputsArray[0].length>0?
+			   new XML('<wps:ResponseDocument  '+(this.async?'storeExecuteResponse="true" status="true"':'')+' xmlns:wps="'+this.namespaces['wps']+'">'+
+				   outputsArray[0].join('\n')+
+				   '</wps:ResponseDocument>')
+			   :
+			   null);
+    var rawDataOutputs=(outputsArray[1].length>0?
+			outputsArray[1].join('\n')
+			:
+			null);
+    var res=new XML('<wps:ResponseForm xmlns:wps="'+this.namespaces['wps']+'">'+
+		    (responseDocuments!=null?responseDocuments.toXMLString():"")+
+		    (rawDataOutputs!=null?rawDataOutputs:"")+
+		    '</wps:ResponseForm>');
+    return res.toXMLString();
   },
 
Index: trunk/zoo-project/zoo-api/mono/makefile.vc
===================================================================
--- trunk/zoo-project/zoo-api/mono/makefile.vc	(revision 917)
+++ trunk/zoo-project/zoo-api/mono/makefile.vc	(revision 917)
@@ -0,0 +1,9 @@
+!INCLUDE ../../zoo-kernel/nmake.opt
+
+all: ZMaps.dll
+
+ZMaps.dll: ZMaps.cs
+	$(MONO_DIR)\bin\mcs /target:library ZMaps.cs
+
+clean:
+	erase ZMaps.dll
Index: trunk/zoo-project/zoo-api/r/minimal.r
===================================================================
--- trunk/zoo-project/zoo-api/r/minimal.r	(revision 917)
+++ trunk/zoo-project/zoo-api/r/minimal.r	(revision 917)
@@ -0,0 +1,7 @@
+ZOOTranslate <- function(a) {
+    return (.Call("ZOOTranslate",a))
+}
+
+ZOOUpdateStatus <- function(a,b) {
+    .Call("ZOOUpdateStatus",a,as.numeric(b))
+}
Index: trunk/zoo-project/zoo-client/lib/js/wps-client/zoo.js
===================================================================
--- trunk/zoo-project/zoo-client/lib/js/wps-client/zoo.js	(revision 889)
+++ trunk/zoo-project/zoo-client/lib/js/wps-client/zoo.js	(revision 917)
@@ -679,5 +679,5 @@
 
             $.ajax({
-		url: closure.statusLocation[sid]
+		url: closure.statusLocation[sid]+"&timestamp="++(new Date()).getTime()
 	    })
 		.fail(
Index: trunk/zoo-project/zoo-kernel/Makefile.in
===================================================================
--- trunk/zoo-project/zoo-kernel/Makefile.in	(revision 889)
+++ trunk/zoo-project/zoo-kernel/Makefile.in	(revision 917)
@@ -9,5 +9,5 @@
 
 service.o: service.c service.h
-	gcc ${YAML_CFLAGS} ${XML2CFLAGS} ${CFLAGS} -fPIC -c service.c
+	g++ ${YAML_CFLAGS} ${XML2CFLAGS} ${CFLAGS} -fPIC -c service.c
 
 main_conf_read.tab.c: main_conf_read.y service.h
@@ -38,9 +38,18 @@
 	gcc -fPIC ${XML2CFLAGS} ${CFLAGS} ${JSCFLAGS} ${JS_ENABLED} -c ulinet.c
 
+sshapi.o: sshapi.c
+	g++ -fPIC ${CFLAGS} -c sshapi.c
+
+service_json.o: service_json.c
+	g++ -fPIC ${JSON_CFLAGS} ${CFLAGS} -c service_json.c
+
+service_callback.o: service_callback.c
+	g++ -fPIC ${XML2CFLAGS} ${GDAL_CFLAGS} ${JSON_CFLAGS} ${CFLAGS} -c service_callback.c
+
 request_parser.o: request_parser.c request_parser.h
 	g++ -fPIC ${XML2CFLAGS} ${CFLAGS} ${JSCFLAGS} ${JS_ENABLED} -c request_parser.c
 
 sqlapi.o: sqlapi.c sqlapi.h
-	g++ -fPIC ${GDAL_CFLAGS} ${XML2CFLAGS} ${CFLAGS} ${JSCFLAGS} ${JS_ENABLED} -c sqlapi.c
+	g++ -fPIC ${METADB_ENABLED} ${GDAL_CFLAGS} ${XML2CFLAGS} ${CFLAGS} ${JSCFLAGS} ${JS_ENABLED} -c sqlapi.c
 
 caching.o: caching.c
@@ -48,14 +57,17 @@
 
 response_print.o: response_print.c response_print.h
-	g++ -fPIC ${GDAL_CFLAGS} ${XML2CFLAGS} ${CFLAGS} ${JSCFLAGS} ${JS_ENABLED} -c response_print.c
+	g++ -fPIC ${GDAL_CFLAGS} ${XML2CFLAGS} ${CFLAGS} ${JSCFLAGS} ${JS_ENABLED} ${HPC_ENABLED} -c response_print.c
 
 server_internal.o: server_internal.c server_internal.h service.h mimetypes.h
-	g++ ${GDAL_CFLAGS} ${JS_ENABLED} ${JSCFLAGS} ${XML2CFLAGS} ${CFLAGS} -fPIC -c server_internal.c
+	g++ ${JSON_CFLAGS} ${GDAL_CFLAGS} ${JS_ENABLED} ${JSCFLAGS} ${XML2CFLAGS} ${CFLAGS} -fPIC -c server_internal.c
 
 service_internal.o: service_internal.c service_internal.h service.h
-	gcc ${GDAL_CFLAGS} ${JS_ENABLED} ${JSCFLAGS} ${XML2CFLAGS} ${CFLAGS} -fPIC -c service_internal.c
+	gcc ${JSON_CFLAGS} ${GDAL_CFLAGS} ${JS_ENABLED} ${JSCFLAGS} ${XML2CFLAGS} ${CFLAGS} -fPIC -c service_internal.c
 
 service_yaml.o: service_yaml.c service.h
 	gcc ${YAML_CFLAGS} ${XML2CFLAGS} ${CFLAGS} -fPIC -c service_yaml.c
+
+meta_sql.o: meta_sql.c meta_sql.h service.h
+	g++  ${METADB_ENABLED} ${GDAL_CFLAGS} ${XML2CFLAGS} ${CFLAGS} -c meta_sql.c
 
 service_internal_ms.o: service_internal_ms.c
@@ -66,6 +78,12 @@
 	g++ ${XML2CFLAGS} ${PYTHONCFLAGS} ${CFLAGS} -c service_internal_python.c
 
+service_internal_r.o: service_internal_r.c service.h
+	g++ ${XML2CFLAGS} ${RCFLAGS} ${CFLAGS} -c service_internal_r.c
+
 service_internal_otb.o: service_internal_otb.c service_internal_otb.h service.h
 	g++ ${XML2CFLAGS} ${OTBCFLAGS} ${CFLAGS} -c service_internal_otb.c
+
+service_internal_hpc.o: service_internal_hpc.c service_internal_hpc.h service.h
+	g++  ${JSON_CFLAGS} ${XML2CFLAGS} ${HPCCFLAGS} ${CFLAGS} -c service_internal_hpc.c
 
 service_internal_saga.o: service_internal_saga.c service_internal_saga.h service.h
@@ -99,17 +117,17 @@
 	g++ -c ${XML2CFLAGS} ${PYTHONCFLAGS} ${CFLAGS} service_loader.c
 
-zoo_service_loader.o: zoo_service_loader.c service.h version.h ${MS_FILE} ${PYTHON_FILE} ${PHP_FILE} ${JAVA_FILE} ${JS_FILE} ${PERL_FILE} ${RUBY_FILE} ${YAML_FILE} ${OTB_FILE} ${SAGA_FILE} ${MONO_FILE}
-	g++ -g -O2 ${XML2CFLAGS} ${CFLAGS} ${MONO_CFLAGS} ${SAGA_CFLAGS} ${OTBCFLAGS} ${PYTHONCFLAGS} ${JAVACFLAGS} ${JSCFLAGS} ${PERLCFLAGS} ${PHPCFLAGS} ${SAGA_ENABLED} ${OTB_ENABLED} ${PYTHON_ENABLED} ${JS_ENABLED} ${PHP_ENABLED} ${PERL_ENABLED} ${JAVA_ENABLED} ${MONO_ENABLED}  -c zoo_service_loader.c  -fno-common -DPIC -o zoo_service_loader.o
+zoo_service_loader.o: zoo_service_loader.c service.h version.h ${MS_FILE} ${R_FILE} ${PYTHON_FILE} ${PHP_FILE} ${JAVA_FILE} ${JS_FILE} ${PERL_FILE} ${RUBY_FILE} ${YAML_FILE} ${OTB_FILE} ${SAGA_FILE} ${MONO_FILE} ${HPC_FILES} ${METADB_FILE}
+	g++ -g -O2 ${JSON_CFLAGS} ${GDAL_CFLAGS} ${XML2CFLAGS} ${CFLAGS} ${MONO_CFLAGS} ${SAGA_CFLAGS} ${OTBCFLAGS} ${RCFLAGS} ${PYTHONCFLAGS} ${JAVACFLAGS} ${JSCFLAGS} ${PERLCFLAGS} ${PHPCFLAGS} ${SAGA_ENABLED} ${OTB_ENABLED} ${HPC_ENABLED} ${PYTHON_ENABLED} ${R_ENABLED} ${JS_ENABLED} ${PHP_ENABLED} ${PERL_ENABLED} ${JAVA_ENABLED} ${MONO_ENABLED} ${METADB_ENABLED} -c zoo_service_loader.c  -fno-common -DPIC -o zoo_service_loader.o
 
 libzoo_service.${EXT}: version.h service_internal.o service.o sqlapi.o
-	gcc -shared  ${GDAL_CFLAGS} ${DEFAULT_OPTS} -fpic -o libzoo_service.${EXT} ${CFLAGS}  service_internal.o service.o sqlapi.o ${FCGI_LDFLAGS} ${GDAL_LIBS}
+	g++ -shared  ${GDAL_CFLAGS} ${DEFAULT_OPTS} -fpic -o libzoo_service.${EXT} ${CFLAGS}  service_internal.o service.o sqlapi.o ${FCGI_LDFLAGS} ${GDAL_LIBS} ${ZOO_LDFLAGS} ${MACOS_LD_FLAGS}
 
-zoo_loader.cgi: version.h libzoo_service.${EXT} zoo_loader.c zoo_service_loader.o  ulinet.o service.h lex.sr.o service_conf.tab.o service_conf.y ulinet.o main_conf_read.tab.o lex.cr.o request_parser.o response_print.o server_internal.o caching.o ${MS_FILE} ${PYTHON_FILE} ${PHP_FILE} ${JAVA_FILE} ${JS_FILE} ${PERL_FILE} ${RUBY_FILE} ${YAML_FILE} ${OTB_FILE} ${SAGA_FILE}
-	g++ -g -O2 ${JSCFLAGS} ${PHPCFLAGS}  ${PERLCFLAGS} ${RUBYCFLAGS}  ${JAVACFLAGS} ${XML2CFLAGS} ${PYTHONCFLAGS} ${CFLAGS} -c zoo_loader.c  -fno-common -DPIC -o zoo_loader.o
-	g++  ${JSCFLAGS} ${SAGA_CFLAGS} ${OTBCFLAGS} ${GDAL_CFLAGS} ${XML2CFLAGS} ${PHPCFLAGS} ${PERLCFLAGS} ${JAVACFLAGS} ${PYTHONCFLAGS} ${CFLAGS} zoo_loader.o zoo_service_loader.o ${MS_FILE} ${PYTHON_FILE}  ${PERL_FILE} ${PHP_FILE}  ${JS_FILE} ${JAVA_FILE} ${YAML_FILE} ${OTB_FILE} ${SAGA_FILE} ${MONO_FILE} response_print.o server_internal.o caching.o request_parser.o ulinet.o lex.cr.o lex.sr.o service_conf.tab.o main_conf_read.tab.o -o zoo_loader.cgi -L. ${LDFLAGS}
+zoo_loader.cgi: version.h libzoo_service.${EXT} zoo_loader.c zoo_service_loader.o  ulinet.o service.h lex.sr.o service_conf.tab.o service_conf.y ulinet.o main_conf_read.tab.o lex.cr.o request_parser.o response_print.o server_internal.o caching.o ${MS_FILE} ${PYTHON_FILE} ${PHP_FILE} ${JAVA_FILE} ${JS_FILE} ${PERL_FILE} ${RUBY_FILE} ${YAML_FILE} ${OTB_FILE} ${R_FILE} ${SAGA_FILE} ${HPC_FILES} ${METADB_FILE} ${JSON_FILE} ${CALLBACK_FILE}
+	g++ -g -O2 ${JSON_CFLAGS} ${JSCFLAGS} ${PHPCFLAGS}  ${PERLCFLAGS} ${RUBYCFLAGS}  ${JAVACFLAGS} ${XML2CFLAGS} ${PYTHONCFLAGS} ${CFLAGS} -c zoo_loader.c  -fno-common -DPIC -o zoo_loader.o
+	g++  ${JSON_CFLAGS} ${JSCFLAGS} ${SAGA_CFLAGS} ${OTBCFLAGS} ${GDAL_CFLAGS} ${XML2CFLAGS} ${PHPCFLAGS} ${PERLCFLAGS} ${JAVACFLAGS} ${PYTHONCFLAGS} ${CFLAGS} zoo_loader.o zoo_service_loader.o ${MS_FILE} ${PYTHON_FILE}  ${PERL_FILE} ${PHP_FILE}  ${JS_FILE} ${JAVA_FILE} ${YAML_FILE} ${OTB_FILE} ${SAGA_FILE} ${MONO_FILE} ${HPC_FILES} ${METADB_FILE} ${JSON_FILE} ${R_FILE} ${CALLBACK_FILE} response_print.o server_internal.o caching.o request_parser.o ulinet.o lex.cr.o lex.sr.o service_conf.tab.o main_conf_read.tab.o -o zoo_loader.cgi -L. ${LDFLAGS}
 
-zcfg2yaml: zcfg2yaml.c service.h lex.sr.o service_conf.tab.o service_conf.y main_conf_read.tab.o lex.cr.o response_print.o server_internal.o service_internal.o ${MS_FILE} ${YAML_FILE}
+zcfg2yaml: zcfg2yaml.c service.h lex.sr.o service_conf.tab.o service_conf.y main_conf_read.tab.o lex.cr.o response_print.o server_internal.o service_internal.o ${MS_FILE} ${YAML_FILE} ${CALLBACK_FILE}
 	g++ -g -O2 ${JSCFLAGS} ${RUBYCFLAGS} ${XML2CFLAGS} ${CFLAGS} -c zcfg2yaml.c  -fno-common -DPIC -o zcfg2yaml.o
-	g++  ${XML2CFLAGS} ${CFLAGS} zcfg2yaml.o server_internal.o service_internal.o ${MS_FILE} response_print.o lex.cr.o lex.sr.o service_conf.tab.o main_conf_read.tab.o  ${YAML_FILE} -o zcfg2yaml -L. ${LDFLAGS}
+	g++  ${XML2CFLAGS} ${CFLAGS} zcfg2yaml.o caching.o ulinet.o ${CALLBACK_FILE} server_internal.o service_internal.o ${MS_FILE} response_print.o lex.cr.o lex.sr.o service_conf.tab.o main_conf_read.tab.o  ${YAML_FILE} -o zcfg2yaml -L. ${LDFLAGS}
 
 install: zoo_loader.cgi
Index: trunk/zoo-project/zoo-kernel/ZOOMakefile.opts.in
===================================================================
--- trunk/zoo-project/zoo-kernel/ZOOMakefile.opts.in	(revision 889)
+++ trunk/zoo-project/zoo-kernel/ZOOMakefile.opts.in	(revision 917)
@@ -30,4 +30,12 @@
 YAML_FILE1=@YAML_FILE1@
 
+JSON_CFLAGS=@JSON_CPPFLAGS@
+JSON_LDFLAGS=@JSON_LDFLAGS@
+JSON_FILE=@JSON_FILE@
+
+METADB_ENABLED=@METADB@
+METADB_FILE=@METADB_FILE@
+
+
 GDAL_CFLAGS=@GDAL_CFLAGS@
 GDAL_LIBS=@GDAL_LIBS@
@@ -50,4 +58,9 @@
 PYTHON_FILE=@PYTHON_FILE@
 
+RCFLAGS=@R_CPPFLAGS@
+RLDFLAGS=@R_LDFLAGS@
+R_ENABLED=@R_ENABLED@
+R_FILE=@R_FILE@
+
 RUBYCFLAGS=@RUBY_CPPFLAGS@
 RUBYLDFLAGS=@RUBY_LDFLAGS@
@@ -68,5 +81,5 @@
 
 ZOO_CFLAGS=-I${ZRPATH}/../thirds/cgic206/ -I${ZRPATH}/zoo-kernel/
-ZOO_LDFLAGS=@OPENSSL_LDFLAGS@ -luuid
+ZOO_LDFLAGS=@OPENSSL_LDFLAGS@ @UUID_LDFLAGS@
 
 JAVACFLAGS=@JAVA_CPPFLAGS@
@@ -80,9 +93,16 @@
 PHP_FILE=@PHP_FILE@
 
-
 PERLCFLAGS=@PERL_CPPFLAGS@
 PERLLDFLAGS=@PERL_LDFLAGS@
 PERL_ENABLED=@PERL_ENABLED@
 PERL_FILE=@PERL_FILE@
+
+HPCCFLAGS=@SSH2_CPPFLAGS@ @HPC_CPPFLAGS@
+HPCLDFLAGS=@SSH2_LDFLAGS@ @HPC_LDFLAGS@
+HPC_ENABLED=@HPC_ENABLED@
+HPC_FILES=@HPC_FILES@
+
+CALLBACK_FILE=@CALLBACK_FILE@
+CALLBACK_USE=@CALLBACK_USE@
 
 OTBCFLAGS=@OTB_CPPFLAGS@
@@ -101,6 +121,6 @@
 MONO_FILE=@MONO_FILE@
 
-CFLAGS=-Wdeclaration-after-statement @RELY_ON_DB@ @DEB_DEF@ -fpic @OPENSSL_CFLAGS@ ${FCGI_CFLAGS} ${YAML_CFLAGS} ${MACOS_CFLAGS} ${MS_CFLAGS} -I../../thirds/cgic206 -I. -DLINUX_FREE_ISSUE #-DDEBUG #-DDEBUG_SERVICE_CONF
-LDFLAGS=-lzoo_service @DEFAULT_LIBS@ -L../../thirds/cgic206 -lcgic ${GDAL_LIBS} ${XML2LDFLAGS} ${PYTHONLDFLAGS} ${PERLLDFLAGS}  ${PHPLDFLAGS} ${JAVALDFLAGS} ${JSLDFLAGS}  ${FCGI_LDFLAGS} @OPENSSL_LDFLAGS@ -luuid ${MS_LDFLAGS} ${MACOS_LD_FLAGS} ${MACOS_LD_NET_FLAGS} ${YAML_LDFLAGS} ${OTBLDFLAGS} ${SAGA_LDFLAGS} ${MONO_LDFLAGS}
+CFLAGS=@CALLBACK_USE@ @SSH2_CPPFLAGS@ @PROJ_CPPFLAGS@ @RELY_ON_DB@ @DEB_DEF@ -fpic @OPENSSL_CFLAGS@ @UUID_CFLAGS@ ${FCGI_CFLAGS} ${YAML_CFLAGS} ${MACOS_CFLAGS} ${MS_CFLAGS} -I../../thirds/cgic206 -I. -DLINUX_FREE_ISSUE #-DDEBUG #-DDEBUG_SERVICE_CONF
+LDFLAGS=-lzoo_service @SSH2_LDFLAGS@ @PROJ_LDFLAGS@ @DEFAULT_LIBS@ -L../../thirds/cgic206 -lcgic ${GDAL_LIBS} ${XML2LDFLAGS} ${PYTHONLDFLAGS} ${PERLLDFLAGS} ${PHPLDFLAGS} ${JAVALDFLAGS} ${JSLDFLAGS}  ${FCGI_LDFLAGS} @OPENSSL_LDFLAGS@ @UUID_LDFLAGS@ ${MS_LDFLAGS} ${MACOS_LD_FLAGS} ${MACOS_LD_NET_FLAGS} ${YAML_LDFLAGS} ${OTBLDFLAGS} ${SAGA_LDFLAGS} ${MONO_LDFLAGS} ${RLDFLAGS} @JSON_LDFLAGS@ @XSLT_LDFLAGS@
 
 DATAROOTDIR=@datarootdir@/zoo-project
Index: trunk/zoo-project/zoo-kernel/caching.c
===================================================================
--- trunk/zoo-project/zoo-kernel/caching.c	(revision 889)
+++ trunk/zoo-project/zoo-kernel/caching.c	(revision 917)
@@ -23,14 +23,14 @@
  */
 
+#include <openssl/md5.h>
+#include <openssl/evp.h>
 #include "caching.h"
 #include "service.h"
 #include "service_internal.h"
 #include "response_print.h"
-#include <openssl/md5.h>
-#include <openssl/hmac.h>
-#include <openssl/evp.h>
-#include <openssl/bio.h>
-#include <openssl/buffer.h>
-
+#ifdef MS_FORCE_LOCAL_FILE_USE
+#include "ogr_api.h"
+#include "mapserver.h"
+#endif
 /**
  * Compute md5
@@ -41,16 +41,16 @@
  */
 char* getMd5(char* url){
-  EVP_MD_CTX md5ctx;
+  EVP_MD_CTX *md5ctx=EVP_MD_CTX_create();
   char* fresult=(char*)malloc((EVP_MAX_MD_SIZE+1)*sizeof(char));
   unsigned char result[EVP_MAX_MD_SIZE];
   unsigned int len;
-  EVP_DigestInit(&md5ctx, EVP_md5());
-  EVP_DigestUpdate(&md5ctx, url, strlen(url));
-  EVP_DigestFinal_ex(&md5ctx,result,&len);
-  EVP_MD_CTX_cleanup(&md5ctx);
+  EVP_DigestInit(md5ctx, EVP_md5());
+  EVP_DigestUpdate(md5ctx, url, strlen(url));
+  EVP_DigestFinal_ex(md5ctx,result,&len);
+  EVP_MD_CTX_destroy(md5ctx);
   int i;
   for(i = 0; i < len; i++){
     if(i>0){
-      char *tmp=strdup(fresult);
+      char *tmp=zStrdup(fresult);
       sprintf(fresult,"%s%02x", tmp,result[i]);
       free(tmp);
@@ -62,4 +62,125 @@
 }
 
+/**
+ * Compute md5 of a file
+ * 
+ * @param file the char* 
+ * @return a char* representing the md5 of the url
+ * @warning make sure to free resources returned by this function
+ */
+char* getMd5f(char* file){
+  EVP_MD_CTX *md5ctx=EVP_MD_CTX_create();
+  char* fresult=(char*)malloc((EVP_MAX_MD_SIZE+1)*sizeof(char));
+  unsigned char result[EVP_MAX_MD_SIZE];
+  unsigned int len;
+  int bytes;
+  int dlen=65536;
+  unsigned char data[65537];
+  FILE *inFile = fopen (file, "rb");
+  EVP_DigestInit(md5ctx, EVP_md5());
+  while ((bytes = fread (data, sizeof(unsigned char), dlen, inFile)) != 0)
+    EVP_DigestUpdate(md5ctx, data, bytes);
+  EVP_DigestFinal_ex(md5ctx,result,&len);
+  EVP_MD_CTX_destroy(md5ctx);
+  int i;
+  for(i = 0; i < len; i++){
+    if(i>0){
+      char *tmp=zStrdup(fresult);
+      sprintf(fresult,"%s%02x", tmp,result[i]);
+      free(tmp);
+    }
+    else
+      sprintf(fresult,"%02x",result[i]);
+  }
+  fclose (inFile);
+  return fresult;
+}
+
+
+
+/**
+ * Create a URL by appending every request header listed in the security 
+ * section.This imply that the URL will contain any authentication 
+ * informations that should be fowarded to the server from which de input
+ * was download.
+ * @param conf the main configuration maps
+ * @param request the URL to transform.
+ * @return a char* that contain the original URL plus potential header (only for
+ * hosts that are not shared).
+ * @warning Be sure to free the memory returned by this function.
+ */
+char* getFilenameForRequest(maps* conf, const char* request){
+  map* passThrough=getMapFromMaps(conf,"security","attributes");
+  map* targetHosts=getMapFromMaps(conf,"security","hosts");
+  char* passedHeader[10];
+  int cnt=0;
+  char *res=zStrdup(request);
+  char *toAppend=NULL;
+  if(passThrough!=NULL && targetHosts!=NULL){
+    char *tmp=zStrdup(passThrough->value);
+    char *token, *saveptr;
+    token = strtok_r (tmp, ",", &saveptr);
+    int i;
+    if((strstr(targetHosts->value,"*")!=NULL || isProtectedHost(targetHosts->value,request)==1) && strncasecmp(getProvenance(conf,request),"SHARED",6)!=0){
+      while (token != NULL){
+	int length=strlen(token)+6;
+	char* tmp1=(char*)malloc(length*sizeof(char));
+	map* tmpMap;
+	snprintf(tmp1,6,"HTTP_");
+	int j;
+	for(j=0;token[j]!='\0';j++){
+	  if(token[j]!='-')
+	    tmp1[5+j]=toupper(token[j]);
+	  else
+	    tmp1[5+j]='_';
+	  tmp1[5+j+1]='\0';
+	}
+	tmpMap = getMapFromMaps(conf,"renv",tmp1);
+	if(tmpMap!=NULL){
+	  if(toAppend==NULL){
+	    toAppend=(char*)malloc((strlen(tmpMap->value)+1)*sizeof(char));
+	    sprintf(toAppend,"%s",tmpMap->value);
+	  }else{
+	    char *tmp3=zStrdup(toAppend);
+	    toAppend=(char*)realloc(toAppend,(strlen(tmpMap->value)+strlen(tmp3)+2)*sizeof(char));
+	    sprintf(toAppend,"%s,%s",tmp3,tmpMap->value);
+	    free(tmp3);
+	  }
+	}
+	free(tmp1);
+	cnt+=1;
+	token = strtok_r (NULL, ",", &saveptr);
+      }
+    }
+    free(tmp);
+  }
+  if(toAppend!=NULL){
+    char *tmp3=zStrdup(res);
+    res=(char*)realloc(res,(strlen(tmp3)+strlen(toAppend)+1)*sizeof(char));
+    sprintf(res,"%s%s",tmp3,toAppend);
+    free(tmp3);
+    free(toAppend);
+  }
+  return res;
+}
+
+/**
+ * Store MD5 of the content of a file
+ * @file char* the full path of the file
+ */
+int storeMd5(char* file){
+  char* storage=zStrdup(file);
+  char* md5fstr=getMd5f(file);
+  storage[strlen(storage)-2]='m';
+  storage[strlen(storage)-1]='d';
+  FILE* fo=fopen(storage,"w+");
+  if(fo==NULL)
+    return 1;
+  fwrite(md5fstr,sizeof(char),strlen(md5fstr),fo);
+  free(md5fstr);
+  free(storage);
+  fclose(fo);
+  return 0;
+}
 
 /**
@@ -76,43 +197,153 @@
  * @param max_path the size of the allocated filepath buffer  
  */
+void cacheFile(maps* conf,char* request,char* mimeType,int length,char* filename){
+  map* tmp=getMapFromMaps(conf,"main","cacheDir");
+  char contentr[4096];
+  int cred=0;
+  if(tmp!=NULL){
+    char* myRequest=getFilenameForRequest(conf,request);
+    char* md5str=getMd5(myRequest);
+    free(myRequest);
+    char* fname=(char*)malloc(sizeof(char)*(strlen(tmp->value)+strlen(md5str)+6));
+    // Store md5
+    char* md5fstr=getMd5f(filename);
+    sprintf(fname,"%s/%s.zmd",tmp->value,md5str);
+    FILE* fo=fopen(fname,"w+");
+#ifdef DEBUG
+    fprintf(stderr,"filename: %s\n",filename);
+    fprintf(stderr,"MD5: %s\n",md5fstr);
+#endif
+    fwrite(md5fstr,sizeof(char),strlen(md5fstr),fo);
+    free(md5fstr);
+    fclose(fo);
+    
+    sprintf(fname,"%s/%s.zca",tmp->value,md5str);
+    zooLock* lck=lockFile(conf,fname,'w');
+    if(lck!=NULL){
+#ifdef DEBUG
+      fprintf(stderr,"Cache list : %s\n",fname);
+      fflush(stderr);
+#endif
+      FILE* fi=fopen(filename,"rb");
+      sprintf(fname,"%s/%s.zca",tmp->value,md5str);
+      fo=fopen(fname,"w+");
+      if(fo==NULL){
+#ifdef DEBUG
+	fprintf (stderr, "Failed to open %s for writing: %s\n",fname, strerror(errno));
+#endif
+	unlockFile(conf,lck);
+	return;
+      }
+      if(fi==NULL){
+#ifdef DEBUG
+	fprintf (stderr, "Failed to open %s for reading: %s\n",filename, strerror(errno));
+#endif
+	unlockFile(conf,lck);
+	return;
+      }
+      memset(contentr,0,4096);
+      while((cred=fread(contentr,sizeof(char),4096,fi))>0){
+	fwrite(contentr,sizeof(char),cred,fo);
+	fflush(fo);
+	memset(contentr,0,4096);
+      }
+      unlockFile(conf,lck);
+      fclose(fo);
+      fclose(fi);
+
+      // Store mimeType
+      sprintf(fname,"%s/%s.zcm",tmp->value,md5str);
+      fo=fopen(fname,"w+");
+#ifdef DEBUG
+      fprintf(stderr,"MIMETYPE: %s\n",mimeType);
+#endif
+      fwrite(mimeType,sizeof(char),strlen(mimeType),fo);
+      fclose(fo);
+
+      // Store provenance
+      sprintf(fname,"%s/%s.zcp",tmp->value,md5str);
+      fo=fopen(fname,"w+");
+      char* origin=getProvenance(conf,request);
+#ifdef DEBUG
+      fprintf(stderr,"ORIGIN: %s\n",mimeType);
+#endif
+      fwrite(origin,sizeof(char),strlen(origin),fo);
+      fclose(fo);
+
+      free(md5str);
+
+    }
+    free(fname);
+  }
+}
+
+/**
+ * Cache a file for a given request.
+ * For each cached file, the are two files stored, a .zca and a .zcm containing
+ * the downloaded content and the mimeType respectively. 
+ *
+ * @param conf the maps containing the settings of the main.cfg file
+ * @param request the url used too fetch the content
+ * @param content the downloaded content
+ * @param mimeType the content mimeType 
+ * @param length the content size
+ * @param filepath a buffer for storing the path of the cached file; may be NULL
+ * @param max_path the size of the allocated filepath buffer  
+ */
 void addToCache(maps* conf,char* request,char* content,char* mimeType,int length, 
                 char* filepath, size_t max_path){
   map* tmp=getMapFromMaps(conf,"main","cacheDir");
   if(tmp!=NULL){
-    char* md5str=getMd5(request);
+    char* myRequest=getFilenameForRequest(conf,request);
+    char* md5str=getMd5(myRequest);
+    free(myRequest);
     char* fname=(char*)malloc(sizeof(char)*(strlen(tmp->value)+strlen(md5str)+6));
     sprintf(fname,"%s/%s.zca",tmp->value,md5str);
-#ifdef DEBUG
-    fprintf(stderr,"Cache list : %s\n",fname);
-    fflush(stderr);
-#endif
-    FILE* fo=fopen(fname,"w+");
-    if(fo==NULL){
-#ifdef DEBUG
-      fprintf (stderr, "Failed to open %s for writing: %s\n",fname, strerror(errno));
-#endif
-      filepath = NULL;	
-      return;
-    }
-    fwrite(content,sizeof(char),length,fo);
-    fclose(fo);
+    zooLock* lck=lockFile(conf,fname,'w');
+    if(lck!=NULL){
+#ifdef DEBUG
+      fprintf(stderr,"Cache list : %s\n",fname);
+      fflush(stderr);
+#endif
+      FILE* fo=fopen(fname,"w+");
+      if(fo==NULL){
+#ifdef DEBUG
+	fprintf (stderr, "Failed to open %s for writing: %s\n",fname, strerror(errno));
+#endif
+	filepath = NULL;
+	unlockFile(conf,lck);
+	return;
+      }
+      fwrite(content,sizeof(char),length,fo);
+      unlockFile(conf,lck);
+      fclose(fo);
 	
-	if (filepath != NULL) {
-		strncpy(filepath, fname, max_path);
-	}	
-
-    sprintf(fname,"%s/%s.zcm",tmp->value,md5str);
-    fo=fopen(fname,"w+");
-#ifdef DEBUG
-    fprintf(stderr,"MIMETYPE: %s\n",mimeType);
-#endif
-    fwrite(mimeType,sizeof(char),strlen(mimeType),fo);
-    fclose(fo);
-
-    free(md5str);
-    free(fname);
+      if (filepath != NULL) {
+	strncpy(filepath, fname, max_path);
+      }
+
+      sprintf(fname,"%s/%s.zcm",tmp->value,md5str);
+      fo=fopen(fname,"w+");
+#ifdef DEBUG
+      fprintf(stderr,"MIMETYPE: %s\n",mimeType);
+#endif
+      fwrite(mimeType,sizeof(char),strlen(mimeType),fo);
+      fclose(fo);
+
+      sprintf(fname,"%s/%s.zcp",tmp->value,md5str);
+      fo=fopen(fname,"w+");
+      char* origin=getProvenance(conf,request);
+#ifdef DEBUG
+      fprintf(stderr,"ORIGIN: %s\n",mimeType);
+#endif
+      fwrite(origin,sizeof(char),strlen(origin),fo);
+      fclose(fo);
+
+      free(md5str);
+      free(fname);
+    }
   }
   else {
-	  filepath = NULL;
+    filepath = NULL;
   }	  
 }
@@ -127,7 +358,56 @@
  */
 char* isInCache(maps* conf,char* request){
+  map* tmpUrl=getMapFromMaps(conf,"main","tmpUrl");
   map* tmpM=getMapFromMaps(conf,"main","cacheDir");
-  if(tmpM!=NULL){
-    char* md5str=getMd5(request);
+  if(tmpM==NULL)
+    tmpM=getMapFromMaps(conf,"main","tmpPath");
+  if(strstr(request,tmpUrl->value)!=NULL){
+    map* tmpPath=getMapFromMaps(conf,"main","tmpPath");
+    char* tmpStr=strstr(request,tmpUrl->value);
+    char* tmpStr1=zStrdup(tmpStr+strlen(tmpUrl->value));
+    char* res=(char*) malloc((strlen(tmpPath->value)+strlen(tmpStr1)+2)*sizeof(char));
+    sprintf(res,"%s/%s",tmpPath->value,tmpStr1);
+    free(tmpStr1);
+    return res;
+  }
+#ifdef MS_FORCE_LOCAL_FILE_USE
+  map* msUrl=getMapFromMaps(conf,"main","mapserverAddress");
+  if(msUrl!=NULL && strstr(request,msUrl->value)!=NULL){
+    char *tmpStr=strstr(request,"?");
+    char *cursor=zStrdup(tmpStr+1);
+    char *token, *saveptr;
+    token = strtok_r (cursor, "&", &saveptr);
+    while(token!=NULL){
+      char *token1, *saveptr1;
+      token1 = strtok_r (token, "=", &saveptr1);
+      char *name=NULL;
+      while(token1!=NULL){
+	if(name==NULL)
+	  name=zStrdup(token1);
+	else
+	  if(strcasecmp(name,"map")==0){
+	    mapObj *myMap=msLoadMap(token1,NULL);
+	    char * res=zStrdup(myMap->layers[0]->data);
+	    free(name);
+	    free(cursor);
+	    msFreeMap(myMap);
+	    return res;
+	  }
+	token1 = strtok_r (NULL, "=", &saveptr1);
+      }
+      token = strtok_r (NULL, "&", &saveptr);
+    }
+    free(cursor);
+  }
+#endif  
+  if(strncasecmp(request,"file://",7)==0){
+    char* tmpStr=zStrdup(request+7);
+    fprintf(stderr,"**** %s %d %s \n",__FILE__,__LINE__,tmpStr);
+    return tmpStr;
+  }
+  else{
+    char* myRequest=getFilenameForRequest(conf,request);
+    char* md5str=getMd5(myRequest);
+    free(myRequest);
 #ifdef DEBUG
     fprintf(stderr,"MD5STR : (%s)\n\n",md5str);
@@ -135,6 +415,6 @@
     char* fname=(char*)malloc(sizeof(char)*(strlen(tmpM->value)+strlen(md5str)+6));
     sprintf(fname,"%s/%s.zca",tmpM->value,md5str);
-    struct stat f_status;
-    int s=stat(fname, &f_status);
+    zStatStruct f_status;
+    int s=zStat(fname, &f_status);
     if(s==0 && f_status.st_size>0){
       free(md5str);
@@ -158,9 +438,11 @@
  */
 int readCurrentInput(maps** m,maps** in,int* index,HINTERNET* hInternet,map** error){
+  
+  int shouldClean=-1;
   map* tmp1;
   char sindex[5];
   maps* content=*in;
   map* length=getMap(content->content,"length");
-  int shouldClean=-1;
+  map* memUse=getMapFromMaps(*m,"main","memory");
   if(length==NULL){
     length=createMap("length","1");
@@ -171,4 +453,5 @@
     char *mimeType=NULL;
     int fsize=0;
+    char oriname[12];
     char cname[15];
     char vname[11];
@@ -178,5 +461,8 @@
     char icname[14];
     char xname[16];
+    char bname[8];
+    char hname[11];
     char oname[12];
+    char ufile[12];    
     if(*index>0)
       sprintf(vname1,"value_%d",*index);
@@ -185,6 +471,7 @@
     
     if(i>0){
+      sprintf(cname,"cache_file_%d",i);
       tmp1=getMap(content->content,cname);
-      sprintf(cname,"cache_file_%d",i);
+      sprintf(oriname,"origin_%d",i);
       sprintf(vname,"value_%d",i);
       sprintf(sname,"size_%d",i);
@@ -192,7 +479,11 @@
       sprintf(icname,"isCached_%d",i);
       sprintf(xname,"Reference_%d",i);
+      sprintf(bname,"body_%d",i);
+      sprintf(hname,"headers_%d",i);
       sprintf(oname,"Order_%d",i);
+      sprintf(ufile,"use_file_%d",i);
     }else{
       sprintf(cname,"cache_file");
+      sprintf(oriname,"origin");
       sprintf(vname,"value");
       sprintf(sname,"size");
@@ -200,5 +491,8 @@
       sprintf(icname,"isCached");
       sprintf(xname,"Reference");
+      sprintf(bname,"body");
+      sprintf(hname,"headers");
       sprintf(oname,"Order");
+      sprintf(ufile,"use_file");
     }
     
@@ -206,17 +500,19 @@
     sprintf(sindex,"%d",*index+1);
     if((tmp1=getMap(content->content,xname))!=NULL && tmap!=NULL && strcasecmp(tmap->value,sindex)==0){
-      
-      if(getMap(content->content,icname)==NULL){
-	fcontent=(char*)malloc((hInternet->ihandle[*index].nDataLen+1)*sizeof(char));
-	if(fcontent == NULL){
-	  errorException(*m, _("Unable to allocate memory"), "InternalError",NULL);
-	  return -1;
+
+      if(getMap(content->content,icname)==NULL) {
+	if(memUse==NULL || strcasecmp(memUse->value,"load")==0){
+	  fcontent=(char*)malloc((hInternet->ihandle[*index].nDataLen+1)*sizeof(char));
+	  if(fcontent == NULL){
+	    errorException(*m, _("Unable to allocate memory"), "InternalError",NULL);
+	    return -1;
+	  }
+	  size_t dwRead;
+	  InternetReadFile(hInternet->ihandle[*index], 
+			   (LPVOID)fcontent, 
+			   hInternet->ihandle[*index].nDataLen, 
+			   &dwRead);
+	  fcontent[hInternet->ihandle[*index].nDataLen]=0;
 	}
-	size_t dwRead;
-	InternetReadFile(hInternet->ihandle[*index], 
-			 (LPVOID)fcontent, 
-			 hInternet->ihandle[*index].nDataLen, 
-			 &dwRead);
-	fcontent[hInternet->ihandle[*index].nDataLen]=0;
 	fsize=hInternet->ihandle[*index].nDataLen;
 	if(hInternet->ihandle[*index].mimeType==NULL)
@@ -226,10 +522,13 @@
 	
 	map* tmpMap=getMapOrFill(&(*in)->content,vname,"");
-	free(tmpMap->value);
-	tmpMap->value=(char*)malloc((fsize+1)*sizeof(char));
-	if(tmpMap->value==NULL){
-	  return errorException(*m, _("Unable to allocate memory"), "InternalError",NULL);
-	}
-	memcpy(tmpMap->value,fcontent,(fsize+1)*sizeof(char));
+	if(memUse==NULL || strcasecmp(memUse->value,"load")==0){
+	  free(tmpMap->value);
+	  tmpMap->value=(char*)malloc((fsize+1)*sizeof(char));
+	  if(tmpMap->value==NULL){
+	    return errorException(*m, _("Unable to allocate memory"), "InternalError",NULL);
+	  }
+	  memcpy(tmpMap->value,fcontent,(fsize+1)*sizeof(char));
+	}else
+	  addToMap((*in)->content,ufile,"true");
 	if(hInternet->ihandle[*index].code!=200){
 	  const char *error_rep_str=_("Unable to download the file for the input <%s>, response code was : %d.");
@@ -255,6 +554,27 @@
 	sprintf(ltmp1,"%d",fsize);
 	map* tmp=getMapFromMaps(*m,"main","cacheDir");
+	char *request=NULL;
 	if(tmp!=NULL){
-	  char* md5str=getMd5(tmp1->value);
+	  map* tmp2;
+	  char* md5str=NULL;
+	  if((tmp2=getMap(content->content,bname))!=NULL){
+	    char *tmpStr=(char*)malloc((strlen(tmp1->value)+strlen(tmp2->value)+1)*sizeof(char));
+	    sprintf(tmpStr,"%s%s",tmp1->value,tmp2->value);
+	    if((tmp2=getMap(content->content,"headers"))!=NULL){
+	      char *tmpStr2=zStrdup(tmpStr);
+	      free(tmpStr);
+	      tmpStr=(char*)malloc((strlen(tmpStr2)+strlen(tmp2->value)+1)*sizeof(char));
+	      sprintf(tmpStr,"%s%s",tmpStr2,tmp2->value);
+	      free(tmpStr2);
+	    }
+	    md5str=getMd5(tmpStr);
+	    request=zStrdup(tmpStr);
+	    free(tmpStr);
+	  }else{
+	    char *myRequest=getFilenameForRequest(*m,tmp1->value);
+	    md5str=getMd5(myRequest);
+	    request=zStrdup(tmp1->value);
+	    free(myRequest);
+	  }
 	  char* fname=(char*)malloc(sizeof(char)*(strlen(tmp->value)+strlen(md5str)+6));
 	  sprintf(fname,"%s/%s.zca",tmp->value,md5str);
@@ -264,9 +584,16 @@
 	addToMap((*in)->content,sname,ltmp1);
 	addToMap((*in)->content,mname,mimeType);
-	addToCache(*m,tmp1->value,fcontent,mimeType,fsize, NULL, 0);
-	free(fcontent);
+	char* origin=getProvenance(*m,request);
+	addToMap((*in)->content,oriname,origin);
+	if(memUse==NULL || strcasecmp(memUse->value,"load")==0){
+	  addToCache(*m,request,fcontent,mimeType,fsize, NULL, 0);
+	  free(fcontent);
+	}else{
+	  addToMap((*in)->content,ufile,"true");
+	  cacheFile(*m,request,mimeType,fsize,hInternet->ihandle[*index].filename);
+	}
 	free(mimeType);
-	*index++;
-	
+	free(request);
+	(*index)++;
       }
     }
@@ -324,7 +651,7 @@
  */
 void addRequestToQueue(maps** m,HINTERNET* hInternet,const char* url,bool req){
-  hInternet->waitingRequests[hInternet->nb]=strdup(url);
+  hInternet->waitingRequests[hInternet->nb]=zStrdup(url);
   if(req)
-    InternetOpenUrl(hInternet,hInternet->waitingRequests[hInternet->nb],NULL,0,INTERNET_FLAG_NO_CACHE_WRITE,0);
+    InternetOpenUrl(hInternet,hInternet->waitingRequests[hInternet->nb],NULL,0,INTERNET_FLAG_NO_CACHE_WRITE,0,*m);
   maps *oreq=getMaps(*m,"orequests");
   if(oreq==NULL){
@@ -335,5 +662,5 @@
     free(oreq);
   }else{
-    setMapArray(oreq->content,"value",hInternet->nb-1,url);
+    setMapArray(oreq->content,"value",hInternet->nb,url);
   }
 }
@@ -352,5 +679,7 @@
   char* cached=isInCache(*m,url);
   char *mimeType=NULL;
-  int fsize=0;
+  char *origin=NULL;
+  long long fsize=0;
+  map* memUse=getMapFromMaps(*m,"main","memory");
 
   map* t=getMap(*content,"xlink:href");
@@ -361,19 +690,29 @@
 
   if(cached!=NULL){
-
-    struct stat f_status;
-    int s=stat(cached, &f_status);
+    zStatStruct f_status;
+    int s=zStat(cached, &f_status);
     if(s==0){
-      fcontent=(char*)malloc(sizeof(char)*(f_status.st_size+1));
-      FILE* f=fopen(cached,"rb");
-      fread(fcontent,f_status.st_size,1,f);
+      zooLock* lck=lockFile(*m,cached,'r');
+      if(lck==NULL)
+	return -1;
       fsize=f_status.st_size;
-      fcontent[fsize]=0;
-      fclose(f);
+      if(memUse==NULL || strcasecmp(memUse->value,"load")==0){
+	fcontent=(char*)malloc(sizeof(char)*(f_status.st_size+1));
+	FILE* f=fopen(cached,"rb");
+	if(f!=NULL){
+	  fread(fcontent,f_status.st_size,1,f);
+	  fcontent[fsize]=0;
+	  fclose(f);
+	}
+      }
       addToMap(*content,"cache_file",cached);
+      unlockFile(*m,lck);
     }
     cached[strlen(cached)-1]='m';
-    s=stat(cached, &f_status);
+    s=zStat(cached, &f_status);
     if(s==0){
+      zooLock* lck=lockFile(*m,cached,'r');
+      if(lck==NULL)
+	return -1;
       mimeType=(char*)malloc(sizeof(char)*(f_status.st_size+1));
       FILE* f=fopen(cached,"rb");
@@ -381,6 +720,19 @@
       mimeType[f_status.st_size]=0;
       fclose(f);
-    }
-
+      unlockFile(*m,lck);
+    }
+    cached[strlen(cached)-1]='p';
+    s=zStat(cached, &f_status);
+    if(s==0){
+      zooLock* lck=lockFile(*m,cached,'r');
+      if(lck==NULL)
+	return -1;
+      origin=(char*)malloc(sizeof(char)*(f_status.st_size+1));
+      FILE* f=fopen(cached,"rb");
+      fread(origin,f_status.st_size,1,f);
+      mimeType[f_status.st_size]=0;
+      fclose(f);
+      unlockFile(*m,lck);
+    }
   }else{    
     addRequestToQueue(m,hInternet,url,true);
@@ -393,34 +745,50 @@
     addToMap(*content,"fmimeType",mimeType);
   }
+  if(origin!=NULL){
+    addToMap(*content,"origin",origin);
+  }
 
   map* tmpMap=getMapOrFill(content,"value","");
-    
-  free(tmpMap->value);
-  tmpMap->value=(char*)malloc((fsize+1)*sizeof(char));
-  if(tmpMap->value==NULL || fcontent == NULL)
-    return errorException(*m, _("Unable to allocate memory"), "InternalError",NULL);
-  memcpy(tmpMap->value,fcontent,(fsize+1)*sizeof(char));
-
+  if(memUse==NULL || strcasecmp(memUse->value,"load")==0){
+    free(tmpMap->value);
+    tmpMap->value=(char*)malloc((fsize+1)*sizeof(char));
+    if(tmpMap->value==NULL || fcontent == NULL)
+      return errorException(*m, _("Unable to allocate memory"), "InternalError",NULL);
+    memcpy(tmpMap->value,fcontent,(fsize+1)*sizeof(char));
+  }
+  
   char ltmp1[256];
-  sprintf(ltmp1,"%d",fsize);
+  sprintf(ltmp1,"%ld",fsize);
   addToMap(*content,"size",ltmp1);
   if(cached==NULL){
-    addToCache(*m,url,fcontent,mimeType,fsize, NULL, 0);
+    if(memUse==NULL || strcasecmp(memUse->value,"load")==0)
+      addToCache(*m,url,fcontent,mimeType,fsize, NULL, 0);
+    else
+      cacheFile(*m,url,mimeType,fsize,hInternet->ihandle[hInternet->nb-1].filename);
   }
   else{
     addToMap(*content,"isCached","true");
     map* tmp=getMapFromMaps(*m,"main","cacheDir");
-    if(tmp!=NULL){
+    map* tmp1=getMap((*content),"cache_file");
+    if(tmp!=NULL && tmp1==NULL){
       map *c=getMap((*content),"xlink:href");
-      char* md5str=getMd5(c->value);
-      char* fname=(char*)malloc(sizeof(char)*(strlen(tmp->value)+strlen(md5str)+6));
-      sprintf(fname,"%s/%s.zca",tmp->value,md5str);
-      addToMap(*content,"cache_file",fname);
-      free(fname);
-    }
-  }
-  free(fcontent);
-  free(mimeType);
-  free(cached);
+      if(strncasecmp(c->value,"file://",7)!=0){
+	char *myRequest=getFilenameForRequest(*m,c->value);
+	char* md5str=getMd5(myRequest);
+	free(myRequest);
+	char* fname=(char*)malloc(sizeof(char)*(strlen(tmp->value)+strlen(md5str)+6));
+	sprintf(fname,"%s/%s.zca",tmp->value,md5str);
+	addToMap(*content,"cache_file",fname);
+	free(fname);
+	free(md5str);
+      }
+    }
+  }
+  if(fcontent!=NULL)
+    free(fcontent);
+  if(mimeType!=NULL)
+    free(mimeType);
+  if(cached!=NULL)
+    free(cached);
   return 0;
 }
Index: trunk/zoo-project/zoo-kernel/caching.h
===================================================================
--- trunk/zoo-project/zoo-kernel/caching.h	(revision 889)
+++ trunk/zoo-project/zoo-kernel/caching.h	(revision 917)
@@ -35,5 +35,7 @@
   void addRequestToQueue(maps**,HINTERNET*,const char*,bool);
   int loadRemoteFile(maps**,map**,HINTERNET*,char*);
-
+  char* getMd5f(char*);
+  int storeMd5(char*);
+  
 #ifdef __cplusplus
 }
Index: trunk/zoo-project/zoo-kernel/configure.ac
===================================================================
--- trunk/zoo-project/zoo-kernel/configure.ac	(revision 889)
+++ trunk/zoo-project/zoo-kernel/configure.ac	(revision 917)
@@ -1,3 +1,5 @@
 AC_INIT([ZOO Kernel], [1.7.0], [bugs@zoo-project.org])
+
+AC_CONFIG_MACRO_DIR([macros])
 
 # Checks for programs.
@@ -12,5 +14,4 @@
 AC_CHECK_LIB([dl], [dlopen,dlsym,dlerror,dlclose])
 AC_CHECK_LIB([crypto], [EVP_DigestInit,EVP_md5,EVP_DigestUpdate,BIO_f_base64,BIO_new])
-AC_CHECK_LIB([uuid], [uuid_generate_time])
 
 DEFAULT_LIBS="$LIBS"
@@ -20,5 +21,5 @@
 # Checks for header files.
 AC_FUNC_ALLOCA
-AC_CHECK_HEADERS([fcntl.h inttypes.h libintl.h malloc.h stddef.h stdlib.h string.h unistd.h])
+AC_CHECK_HEADERS([fcntl.h inttypes.h malloc.h stddef.h stdlib.h string.h unistd.h])
 
 # Checks for typedefs, structures, and compiler characteristics.
@@ -38,4 +39,61 @@
 AC_FUNC_REALLOC
 AC_CHECK_FUNCS([dup2 getcwd memset setenv strdup strstr])
+
+#============================================================================
+# Detect if uuid is available
+#============================================================================
+
+AC_ARG_WITH([uuid],
+    [AS_HELP_STRING([--with-uuid=PATH], [Specifies an alternative location for the ossp-uuid library])],
+    [UUID_DIR="$withval"], [UUID_DIR="/usr/"])
+UUID_CFLAGS="-I$UUID_DIR/include"
+UUID_LDFLAGS="-L$UUID_DIR/lib -luuid"
+CPPFLAGS_SAVE="$CPPFLAGS"
+CPPFLAGS="$UUID_CFLAGS"
+LIBS_SAVE="$LIBS"
+LIBS="$UUID_LDFLAGS"
+AC_CHECK_HEADERS([uuid/uuid.h],
+			[], [AC_MSG_ERROR([could not find header file uuid.h])])
+AC_CHECK_LIB([uuid], [uuid_generate_time],
+			[], [AC_MSG_ERROR([could not find function in uuid library])])
+CPPFLAGS="$CPPFLAGS_SAVE"
+AC_SUBST([UUID_CFLAGS])
+AC_SUBST([UUID_LDFLAGS])
+
+#============================================================================
+# Detect if json-c is available
+#============================================================================
+
+AC_ARG_WITH([callback],
+    [AS_HELP_STRING([--with-callback=yes], [Activate callback invocation during HPC execution])],
+    [CALLBACK_ACTIVATED="$withval"], [CALLBACK_ACTIVATED="no"])
+    
+AC_ARG_WITH([json],
+    [AS_HELP_STRING([--with-json=PATH], [Specifies an alternative location for the json-c library])],
+    [JSON_DIR="$withval"], [JSON_DIR="/usr/"])
+if test "x$JSON_DIR" != "x" && test "x$CALLBACK_ACTIVATED" == "xyes"
+then
+	JSON_CPPFLAGS="-I$JSON_DIR/include/json-c/"
+	JSON_LDFLAGS="-L$JSON_DIR/lib -ljson-c"
+	CPPFLAGS_SAVE="$CPPFLAGS"
+	CPPFLAGS="$JSON_CPPFLAGS"
+	LIBS_SAVE="$LIBS"
+	LIBS="$JSON_LDFLAGS"
+	AC_CHECK_HEADERS([json_object.h],
+		[], [AC_MSG_ERROR([could not find header file json_object.h])])
+	AC_CHECK_LIB([json-c], [json_object_new_object],
+		[], [AC_MSG_ERROR([could not find function in json-c library])])
+	CPPFLAGS="$CPPFLAGS_SAVE"
+	JSON_FILE="service_json.o"
+	JSON_ENABLED="-DJSON"
+	CALLBACK_FILE="service_callback.o"
+	CALLBACK_USE="-DUSE_CALLBACK"
+fi
+AC_SUBST([JSON_CPPFLAGS])
+AC_SUBST([JSON_LDFLAGS])
+AC_SUBST([JSON_FILE])
+AC_SUBST([JSON_ENABLED])
+AC_SUBST([CALLBACK_FILE])
+AC_SUBST([CALLBACK_USE])
 
 #============================================================================
@@ -56,6 +114,27 @@
 AC_CHECK_LIB(crypto, BIO_f_base64,
 			[], [AC_MSG_ERROR([could not find $i function in openssl library])])
+CPPFLAGS="$CPPFLAGS_SAVE"
 AC_SUBST([OPENSSL_CFLAGS])
 AC_SUBST([OPENSSL_LDFLAGS])
+
+#============================================================================
+# Detect if gettext is available
+#============================================================================
+
+#AC_ARG_WITH([gettext],
+#    [AS_HELP_STRING([--with-gettext=PATH], [Specifies an alternative location for the openssl library])],
+#    [GETTEXT_DIR="$withval"], [GETTEXT_DIR="/usr/"])
+
+#GETTEXT_CFLAGS="-I$GETTEXT_DIR/include"
+#GETTEXT_LDFLAGS="-L$GETTEXT_DIR/lib -lintl"
+#CFLAGS_SAVE="$CFLAGS"
+#CFLAGS="$GETTEXT_CFLAGS"
+#LIBS_SAVE="$LIBS"
+#LIBS="$GETTEXT_LDFLAGS"
+#AM_GNU_GETTEXT([external], [], [])
+#AC_CHECK_LIB(intl,
+#			[dgettext], [] , [AC_MSG_ERROR([could not find $i function in gettext library])])
+#AC_SUBST([GETTEXT_CFLAGS])
+#AC_SUBST([GETTEXT_LDFLAGS])
 
 #============================================================================
@@ -145,4 +224,57 @@
 AC_SUBST([FCGI_LDFLAGS])
 
+AC_ARG_WITH([metadb],
+        [AS_HELP_STRING([--with-metadb=yes], [Activates the metadata database support])],
+        [WITHMETADB="$withval"], [WITHMETADB=""])
+
+if test "x$WITHMETADB" = "xyes"; then
+   	METADB="-DMETA_DB"
+	METADB_FILE="meta_sql.o sqlapi.o"
+else
+	METADB=""
+	METADB_FILE=""
+fi
+
+AC_SUBST([METADB])
+AC_SUBST([METADB_FILE])
+
+AC_ARG_WITH([hpc],
+        [AS_HELP_STRING([--with-hpc=yes], [Specifies if you need to activate HPC support])],
+        [HPCWITH="$withval"], [HPCWITH="no"])
+
+
+AC_ARG_WITH([ssh2],
+        [AS_HELP_STRING([--with-ssh2=PATH], [Specifies an alternative location for the ssh2 library])],
+        [SSH2PATH="$withval"], [SSH2PATH="/usr"])
+
+if test "x$HPCWITH" = "xyes"; then
+   	HPC_FILES="service_internal_hpc.o sshapi.o"
+	HPC_ENABLED="-DUSE_HPC"
+	HPC_CPPFLAGS=""
+	HPC_LDFLAGS=""
+	# Extract the linker and include flags
+	SSH2_LDFLAGS="-L$SSH2PATH/lib -lssh2"
+	SSH2_CPPFLAGS="-I$SSH2PATH/include"
+	# Check headers file
+	CPPFLAGS_SAVE="$CPPFLAGS"
+	CPPFLAGS="$SSH2_CPPFLAGS"
+	LIBS_SAVE="$LIBS"
+	LIBS="$SSH2_LDFLAGS"
+	
+	AC_CHECK_HEADERS([libssh2.h],
+                 [], [AC_MSG_ERROR([could not find headers related to libssh2])])
+	AC_CHECK_LIB([ssh2], [libssh2_session_init])
+
+	LIBS="$LIBS_SAVE"
+fi
+
+AC_SUBST([HPC_CPPFLAGS])
+AC_SUBST([HPC_LDFLAGS])
+AC_SUBST([HPC_ENABLED])
+AC_SUBST([HPC_FILES])
+
+AC_SUBST([SSH2_CPPFLAGS])
+AC_SUBST([SSH2_LDFLAGS])
+
 # ===========================================================================
 # Detect if libxml2 is installed
@@ -400,4 +532,41 @@
 AC_SUBST([MS_LIBS])
 AC_SUBST([MS_FILE])
+AC_SUBST([MS_VERSION])
+
+# ===========================================================================
+# Detect if R is installed
+# ===========================================================================
+
+AC_ARG_WITH([r], 
+	[AS_HELP_STRING([--with-r=PATH], [To enable python support or Specifies an alternative directory for R installation,  disabled by default])], 
+	[R_PATH="$withval"; R_ENABLED="-DUSE_R"], [R_ENABLED=""])
+
+if test -z "$R_ENABLED"
+then
+	R_FILE=""
+else
+	R_FILE="service_internal_r.o"
+	# Extract the linker and include flags 
+	R_LDFLAGS="-L$R_PATH/lib/ -lR"
+	R_CPPFLAGS="-I$R_PATH/include/"
+
+	# Check headers file
+	CPPFLAGS_SAVE="$CPPFLAGS"
+	CPPFLAGS="$R_CPPFLAGS"
+	AC_CHECK_HEADERS([RInternals.h],
+		 [], [AC_MSG_ERROR([could not find headers include related to R])])
+
+	# Ensure we can link against libphp
+	#LIBS_SAVE="$LIBS"
+	#LIBS="$R_LDFLAGS"
+	#AC_CHECK_LIB([$LIBS], [R_tryEval], [], [AC_MSG_ERROR([could not find libR])], [])
+	#LIBS="$LIBS_SAVE"
+fi
+
+AC_SUBST([R_CPPFLAGS])
+AC_SUBST([R_LDFLAGS])
+AC_SUBST([R_ENABLED])
+AC_SUBST([R_FILE])
+
 
 # ===========================================================================
@@ -646,5 +815,5 @@
 
 	AC_LANG([C++])
-	echo $JAVA_CPPFLAGS
+	#echo $JAVA_CPPFLAGS
 	# Check headers file (second time we check that in fact)
 	CPPFLAGS_SAVE="$CPPFLAGS"
@@ -696,5 +865,5 @@
 
 	AC_LANG([C++])
-	echo $JAVA_CPPFLAGS
+	#echo $JAVA_CPPFLAGS
 	# Check headers file (second time we check that in fact)
 	CPPFLAGS_SAVE="$CFLAGS"
@@ -888,4 +1057,8 @@
         [SAGAPATH="$withval"], [SAGAPATH=""])
 
+AC_ARG_WITH([saga-version],
+        [AS_HELP_STRING([--with-saga-version=VERSION], [Specifies the SAGA-GIS version number])],
+        [SAGAVERS="$withval"], [SAGAVERS="2"])
+
 if test -z "$SAGAPATH"
 then
@@ -903,5 +1076,5 @@
 	WX_ISSUE="-D_WX_WXCRTVARARG_H_"
 	SAGA_DEFS="-D_SAGA_LINUX -D_TYPEDEF_BYTE -D_TYPEDEF_WORD -DMODULE_LIBRARY_PATH=\\\"$SAGAPATH/lib/saga\\\""
-	SAGA_CPPFLAGS=" -fPIC -I$SAGAPATH/include/saga/saga_core/saga_api/ `$WXCFG --unicode=yes --static=no --cxxflags` -D_SAGA_UNICODE $SAGA_DEFS $WX_ISSUE"
+	SAGA_CPPFLAGS="-DSAGA_VERSION=${SAGAVERS} -fPIC -I$SAGAPATH/include/saga/saga_core/saga_api/ `$WXCFG --unicode=yes --static=no --cxxflags` -D_SAGA_UNICODE $SAGA_DEFS $WX_ISSUE"
 	SAGA_LDFLAGS="-fPIC `$WXCFG --unicode=yes --static=no --libs` -lsaga_api"
 	SAGA_ENABLED="-DUSE_SAGA"
@@ -914,8 +1087,16 @@
 	LIBS_SAVE="$LIBS"
 	LIBS="$SAGA_LDFLAGS"
-	AC_CHECK_HEADERS([module_library.h],
-			[], [AC_MSG_ERROR([could not find header file $i related to SAGA-GIS])])
-	AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include "module_library.h"],[SG_Get_Module_Library_Manager();]])],
-		[AC_MSG_RESULT([checking for SG_Get_Module_Library_Manager... yes])],[AC_MSG_ERROR([checking for SG_Get_Module_Library_Manager... failed])])
+        if test "$SAGAVERS" == "2"; then
+        AC_CHECK_HEADERS([module_library.h],
+                        [], [AC_MSG_ERROR([could not find header file $i related to SAGA-GIS])])
+        AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include "module_library.h"],[SG_Get_Module_Library_Manager();]])],
+                [AC_MSG_RESULT([checking for SG_Get_Module_Library_Manager... yes])],[AC_MSG_ERROR([checking for SG_Get_Module_Library_Manager... failed])])
+        else
+        AC_CHECK_HEADERS([tool_library.h],
+                        [], [AC_MSG_ERROR([could not find header file $i related to SAGA-GIS])])
+        AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include "tool_library.h"],[SG_Get_Tool_Library_Manager();]])],
+                [AC_MSG_RESULT([checking for SG_Get_Tool_Library_Manager... yes])],[AC_MSG_ERROR([checking for SG_Get_Tool_Library_Manager... failed])])
+        fi
+	
 	LIBS="$LIBS_SAVE"
 	AC_LANG_POP([C++])
Index: trunk/zoo-project/zoo-kernel/main_conf_read.y
===================================================================
--- trunk/zoo-project/zoo-kernel/main_conf_read.y	(revision 889)
+++ trunk/zoo-project/zoo-kernel/main_conf_read.y	(revision 917)
@@ -87,5 +87,5 @@
  ;
 
-pair: PAIR {curr_key=zStrdup($1);}
+pair: PAIR {if(curr_key!=NULL) free(curr_key);curr_key=zStrdup($1);}
 | EPAIR {
   if(current_content==NULL) 
@@ -99,6 +99,7 @@
   }
   free(curr_key);
+  curr_key=NULL;
   }
-| SPAIR  {curr_key=zStrdup($1);if(debug) printf("SPAIR FOUND !!\n"); }
+| SPAIR  {if(curr_key!=NULL) free(curr_key);curr_key=zStrdup($1);if(debug) printf("SPAIR FOUND !!\n"); }
  ;
 
@@ -162,4 +163,7 @@
     free(current_content);
   }
+  if(curr_key!=NULL){
+    free(curr_key);
+  }
 
   fclose(crin);
Index: trunk/zoo-project/zoo-kernel/makefile.vc
===================================================================
--- trunk/zoo-project/zoo-kernel/makefile.vc	(revision 889)
+++ trunk/zoo-project/zoo-kernel/makefile.vc	(revision 917)
@@ -50,4 +50,7 @@
 	$(CPP) $(CFLAGS) /c caching.c
 
+service_json.obj: service_json.c service_json.h
+	$(CPP) $(CFLAGS) /c service_json.c
+
 request_parser.obj: request_parser.c request_parser.h
 	$(CPP) $(CFLAGS) /c request_parser.c
@@ -71,4 +74,7 @@
 	$(CPP) /c $(CFLAGS) service_internal_ruby.c
 
+service_internal_mono.obj: service_internal_mono.c service_internal_mono.h service.h
+        $(CPP) /c $(MONO_CLAGS) $(CFLAGS) service_internal_mono.c
+
 service_internal_python.obj: service_internal_python.c service.h
 	$(CPP) /c $(CFLAGS) service_internal_python.c
@@ -89,4 +95,7 @@
 	$(CPP) /c $(CFLAGS) $(PHP_CFLAGS) service_internal_php.c
     
+service_callback.obj: service_callback.c service_callback.h service.h
+	$(CPP) /c $(CFLAGS) service_callback.c
+    
 service_internal_php7.obj: service_internal_php7.c service_internal_php.h service.h
 	$(CPP) /c $(CFLAGS) $(PHP_CFLAGS) service_internal_php7.c    
@@ -95,9 +104,9 @@
 	link /dll /out:$(LIBZOO_SERVICE) ./service.obj ./service_internal.obj ./sqlapi.obj $(LDFLAGS) /FORCE:MULTIPLE
 
-$(PROGRAMNAME): version.h $(LIBZOO_SERVICE) zoo_loader.obj zoo_service_loader.obj service_internal.obj $(PY_FILE) $(JAVA_FILE) $(MS_FILE) $(JS_FILE) $(RUBY_FILE) $(PHP_FILE) ulinet.obj lex.cr.obj lex.sr.obj service_conf.tab.obj main_conf_read.tab.obj request_parser.obj response_print.obj server_internal.obj caching.obj
-	link zoo_loader.obj request_parser.obj response_print.obj server_internal.obj caching.obj $(PY_FILE) $(JAVA_FILE) $(MS_FILE) $(JS_FILE) $(RUBY_FILE) $(PHP_FILE) ulinet.obj main_conf_read.tab.obj lex.cr.obj service_conf.tab.obj lex.sr.obj  zoo_service_loader.obj ./libzoo_service.lib /out:$(PROGRAMNAME) $(LDFLAGS) $(LDFLAGSCGI) 
+$(PROGRAMNAME): version.h $(LIBZOO_SERVICE) zoo_loader.obj zoo_service_loader.obj service_internal.obj $(PY_FILE) $(JAVA_FILE) $(MS_FILE) $(JS_FILE) $(MONO_FILE) $(RUBY_FILE) $(PHP_FILE) ulinet.obj lex.cr.obj lex.sr.obj service_conf.tab.obj main_conf_read.tab.obj request_parser.obj response_print.obj server_internal.obj caching.obj service_json.obj service_callback.obj
+	link zoo_loader.obj request_parser.obj response_print.obj server_internal.obj caching.obj service_json.obj service_callback.obj $(PY_FILE) $(JAVA_FILE) $(MS_FILE) $(JS_FILE) $(MONO_FILE) $(RUBY_FILE) $(PHP_FILE) ulinet.obj main_conf_read.tab.obj lex.cr.obj service_conf.tab.obj lex.sr.obj  zoo_service_loader.obj ./libzoo_service.lib /out:$(PROGRAMNAME) $(LDFLAGS) $(LDFLAGSCGI) $(JSONC_LIB) $(PTHREADS_LIB) $(XSLT_LIB)
 
-zcfg2yaml: version.h zcfg2yaml.obj zoo_service_loader.obj service_internal.obj $(PY_FILE) $(JAVA_FILE) $(MS_FILE) $(JS_FILE) $(RUBY_FILE) ulinet.obj lex.cr.obj lex.sr.obj service_conf.tab.obj main_conf_read.tab.obj
-	link zcfg2yaml.obj server_internal.obj $(PY_FILE) $(JAVA_FILE) $(MS_FILE) $(JS_FILE) $(RUBY_FILE) $(PHP_FILE) ulinet.obj response_print.obj main_conf_read.tab.obj lex.cr.obj service_conf.tab.obj lex.sr.obj ./libzoo_service.lib /out:zcfg2yaml.exe $(LDFLAGS) $(LDFLAGSCGI)
+zcfg2yaml: version.h zcfg2yaml.obj zoo_service_loader.obj service_internal.obj caching.obj $(PY_FILE) $(JAVA_FILE) $(MS_FILE) $(JS_FILE) $(MONO_FILE) $(RUBY_FILE) ulinet.obj lex.cr.obj lex.sr.obj service_conf.tab.obj main_conf_read.tab.obj
+	link zcfg2yaml.obj server_internal.obj caching.obj $(PY_FILE) $(JAVA_FILE) $(MS_FILE) $(JS_FILE) $(MONO_FILE) $(RUBY_FILE) $(PHP_FILE) ulinet.obj response_print.obj main_conf_read.tab.obj lex.cr.obj service_conf.tab.obj lex.sr.obj ./libzoo_service.lib /out:zcfg2yaml.exe $(LDFLAGS) $(LDFLAGSCGI)
 
 clean:
@@ -105,3 +114,3 @@
 
 embed-manifest: zoo_loader.cgi
-	mt.exe -manifest zoo_loader.cgi.manifest -outputresource:zoo_loader.cgi;1
+	mt.exe -manifest zoo_loader.cgi.manifest -outputresource:zoo_loader.cgi;
Index: trunk/zoo-project/zoo-kernel/meta_sql.c
===================================================================
--- trunk/zoo-project/zoo-kernel/meta_sql.c	(revision 917)
+++ trunk/zoo-project/zoo-kernel/meta_sql.c	(revision 917)
@@ -0,0 +1,482 @@
+/*
+ * Author : Gérald Fenoy
+ *
+ * Copyright 2017 GeoLabs SARL. All rights reserved.
+ *
+ * This work was supported by public funds received in the framework of GEOSUD,
+ * a project (ANR-10-EQPX-20) of the program "Investissements d'Avenir" managed
+ * by the French National Research Agency
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifdef META_DB
+#include "ogr_api.h"
+#include "ogrsf_frmts.h"
+#include "ogr_p.h"
+#if GDAL_VERSION_MAJOR >= 2
+#include <gdal_priv.h>
+#endif
+
+#include "meta_sql.h"
+#include "sqlapi.h"
+#include "response_print.h"
+#ifdef USE_HPC
+#include "service_internal_hpc.h"
+#endif
+#define META_SERVICES_LIST_ALL \
+  "select id,identifier,title,abstract,service_type,service_provider,conf_id"\
+  " from ows_process"
+#define META_SERVICES_LIST_ALL_LENGTH strlen(META_SERVICES_LIST_ALL)
+
+#define META_SERVICES_KEYWORDS_FROM_PROCESS \
+  "SELECT keyword FROM CollectionDB.ows_Keywords where id in"\
+  " (SELECT keywords_id FROM CollectionDB.DescriptionsKeywordsAssignment"\
+  " where descriptions_id=%s) "
+#define META_SERVICES_KEYWORDS_FROM_PROCESS_LENGTH strlen(META_SERVICES_KEYWORDS_FROM_PROCESS)
+
+#define META_SERVICES_META_FROM_ANYTHING \
+  "SELECT title,role,href FROM CollectionDB.ows_Metadata where id in"\
+  " (SELECT metadata_id FROM CollectionDB.DescriptionsMetadataAssignment"\
+  " where descriptions_id=%s) "
+#define META_SERVICES_META_FROM_ANYTHING_LENGTH strlen(META_SERVICES_META_FROM_ANYTHING)
+
+#define META_SERVICES_AP_FROM_ANYTHING \
+  "SELECT id,title,role,href FROM CollectionDB.ows_AdditionalParameters where id in"\
+  " (SELECT additional_parameters_id FROM CollectionDB.DescriptionsAdditionalParametersAssignment"\
+  " where descriptions_id=%s) "
+#define META_SERVICES_AP_FROM_ANYTHING_LENGTH strlen(META_SERVICES_AP_FROM_ANYTHING)
+
+#define META_SERVICES_AP_FROM_AP \
+  "SELECT key,value FROM CollectionDB.ows_AdditionalParameter where additional_parameters_id =$q$%s$q$"
+#define META_SERVICES_AP_FROM_AP_LENGTH strlen(META_SERVICES_AP_FROM_AP)
+
+#define META_SERVICES_LIST_INPUTS_FROM_PROCESS				\
+  "select id, identifier,title,abstract,min_occurs,max_occurs from CollectionDB.ows_Input where id in (SELECT input_id from CollectionDB.ProcessInputAssignment where process_id=%s) order by id"
+#define META_SERVICES_LIST_INPUTS_FROM_PROCESS_LENGTH strlen(META_SERVICES_LIST_INPUTS_FROM_PROCESS)
+
+#define META_SERVICES_LIST_INPUTS_FROM_INPUT				\
+  "select id, identifier,title,abstract,min_occurs,max_occurs from CollectionDB.ows_Input where id in (SELECT child_input from CollectionDB.InputInputAssignment where parent_input=%s) order by id"
+#define META_SERVICES_LIST_INPUTS_FROM_INPUT_LENGTH strlen(META_SERVICES_LIST_INPUTS_FROM_INPUT)
+
+#define META_SERVICES_LIST_OUTPUTS_FROM_PROCESS \
+  "select id, identifier,title,abstract from CollectionDB.ows_Output where id in (SELECT output_id from CollectionDB.ProcessOutputAssignment where process_id=%s) order by id"
+#define META_SERVICES_LIST_OUTPUTS_FROM_PROCESS_LENGTH strlen(META_SERVICES_LIST_OUTPUTS_FROM_PROCESS)
+
+#define META_SERVICES_LIST_OUTPUTS_FROM_OUTPUT \
+  "select id, identifier,title,abstract from CollectionDB.ows_Output where id in (SELECT child_output from CollectionDB.OutputOutputAssignment where parent_output=%s) order by id"
+#define META_SERVICES_LIST_OUTPUTS_FROM_OUTPUT_LENGTH strlen(META_SERVICES_LIST_OUTPUTS_FROM_OUTPUT)
+
+#define META_SERVICES_LIST_LITERAL_FROM_IO \
+  "select (SELECT name as type FROM CollectionDB.PrimitiveDatatypes where CollectionDB.PrimitiveDatatypes.id=data_type_id),default_value,(SELECT uom from CollectionDB.PrimitiveUOM where id=CollectionDB.LiteralDataDomain.uom),translate(translate(ARRAY((SELECT allowed_Value from CollectionDB.AllowedValues where id in (SELECT allowed_value_id from CollectionDB.AllowedValuesAssignment where literal_data_domain_id=CollectionDB.LiteralDataDomain.id)))::varchar,'{',''),'}',''),def as allowedvalues from CollectionDB.LiteralDataDomain where id in (SELECT data_description_id from CollectionDB.%sDataDescriptionAssignment where %s_id = %s);"
+#define META_SERVICES_LIST_LITERAL_FROM_IO_LENGTH strlen(META_SERVICES_LIST_LITERAL_FROM_IO)
+
+#define META_SERVICES_LIST_FORMATS_FROM_IO \
+  "select mime_type,encoding,schema,maximum_megabytes,CASE WHEN use_mapserver THEN 'true' ELSE 'false' END, ms_styles, def from CollectionDB.ows_Format,CollectionDB.PrimitiveFormats where CollectionDB.ows_Format.primitive_format_id=CollectionDB.PrimitiveFormats.id and CollectionDB.ows_Format.id in (SELECT format_id from collectiondb.ows_datadescription where id in ( SELECT data_description_id from CollectionDB.%sDataDescriptionAssignment where %s_id = %s))"
+#define META_SERVICES_LIST_FORMATS_FROM_IO_LENGTH strlen(META_SERVICES_LIST_FORMATS_FROM_IO)
+
+/**
+ * Create a new iotype pointer using field names from an OGRFeature
+ *
+ * @param f the OGRFeature 
+ * @param fields the fields names
+ * @return the iotype
+ */
+iotype* getIoType(OGRFeature* f,const char** fields){
+  iotype* io=(iotype*)malloc(IOTYPE_SIZE);
+  io->content=NULL;
+  io->next=NULL;
+  for(int i=0;i<6;i++){
+    if(fields[i]==NULL)
+      return io;
+    const char* tmpS=f->GetFieldAsString( i );
+    if(strlen(tmpS)>0){
+      if(io->content==NULL)
+	io->content=createMap(fields[i],tmpS);
+      else
+	addToMap(io->content,fields[i],tmpS);
+    }
+  }
+  return io;
+}
+
+/**
+ * Fill the AdditionalParameters map with the data extracted from metadb
+ *
+ * @param conf the main configuration maps
+ * @param ap the map to fill
+ * @param dref the description identifier
+ * @return the number of metadata field found
+ */
+int fillAdditionalParameters(maps* conf,map** ap,const char* dref){
+  int res=0;
+  char* ioQuery=(char*)malloc((META_SERVICES_AP_FROM_ANYTHING_LENGTH+strlen(dref)+1)*sizeof(char));
+  sprintf(ioQuery,META_SERVICES_AP_FROM_ANYTHING,dref);
+  OGRFeature  *meta = NULL;
+  OGRLayer *metas=fetchSql(conf,0,ioQuery);
+  free(ioQuery);
+  int cnt=0;
+  char fields[3][255]={
+    "title",
+    "role",
+    "href"
+  };
+  while( (meta = metas->GetNextFeature()) != NULL ){
+    int i=0;
+    for(i=0;i<3;i++){      
+      const char *tmp=meta->GetFieldAsString(i+1);
+      if(strlen(tmp)>0)
+	if(*ap==NULL){
+	  (*ap)=createMap(fields[i],tmp);
+	  addToMap(*ap,"fromDb","true");
+	}
+	else
+	  setMapArray(*ap,fields[i],res,tmp);
+    }
+    char* apQuery=(char*)malloc((META_SERVICES_AP_FROM_AP_LENGTH+strlen(dref)+1)*sizeof(char));
+    sprintf(apQuery,META_SERVICES_AP_FROM_AP,meta->GetFieldAsString(0));
+    OGRFeature  *adp = NULL;
+    OGRLayer *adps=fetchSql(conf,0,apQuery);
+    free(apQuery);
+    while( (adp = adps->GetNextFeature()) != NULL ){
+      addToMap(*ap,adp->GetFieldAsString(0),adp->GetFieldAsString(1));
+      OGRFeature::DestroyFeature( adp );
+    }
+    cleanFetchSql(conf,0,adps);
+    res++;
+    OGRFeature::DestroyFeature( meta );
+  }
+  cleanFetchSql(conf,0,metas);
+  return res;
+}
+
+/**
+ * Fill the metadata map with the data extracted from metadb
+ *
+ * @param conf the main configuration maps
+ * @param metadata the map to fill
+ * @param dref the description identifier
+ * @return the number of metadata field found
+ */
+int fillMetadata(maps* conf,map** metadata,const char* dref){
+  int res=0;
+  char* ioQuery=(char*)malloc((META_SERVICES_META_FROM_ANYTHING_LENGTH+strlen(dref)+1)*sizeof(char));
+  sprintf(ioQuery,META_SERVICES_META_FROM_ANYTHING,dref);
+  OGRFeature  *meta = NULL;
+  OGRLayer *metas=fetchSql(conf,0,ioQuery);
+  free(ioQuery);
+  int cnt=0;
+  char fields[3][255]={
+    "title",
+    "role",
+    "href"
+  };
+  while( (meta = metas->GetNextFeature()) != NULL ){
+    int i=0;
+    for(i=0;i<3;i++){
+      const char *tmp=meta->GetFieldAsString(i);
+      if(strlen(tmp)>0)
+	if(*metadata==NULL)
+	  *metadata=createMap(fields[i],tmp);
+	else
+	  addToMap(*metadata,fields[i],tmp);
+    }
+    res++;
+    OGRFeature::DestroyFeature( meta );
+  }
+  cleanFetchSql(conf,0,metas);
+  return res;
+}
+
+/**
+ * Try to fill the default/supported map for the LiteralData with the data
+ * extracted from metadb.
+ *
+ * @param conf the main configuration maps
+ * @param in the element to fill default/supported
+ * @param input the OGRFeature corresponding to the input/output
+ * @param ltype the element type ("Input" or "Output")
+ * @return the number of default/supported definition found
+ */
+int fillLiteralData(maps* conf,elements* in,OGRFeature  *input,const char* ltype){
+  int res=0;
+  char* ioQuery=(char*)malloc((META_SERVICES_LIST_LITERAL_FROM_IO_LENGTH+(strlen(ltype)*2)+strlen(input->GetFieldAsString( 0 ))+1)*sizeof(char));
+  sprintf(ioQuery,META_SERVICES_LIST_LITERAL_FROM_IO,ltype,ltype,input->GetFieldAsString( 0 ));
+  OGRFeature  *io = NULL;
+  OGRLayer *ios=fetchSql(conf,0,ioQuery);
+  free(ioQuery);
+  int ioCnt=0;
+  const char* fields[5]={"dataType","value","uom","AllowedValues",NULL};
+  while( (io = ios->GetNextFeature()) != NULL ){
+    iotype* currentIoType;
+    if(strncmp(io->GetFieldAsString( 4 ),"1",1)==0){
+      in->defaults=getIoType(io,fields);
+    }else{
+      if(in->supported==NULL)
+	in->supported=getIoType(io,fields);
+      else{
+	iotype* p=in->supported;
+	while(p->next!=NULL){
+	  p=p->next;
+	}
+	p->next=getIoType(io,fields);
+      }
+    }
+    in->format=strdup("LiteralData");
+    res++;
+    OGRFeature::DestroyFeature( io );
+  }
+  cleanFetchSql(conf,0,ios);
+  return res;
+}
+
+/**
+ * Try to fill the default/supported map for the ComplexData with the data
+ * extracted from metadb.
+ *
+ * @param conf the main configuration maps
+ * @param in the element to fill default/supported
+ * @param input the OGRFeature corresponding to the input/output
+ * @param ltype the element type ("Input" or "Output")
+ * @return the number of default/supported definition found
+ */
+int fillComplexData(maps* conf,elements* in,OGRFeature  *input,const char* ltype){
+  int res=0;
+  char* ioQuery=(char*)malloc((META_SERVICES_LIST_FORMATS_FROM_IO_LENGTH+(strlen(ltype)*2)+strlen(input->GetFieldAsString( 0 ))+1)*sizeof(char));
+  sprintf(ioQuery,META_SERVICES_LIST_FORMATS_FROM_IO,ltype,ltype,input->GetFieldAsString( 0 ));
+  OGRFeature  *io = NULL;
+  OGRLayer *ios=fetchSql(conf,0,ioQuery);
+  free(ioQuery);
+  int ioCnt=0;
+  const char* fields[6]={"mimeType","ecoding","schema","maximumMegabytes","useMapserver","msStyle"};
+  while( (io = ios->GetNextFeature()) != NULL ){
+    iotype* currentIoType;
+    if(strncmp(io->GetFieldAsString( 6 ),"1",1)==0){
+      in->defaults=getIoType(io,fields);
+    }else{
+      if(in->supported==NULL)
+	in->supported=getIoType(io,fields);
+      else{
+	iotype* p=in->supported;
+	while(p->next!=NULL){
+	  p=p->next;
+	}
+	p->next=getIoType(io,fields);
+      }
+    }
+    in->format=strdup("ComplexData");
+    res++;
+    OGRFeature::DestroyFeature( io );
+  }
+  cleanFetchSql(conf,0,ios);
+  return res;
+}
+
+/**
+ * Extract input definition from metadb
+ *
+ * @param conf the main configuration maps
+ * @param input the OGRFeature pointing to an input
+ * @return a new elements* corresponding to the current input
+ */
+elements* extractInput(maps* conf,OGRFeature *input){
+  elements* res=createElements(input->GetFieldAsString( 1 ));
+  res->content=createMap("title",input->GetFieldAsString( 2 ));
+  addToMap(res->content,"abstract",input->GetFieldAsString( 3 ));
+  addToMap(res->content,"minOccurs",input->GetFieldAsString( 4 ));
+  addToMap(res->content,"maxOccurs",input->GetFieldAsString( 5 ));
+  // Extract metadata
+  fillMetadata(conf,&res->metadata,input->GetFieldAsString( 0 ));
+  res->additional_parameters=NULL;
+  fillAdditionalParameters(conf,&res->additional_parameters,input->GetFieldAsString( 0 ));
+  res->defaults=NULL;
+  res->supported=NULL;
+  res->child=NULL;
+  res->next=NULL;
+  // Extract iotypes
+  int ioCnt=fillLiteralData(conf,res,input,"Input");
+  if(ioCnt==0){
+    ioCnt=fillComplexData(conf,res,input,"Input");
+  }
+  if(ioCnt==0){
+    char* nestedInputsQuery=(char*)malloc((META_SERVICES_LIST_INPUTS_FROM_INPUT_LENGTH+strlen(input->GetFieldAsString( 0 ))+1)*sizeof(char));
+    sprintf(nestedInputsQuery,META_SERVICES_LIST_INPUTS_FROM_INPUT,input->GetFieldAsString( 0 ));
+    OGRFeature  *ninput = NULL;
+    OGRLayer *ninputs=fetchSql(conf,0,nestedInputsQuery);
+    free(nestedInputsQuery);
+    while( (ninput = ninputs->GetNextFeature()) != NULL ){
+      elements* nin=extractInput(conf,ninput);
+      addToElements(&res->child,nin);
+      freeElements(&nin);
+      free(nin);
+      OGRFeature::DestroyFeature( ninput );
+    }
+    cleanFetchSql(conf,0,ninputs);
+  }
+  return res;
+}
+
+/**
+ * Extract output definition from metadb
+ *
+ * @param conf the main configuration maps
+ * @param output the OGRFeature pointing to an output
+ * @return a new elements* corresponding to the current output
+ */
+elements* extractOutput(maps* conf,OGRFeature *output){
+  elements* res=createElements(output->GetFieldAsString( 1 ));
+  res->content=createMap("title",output->GetFieldAsString( 2 ));
+  addToMap(res->content,"abstract",output->GetFieldAsString( 3 ));
+  fillMetadata(conf,&res->metadata,output->GetFieldAsString( 0 ));
+  fillAdditionalParameters(conf,&res->additional_parameters,output->GetFieldAsString( 0 ));
+  int ioCnt=fillLiteralData(conf,res,output,"Output");
+  if(ioCnt==0)
+    ioCnt=fillComplexData(conf,res,output,"Output");
+  char* nestedOutputsQuery=(char*)malloc((META_SERVICES_LIST_OUTPUTS_FROM_OUTPUT_LENGTH+strlen(output->GetFieldAsString( 0 ))+1)*sizeof(char));
+  sprintf(nestedOutputsQuery,META_SERVICES_LIST_OUTPUTS_FROM_OUTPUT,output->GetFieldAsString( 0 ));
+  OGRFeature  *noutput = NULL;
+  OGRLayer *noutputs=fetchSql(conf,0,nestedOutputsQuery);
+  free(nestedOutputsQuery);
+  while( (noutput = noutputs->GetNextFeature()) != NULL ){
+    elements* nout=extractOutput(conf,noutput);
+    addToElements(&res->child,nout);
+    freeElements(&nout);
+    free(nout);
+    OGRFeature::DestroyFeature( noutput );
+  }
+  cleanFetchSql(conf,0,noutputs);
+  return res;
+}
+
+/**
+ * Extract service from metadb
+ *
+ * @param conf the main configuration maps
+ * @param serviceName the service name
+ * @param minimal 1 for minimal metadata extraction (GetCapabilities), 0 in other cases.
+ * @return a new service* corresponding to the service
+ */
+service* extractServiceFromDb(maps* conf,const char* serviceName,int minimal){
+  OGRFeature  *poFeature = NULL;
+  char* tmpQuery=(char*)malloc((META_SERVICES_LIST_ALL_LENGTH+strlen(serviceName)+21)*sizeof(char));
+  sprintf(tmpQuery,"%s WHERE identifier='%s'",META_SERVICES_LIST_ALL,serviceName);  
+  OGRLayer *res=fetchSql(conf,0,tmpQuery);
+  free(tmpQuery);
+  if(res!=NULL){
+    while( (poFeature = res->GetNextFeature()) != NULL ){
+      service* s = (service*) malloc(SERVICE_SIZE);
+      s->name = strdup(poFeature->GetFieldAsString( 1 ));
+      s->content = createMap("title",poFeature->GetFieldAsString( 2 ));
+      addToMap(s->content,"abstract",poFeature->GetFieldAsString( 3 ));
+      addToMap(s->content,"serviceType",poFeature->GetFieldAsString( 4 ));
+      addToMap(s->content,"serviceProvider",poFeature->GetFieldAsString( 5 ));
+      addToMap(s->content,"confId",poFeature->GetFieldAsString( 6 ));
+      addToMap(s->content,"fromDb","true");
+      s->metadata=NULL;
+      fillMetadata(conf,&s->metadata,poFeature->GetFieldAsString( 0 ));
+      s->additional_parameters=NULL;
+      fillAdditionalParameters(conf,&s->additional_parameters,poFeature->GetFieldAsString( 0 ));
+      s->inputs=NULL;
+      s->outputs=NULL;
+      if(minimal==1){
+	OGRFeature::DestroyFeature( poFeature );
+	cleanFetchSql(conf,0,res);
+	return s;
+      }
+      char* inputsQuery=(char*)malloc((META_SERVICES_LIST_INPUTS_FROM_PROCESS_LENGTH+strlen(poFeature->GetFieldAsString( 0 ))+1)*sizeof(char));
+      sprintf(inputsQuery,META_SERVICES_LIST_INPUTS_FROM_PROCESS,poFeature->GetFieldAsString( 0 ));
+      OGRFeature  *input = NULL;
+      OGRLayer *inputs=fetchSql(conf,0,inputsQuery);
+      free(inputsQuery);
+      while( (input = inputs->GetNextFeature()) != NULL ){
+	elements* in=extractInput(conf,input);
+	if(in!=NULL){
+	  addToElements(&s->inputs,in);
+	  freeElements(&in);
+	  free(in);
+	}
+	OGRFeature::DestroyFeature( input );
+      }
+      cleanFetchSql(conf,0,inputs);
+      char* outputsQuery=(char*)malloc((META_SERVICES_LIST_OUTPUTS_FROM_PROCESS_LENGTH+strlen(poFeature->GetFieldAsString( 0 ))+1)*sizeof(char));
+      sprintf(outputsQuery,META_SERVICES_LIST_OUTPUTS_FROM_PROCESS,poFeature->GetFieldAsString( 0 ));
+      OGRFeature  *output = NULL;
+      OGRLayer *outputs=fetchSql(conf,0,outputsQuery);
+      free(outputsQuery);
+      s->outputs=NULL;
+      while( (output = outputs->GetNextFeature()) != NULL ){
+	elements* in=extractOutput(conf,output);
+	if(in!=NULL){
+	  addToElements(&s->outputs,in);
+	  freeElements(&in);
+	  free(in);
+	}
+	OGRFeature::DestroyFeature( output );
+      }
+      cleanFetchSql(conf,0,outputs);
+      OGRFeature::DestroyFeature( poFeature );
+      cleanFetchSql(conf,0,res);
+      return s;
+    }
+  }
+  cleanFetchSql(conf,0,res);
+  return NULL;
+}
+
+/**
+ * Extract every service definitions from metadb
+ *
+ * @param reg the registry
+ * @param conf the main configuration maps
+ * @param n the node where to add the services found
+ * @param func the C function to call for each service found
+ * @param minimal 1 for minimal metadata extraction (GetCapabilities), 0 in other cases.
+ * @return the number of services found, -1 in case of failure
+ */
+int fetchServicesFromDb(registry* reg,maps* conf, xmlDocPtr doc, xmlNodePtr n,
+			void (func) (registry *, maps *, xmlDocPtr, xmlNodePtr,
+				     service *), int minimal ){
+  int result=0;
+  result=_init_sql(conf,"metadb");
+  if(getMapFromMaps(conf,"lenv","dbIssue")!=NULL || result < 0)
+    return -1;
+  // Fetch every services
+  OGRLayer *res=fetchSql(conf,0,META_SERVICES_LIST_ALL);
+  if(res!=NULL){
+    OGRFeature  *poFeature = NULL;
+    const char *tmp1;
+    poFeature = res->GetNextFeature();
+    while( poFeature != NULL ){
+      service* s=extractServiceFromDb(conf,poFeature->GetFieldAsString( 1 ),minimal);
+#ifdef USE_HPC
+      addNestedOutputs(&s);
+#endif
+      func(reg,conf,doc,n,s);
+      freeService(&s);
+      free(s);
+      OGRFeature::DestroyFeature( poFeature );
+      poFeature = res->GetNextFeature();
+      result++;
+    }
+    cleanFetchSql(conf,0,res);
+  }
+  return result;
+}
+
+#endif
Index: trunk/zoo-project/zoo-kernel/meta_sql.h
===================================================================
--- trunk/zoo-project/zoo-kernel/meta_sql.h	(revision 917)
+++ trunk/zoo-project/zoo-kernel/meta_sql.h	(revision 917)
@@ -0,0 +1,53 @@
+/*
+ * Author : Gérald Fenoy
+ *
+ *  Copyright 2017 GeoLabs SARL. All rights reserved.
+ *
+ * This work was supported by public funds received in the framework of GEOSUD,
+ * a project (ANR-10-EQPX-20) of the program "Investissements d'Avenir" managed
+ * by the French National Research Agency
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef ZOO_META_SQL_H
+#define ZOO_META_SQL_H 1
+#ifdef META_DB
+
+#include "service.h"
+#include "service_internal.h"
+
+#include <libxml/parser.h>
+#include <libxml/xpath.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+  ZOO_DLL_EXPORT int fetchServicesFromDb(registry*,maps*, xmlDocPtr, xmlNodePtr,
+					 void (func) (registry *, maps *, xmlDocPtr,
+						      xmlNodePtr,service *),int);
+  ZOO_DLL_EXPORT service* extractServiceFromDb(maps*,const char*,int);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+#endif
Index: trunk/zoo-project/zoo-kernel/mimetypes.h
===================================================================
--- trunk/zoo-project/zoo-kernel/mimetypes.h	(revision 889)
+++ trunk/zoo-project/zoo-kernel/mimetypes.h	(revision 917)
@@ -180,5 +180,5 @@
 	{ "application/vnd.dece.unspecified", "uvx" },
 	{ "application/vnd.dece.zip", "uvz" },
-	{ "application/vnd.denovo.fcselayout-link", "fe_launch" },
+	{ "application/vnd.denovo.fcselayout-link", "fe_launch" },	
 	{ "application/vnd.dna", "dna" },
 	{ "application/vnd.dolby.mlp", "mlp" },
@@ -818,20 +818,48 @@
 */
 static map* getFileExtensionMap(const char* mimeType, bool* hasExt) {
+  map* ext = createMap("extension", "txt");
+  *hasExt = false;
+	
+  if (mimeType != NULL) { 	
+    for (int i = 0; i < NUM_MIME_TYPES; i++) {			
+      if(strncmp(mimeType, MIME[i][M_Type], strlen(MIME[i][M_Type])) == 0) {
+	free(ext->value);
+	ext->value = zStrdup(MIME[i][M_Extension]);
+	*hasExt = true;
+	break;				
+      }	
+    }
+    if (*hasExt == false && strncmp(mimeType, "image/", 6) == 0) {
+      free(ext->value);
+      ext->value = zStrdup(strstr(mimeType, "/") + 1);
+    }
+  }	
+  return ext;
+}
 
-	map* ext = createMap("extension", "txt");
-	*hasExt = false;
-	
-	if (mimeType != NULL) { 	
-		for (int i = 0; i < NUM_MIME_TYPES; i++) {			
-			if 	(strncmp(mimeType, MIME[i][M_Type], strlen(MIME[i][M_Type])) == 0) {
-				ext->value = zStrdup(MIME[i][M_Extension]);
-				*hasExt = true;
-				break;				
-			}		
-		}
-		if (*hasExt == false && strncmp(mimeType, "image/", 6) == 0) {
-			ext->value = zStrdup(strstr(mimeType, "/") + 1);
-		}			
-	}	
-	return ext;
+static int isGeographic(const char* mimeType){
+  char* imageMimeType[4]={
+    "image/tiff",
+    "image/png",
+    "image/jpeg",
+    "application/vnd.google-earth.kmz"
+  };
+  char* vectorMimeType[5]={
+    "text/xml",
+    "application/json",
+    "application/gml+xml",
+    "application/zip",
+    "application/vnd.google-earth.kml+xml"
+  };
+  int i=0;
+  for(;i<4;i++){
+    if(strncmp(imageMimeType[i],mimeType,strlen(imageMimeType[i]))==0)
+      return 1;
+  }
+  i=0;
+  for(;i<5;i++){
+    if(strncmp(vectorMimeType[i],mimeType,strlen(vectorMimeType[i]))==0)
+      return 2;
+  }
+  return -1;
 }
Index: trunk/zoo-project/zoo-kernel/nmake.opt
===================================================================
--- trunk/zoo-project/zoo-kernel/nmake.opt	(revision 889)
+++ trunk/zoo-project/zoo-kernel/nmake.opt	(revision 917)
@@ -87,4 +87,10 @@
 !ENDIF
 
+!IFDEF MONO_DIR
+MONO_CFLAGS=-DUSE_MONO -I"$(MONO_DIR)"\msvc -I"$(MONO_DIR)"\msvc\include -I"$(MONO_DIR)"
+MONO_LDFLAGS=/LIBPATH:"$(MONO_DIR)/msvc/build/sgen/x64/lib/Release" mono-2.0-sgen.lib
+MONO_FILE=service_internal_mono.obj
+!ENDIF
+
 !IFNDEF ZOOK_DIR
 ZOOK_DIR=.
@@ -100,6 +106,10 @@
 !ENDIF
 
-CFLAGS= $(DB_FLAGS) $(MS_DEFS) $(INCLUDES) $(CFLAGS1) /nologo /MD /W3 /EHsc /Ox /D_CRT_SECURE_NO_WARNINGS /DWIN32 /DPROGRAMNAME=\"$(PROGRAMNAME)\" $(CJFLAGS) -I$(ZOOK_DIR) $(RUBY_CFLAGS) -I./ $(JAVA_CFLAGS) $(MS_CFLAGS) -I$(TROOT)\..\..\thirds\dirent-win32 -I$(INTL_DIR) -I$(CURL_DIR)\include -I$(XML2_DIR)\include -I$(GDAL_DIR)\port $(JS_CFLAGS) -I$(GDAL_DIR)\ogr -I$(GDAL_DIR)\gcore -I$(GD_DIR) -I$(ICONV_DIR) -I$(TROOT)\..\..\thirds\include -I$(TROOT)\..\..\thirds\cgic206 -I$(PYTHON_CPATH)\include -I$(SSL_DIR)/inc32 -I$(FCGI_DIR)\include $(PY_CFLAGS) $(PHP_CFLAGS) -DLINUX_FREE_ISSUE #-DDEBUG #-DDEBUG_SERVICE_CONF
+!IFDEF WIN32_DEBUG
+WIN32_DBG=-DWIN32_DEBUG
+!ENDIF
+
+CFLAGS=$(MONO_CFLAGS) $(WIN32_DBG) $(DB_FLAGS) $(MS_DEFS) $(INCLUDES) $(CFLAGS1) /nologo /MD /W3 /EHsc /Ox /D_CRT_SECURE_NO_WARNINGS /DWIN32 /DPROGRAMNAME=\"$(PROGRAMNAME)\" $(CJFLAGS) -I$(ZOOK_DIR) $(RUBY_CFLAGS) -I./ $(JAVA_CFLAGS) $(MS_CFLAGS) -I$(TROOT)\..\..\thirds\dirent-win32 -I$(INTL_DIR) -I$(CURL_DIR)\include -I$(XML2_DIR)\include -I$(GDAL_DIR)\port $(JS_CFLAGS) -I$(GDAL_DIR)\ogr -I$(GDAL_DIR)\gcore -I$(GD_DIR) -I$(ICONV_DIR) -I$(TROOT)\..\..\thirds\include -I$(TROOT)\..\..\thirds\cgic206 -I$(PYTHON_CPATH)\include -I$(SSL_DIR)/inc32 -I$(FCGI_DIR)\include $(PY_CFLAGS) $(PHP_CFLAGS) -DLINUX_FREE_ISSUE #-DDEBUG #-DDEBUG_SERVICE_CONF
 
 LDFLAGSCGI=$(TROOT)/../../thirds/cgic206/libcgic.lib 
-LDFLAGS=$(FCGI_DIR)/libfcgi/Release/libfcgi.lib $(CURL_LIBRARY) $(PY_LDFLAGS) $(XML2_LIBRARY) $(SSL_DIR)/out32dll/libeay32.lib $(JAVA_LDFLAGS) $(SSL_DIR)/out32dll/ssleay32.lib $(MS_LDFLAGS) $(INTL_DIR)/intl.lib $(XML2_DIR)/win32/bin.msvc/libxml2.lib $(GDAL_DIR)/gdal_i.lib $(CURL_DIR)/lib/libcurl.lib $(JS_LDFLAGS) $(RUBY_LDFLAGS) $(PHP_LDFLAGS) /machine:i386
+LDFLAGS=$(MONO_LDFLAGS) $(FCGI_DIR)/libfcgi/Release/libfcgi.lib $(CURL_LIBRARY) $(PY_LDFLAGS) $(XML2_LIBRARY) $(SSL_DIR)/out32dll/libeay32.lib $(JAVA_LDFLAGS) $(SSL_DIR)/out32dll/ssleay32.lib $(MS_LDFLAGS) $(INTL_DIR)/intl.lib $(XML2_DIR)/win32/bin.msvc/libxml2.lib $(GDAL_DIR)/gdal_i.lib $(CURL_DIR)/lib/libcurl.lib $(JS_LDFLAGS) $(RUBY_LDFLAGS) $(PHP_LDFLAGS) /machine:i386
Index: trunk/zoo-project/zoo-kernel/request_parser.c
===================================================================
--- trunk/zoo-project/zoo-kernel/request_parser.c	(revision 889)
+++ trunk/zoo-project/zoo-kernel/request_parser.c	(revision 917)
@@ -28,4 +28,5 @@
 #include "response_print.h"
 #include "caching.h"
+#include "cgic.h"
 
 /**
@@ -154,5 +155,5 @@
       addToMap(cursor->content,"base64_value",tmp->value);
       int size=0;
-      char *s=strdup(tmp->value);
+      char *s=zStrdup(tmp->value);
       free(tmp->value);
       tmp->value=base64d(s,strlen(s),&size);
@@ -174,5 +175,5 @@
 	  addToMap(cursor->content,key,tmp->value);
 	  int size=0;
-	  char *s=strdup(tmp->value);
+	  char *s=zStrdup(tmp->value);
 	  free(tmp->value);
 	  tmp->value=base64d(s,strlen(s),&size);
@@ -521,4 +522,5 @@
   int l = 0;
   map* version=getMapFromMaps(*main_conf,"main","rversion");
+  map* memory=getMapFromMaps(*main_conf,"main","memory");
   int vid=getVersionId(version->value);
   for (k=0; k < nodes->nodeNr; k++)
@@ -533,4 +535,5 @@
 	    xmlChar *val = xmlGetProp (cur, BAD_CAST "id");
 	    tmpmaps = createMaps((char *) val);
+	    xmlFree(val);
 	  }
 
@@ -624,10 +627,8 @@
 			    tmpmaps->content =
 			      createMap (refs[l], (char *) val);
-
 			  map *ltmp = getMap (tmpmaps->content, "method");
 			  if (l == 4 )
 			    {
-			      if ((ltmp==NULL || strncasecmp (ltmp->value, "POST",4) != 0)) // 
-			      //if ((ltmp==NULL || strncmp (ltmp->value, "POST",4) != 0))
+			      if ((ltmp==NULL || strncmp (ltmp->value, "POST",4) != 0))
 				{
 				  if (loadRemoteFile
@@ -751,4 +752,5 @@
 				      map *btmp =
 					getMap (tmpmaps->content, "Reference");
+				      addToMap (tmpmaps->content, "Body", tmp);
 				      if (btmp != NULL)
 					{
@@ -759,5 +761,6 @@
 							   xmlStrlen(btmps),
 							   INTERNET_FLAG_NO_CACHE_WRITE,
-							   0);
+							   0,
+							   *main_conf);
 					  addIntToMap (tmpmaps->content, "Order", hInternet->nb);
 					}
@@ -778,4 +781,6 @@
 				  xmlGetProp (cur3, BAD_CAST "href");
 				HINTERNET bInternet, res1, res;
+				maps *tmpConf=createMaps("main");
+				tmpConf->content=createMap("memory","load");
 				bInternet = InternetOpen (
 #ifndef WIN32
@@ -785,9 +790,11 @@
 							  INTERNET_OPEN_TYPE_PRECONFIG,
 							  NULL, NULL, 0);
+#ifndef WIN32
 				if (!CHECK_INET_HANDLE (bInternet))
 				  fprintf (stderr,
 					   "WARNING : bInternet handle failed to initialize");
+#endif
 				bInternet.waitingRequests[0] =
-				  strdup ((char *) val);
+				  zStrdup ((char *) val);
 				res1 =
 				  InternetOpenUrl (&bInternet,
@@ -795,6 +802,9 @@
 						   [0], NULL, 0,
 						   INTERNET_FLAG_NO_CACHE_WRITE,
-						   0);
+						   0,
+						   tmpConf);
 				processDownloads (&bInternet);
+				freeMaps(&tmpConf);
+				free(tmpConf);
 				char *tmp =
 				  (char *)
@@ -816,5 +826,6 @@
 						  &bRead);
 				tmp[bInternet.ihandle[0].nDataLen] = 0;
-				InternetCloseHandle (&bInternet);
+				InternetCloseHandle(&bInternet);
+				addToMap (tmpmaps->content, "Body", tmp);
 				map *btmp =
 				  getMap (tmpmaps->content, "href");
@@ -829,8 +840,10 @@
 						       strlen(tmp),
 						       INTERNET_FLAG_NO_CACHE_WRITE,
-						       0);
+						       0,
+						       *main_conf);
 				    addIntToMap (tmpmaps->content, "Order", hInternet->nb);
 				  }
 				free (tmp);
+				xmlFree (val);
 			      }
 			}
@@ -895,5 +908,4 @@
 		    }
 		  }
-
 
 		  while (cur4 != NULL)
@@ -967,7 +979,6 @@
 
 		      map *test = getMap (tmpmaps->content, "encoding");
-
 		      if (test == NULL)
-			{ 
+			{
 			  if (tmpmaps->content != NULL)
 			    addToMap (tmpmaps->content, "encoding",
@@ -979,13 +990,15 @@
 			}
 
-		      if (getMap(tmpmaps->content,"dataType")==NULL && strcasecmp (test->value, "base64") != 0)
-			{ 
-			  xmlChar *mv = xmlNodeListGetString (doc,
-							      cur4->xmlChildrenNode,
-							      1);
+		      if (getMap(tmpmaps->content,"dataType")==NULL && test!=NULL && strcasecmp (test->value, "base64") != 0)
+			{
+			  xmlChar *mv = NULL;
+			  /*if(cur4!=NULL && cur4->xmlChildrenNode!=NULL)
+			    xmlChar *mv = xmlNodeListGetString (doc,
+								cur4->xmlChildrenNode,
+								1);*/
 			  map *ltmp =
 			    getMap (tmpmaps->content, "mimeType");
-			  if (mv == NULL
-			      ||
+			  if (/*mv == NULL
+			      ||*/
 			      (xmlStrcasecmp
 			       (cur4->name, BAD_CAST "ComplexData") == 0
@@ -1025,4 +1038,5 @@
 					   buffersize);
 			    }else{
+
 			    if(xmlStrcasecmp
 			       (cur4->name, BAD_CAST "BoundingBoxData") == 0){
@@ -1039,11 +1053,27 @@
 			      xmlNodePtr cur5 = cur4->children;
 			      while (cur5 != NULL
+				     && cur5->type != XML_ELEMENT_NODE
+				     && cur5->type != XML_TEXT_NODE
 				     && cur5->type != XML_CDATA_SECTION_NODE)
 				cur5 = cur5->next;
 			      if (cur5 != NULL
-				  && cur5->type == XML_CDATA_SECTION_NODE){
-				if(mv!=NULL)
-				  xmlFree(mv);
-				mv=xmlStrdup(cur5->content);
+				  && cur5->type != XML_CDATA_SECTION_NODE
+				  && cur5->type != XML_TEXT_NODE)
+				{
+				  xmlDocPtr doc1 = xmlNewDoc (BAD_CAST "1.0");
+				  int buffersize;
+				  xmlDocSetRootElement (doc1, cur5);
+				  xmlDocDumpFormatMemoryEnc (doc1, &mv,
+							     &buffersize,
+							     "utf-8", 0);
+				  addIntToMap (tmpmaps->content, "size",
+					       buffersize);
+				}
+			      else if (cur5 != NULL)/*
+				     && cur5->type == XML_CDATA_SECTION_NODE)*/{
+				xmlFree(mv);
+				if(cur5->content!=NULL){
+				  mv=xmlStrdup(cur5->content);
+				}
 			      }
 			    }
@@ -1088,4 +1118,8 @@
 		cur2 = cur2->next;
 	      }
+	    }
+	  if(memory!=NULL && strncasecmp(memory->value,"load",4)!=0)
+	    if(getMap(tmpmaps->content,"to_load")==NULL){
+	      addToMap(tmpmaps->content,"to_load","false");
 	    }
 	  {
@@ -1123,6 +1157,7 @@
 		  }
 	      }
-	    else
+	    else{
 	      addMapsToMaps (request_output, tmpmaps);
+	    }
 	  }
 	  freeMaps (&tmpmaps);
@@ -1198,4 +1233,5 @@
       const char ress[4][13] =
 	{ "mimeType", "encoding", "schema", "transmission" };
+      xmlFree (val);
       for (l = 0; l < 4; l++){
 	val = xmlGetProp (cur, BAD_CAST ress[l]);
@@ -1217,9 +1253,11 @@
 	while (ccur != NULL){
 	  if(ccur->type == XML_ELEMENT_NODE){
-	    char *xpathExpr=(char*)malloc(65+strlen(tmpmaps->name));
-	    sprintf(xpathExpr,"/*/*[local-name()='Output' and @id='%s']/*[local-name()='Output']",tmpmaps->name);
+	    char *xpathExpr=(char*)malloc(66+strlen(tmpmaps->name));
+	    sprintf(xpathExpr,"/*/*[local-name()='Output' and @id='%s']/*[local-name()='Output']",tmpmaps->name);	    
 	    xmlXPathObjectPtr tmpsptr = extractFromDoc (doc, xpathExpr);
 	    xmlNodeSet* cnodes = tmpsptr->nodesetval;
 	    xmlParseOutputs2(main_conf,request_inputs,&tmpmaps->child,doc,cnodes);
+	    xmlXPathFreeObject (tmpsptr);
+	    free(xpathExpr);
 	    break;
 	  }
@@ -1470,6 +1508,5 @@
 
   xmlInitParser ();
-  //xmlDocPtr doc = xmlReadMemory (post, cgiContentLength, "input_request.xml", NULL, XML_PARSE_RECOVER);
-  xmlDocPtr doc = xmlReadMemory (post, cgiContentLength, "input_request.xml", NULL, XML_PARSE_RECOVER | XML_PARSE_HUGE); // 
+  xmlDocPtr doc = xmlReadMemory (post, cgiContentLength, "input_request.xml", NULL, XML_PARSE_RECOVER);
 
   /**
@@ -1503,4 +1540,5 @@
 	  else
 	    addToMap(*request_inputs,"mode","auto");
+	  xmlFree(val);
 	  val = xmlGetProp (cur, BAD_CAST "response");
 	  if(val!=NULL){
@@ -1515,4 +1553,5 @@
 	    addToMap(*request_inputs,"ResponseDocument","");
 	  }
+	  xmlFree(val);
 	}
       }
@@ -1768,5 +1807,5 @@
 #endif
                   targetFile =
-                    open (storageNameOnServer, O_RDWR | O_CREAT | O_TRUNC,
+                    zOpen (storageNameOnServer, O_RDWR | O_CREAT | O_TRUNC,
                           S_IRWXU | S_IRGRP | S_IROTH);
                   if (targetFile < 0)
@@ -1788,5 +1827,5 @@
                   addToMap (tmpReqI->content, "lref", storageNameOnServer);
                   cgiFormFileClose (file);
-                  close (targetFile);
+                  zClose (targetFile);
 		  free(fileNameOnServer);
 		  free(storageNameOnServer);
@@ -1820,5 +1859,5 @@
   if (r_inputs == NULL){
     if(mandatory>0){
-      const char *replace=_("Mandatory parameter <%s> was not specified");
+      char *replace=_("Mandatory parameter <%s> was not specified");
       char *message=(char*)malloc((strlen(replace)+strlen(toCheck)+1)*sizeof(char));
       sprintf(message,replace,toCheck);
@@ -1869,8 +1908,8 @@
     }
     if(hasValidValue<0){
-      const char *replace=_("The value <%s> was not recognized, %s %s the only acceptable value.");
+      char *replace=_("The value <%s> was not recognized, %s %s the only acceptable value.");
       nb=0;
       char *vvalues=NULL;
-      const char* num=_("is");
+      char* num=_("is");
       while(avalues[nb]!=NULL){
 	char *tvalues;
@@ -1920,2 +1959,43 @@
   }
 }
+
+/**
+ * Parse cookie contained in request headers.
+ *
+ * @param conf the conf maps containinfg the main.cfg
+ * @param cookie the 
+ */
+void parseCookie(maps** conf,const char* cookie){
+  char* tcook=zStrdup(cookie);
+  char *token, *saveptr;
+  token = strtok_r (tcook, "; ", &saveptr);
+  maps* res=createMaps("cookies");
+  while (token != NULL){
+    char *token1, *saveptr1, *name;
+    int i=0;
+    token1 = strtok_r (token, "=", &saveptr1);
+    while (token1 != NULL){
+      if(i==0){
+	name=zStrdup(token1);
+	i++;
+      }
+      else{
+	if(res->content==NULL)
+	  res->content=createMap(name,token1);
+	else
+	  addToMap(res->content,name,token1);
+	free(name);
+	name=NULL;
+	i=0;
+      }
+      token1 = strtok_r (NULL, "=", &saveptr1);
+    }
+    if(name!=NULL)
+      free(name);
+    token = strtok_r (NULL, "; ", &saveptr);
+  }
+  addMapsToMaps(conf,res);
+  freeMaps(&res);
+  free(res);
+  free(tcook);
+}
Index: trunk/zoo-project/zoo-kernel/request_parser.h
===================================================================
--- trunk/zoo-project/zoo-kernel/request_parser.h	(revision 889)
+++ trunk/zoo-project/zoo-kernel/request_parser.h	(revision 917)
@@ -45,4 +45,5 @@
   int kvpParseOutputs(maps**,map *,maps**);
   int xmlParseInputs(maps**,service*,maps**,xmlDocPtr,xmlNodeSet*,HINTERNET*);
+  int xmlParseBoundingBox(maps** main_conf,map** current_input,xmlDocPtr doc);
   int xmlParseOutputs(maps**,map**,maps**,xmlDocPtr,xmlNodePtr,bool);
   int xmlParseRequest(maps**,const char*,map**,service*,maps**,maps**,HINTERNET*);
@@ -50,5 +51,6 @@
   void checkValidValue(map*,map**,const char*,const char**,int);
   int validateRequest(maps**,service*,map*,maps**,maps**,HINTERNET*);
-
+  void parseCookie(maps**,const char*);
+  
 #ifdef __cplusplus
 }
Index: trunk/zoo-project/zoo-kernel/response_print.c
===================================================================
--- trunk/zoo-project/zoo-kernel/response_print.c	(revision 889)
+++ trunk/zoo-project/zoo-kernel/response_print.c	(revision 917)
@@ -23,4 +23,5 @@
  */
 
+#include "service.h"
 #include "response_print.h"
 #include "request_parser.h"
@@ -31,4 +32,7 @@
 #else
 #include "cpl_vsi.h"
+#endif
+#ifdef USE_CALLBACK
+#include "service_callback.h"
 #endif
 
@@ -75,5 +79,5 @@
     }
     if(prefix!=NULL){
-      char* tmp0=strdup(serv->name);
+      char* tmp0=zStrdup(serv->name);
       free(serv->name);
       serv->name=(char*)malloc((strlen(prefix)+strlen(tmp0)+1)*sizeof(char));
@@ -179,5 +183,5 @@
     nbNs++;
     currId=0;
-    nsName[currId]=strdup(name);
+    nsName[currId]=zStrdup(name);
     usedNs[currId]=xmlNewNs(nr,BAD_CAST url,BAD_CAST name);
   }else{
@@ -186,5 +190,5 @@
       nbNs++;
       currId=nbNs-1;
-      nsName[currId]=strdup(name);
+      nsName[currId]=zStrdup(name);
       usedNs[currId]=xmlNewNs(nr,BAD_CAST url,BAD_CAST name);
     }
@@ -251,12 +255,12 @@
   if(soap!=NULL && strcasecmp(soap->value,"true")==0){
     int lNbNs=nbNs;
-    nsName[lNbNs]=strdup("soap");
+    nsName[lNbNs]=zStrdup("soap");
     usedNs[lNbNs]=xmlNewNs(NULL,BAD_CAST "http://www.w3.org/2003/05/soap-envelope",BAD_CAST "soap");
     nbNs++;
     xmlNodePtr nr = xmlNewNode(usedNs[lNbNs], BAD_CAST "Envelope");
-    nsName[nbNs]=strdup("soap");
+    nsName[nbNs]=zStrdup("soap");
     usedNs[nbNs]=xmlNewNs(nr,BAD_CAST "http://www.w3.org/2003/05/soap-envelope",BAD_CAST "soap");
     nbNs++;
-    nsName[nbNs]=strdup("xsi");
+    nsName[nbNs]=zStrdup("xsi");
     usedNs[nbNs]=xmlNewNs(nr,BAD_CAST "http://www.w3.org/2001/XMLSchema-instance",BAD_CAST "xsi");
     nbNs++;
@@ -338,8 +342,8 @@
       }
       else{
-	nc4 = xmlNewNode(ns_ows, BAD_CAST "Language");
-	xmlAddChild(nc4,xmlNewText(BAD_CAST buff));
 	if(dcount==0){
 	  if(vid==0){
+	    nc4 = xmlNewNode(ns_ows, BAD_CAST "Language");
+	    xmlAddChild(nc4,xmlNewText(BAD_CAST buff));
 	    xmlAddChild(nc2,nc4);
 	    xmlAddChild(nc1,nc2);
@@ -361,8 +365,8 @@
       nc4 = xmlNewNode(ns_ows, BAD_CAST "Language");
       xmlAddChild(nc4,xmlNewText(BAD_CAST buff));	      
-	if(vid==0)
-	  xmlAddChild(nc3,nc4);
-	else
-	  xmlAddChild(nc1,nc4);
+      if(vid==0)
+	xmlAddChild(nc3,nc4);
+      else
+	xmlAddChild(nc1,nc4);
     }
   }
@@ -590,11 +594,11 @@
     map* tmp=getMap(toto1->content,"serverAddress");
     if(tmp!=NULL){
-      SERVICE_URL = strdup(tmp->value);
+      SERVICE_URL = zStrdup(tmp->value);
     }
     else
-      SERVICE_URL = strdup("not_defined");
+      SERVICE_URL = zStrdup("not_defined");
   }
   else
-    SERVICE_URL = strdup("not_defined");
+    SERVICE_URL = zStrdup("not_defined");
 
   for(j=0;j<nbSupportedRequests;j++){
@@ -644,7 +648,7 @@
  * @return the generated wps:ProcessOfferings xmlNodePtr 
  */
-void printGetCapabilitiesForProcess(registry *reg, maps* m,xmlNodePtr nc,service* serv){
+void printGetCapabilitiesForProcess(registry *reg, maps* m,xmlDocPtr doc,xmlNodePtr nc,service* serv){
   xmlNsPtr ns,ns_ows,ns_xml,ns_xlink;
-  xmlNodePtr n=NULL,nc1,nc2;
+  xmlNodePtr n=NULL,nc1,nc2,nc3;
   map* version=getMapFromMaps(m,"main","rversion");
   int vid=getVersionId(version->value);
@@ -667,4 +671,6 @@
       limit=7;
     }
+    nc3=NULL;
+    map* sType=getMap(serv->content,"serviceType");
     for(;i<limit;i+=2){
       if(capabilities[vid][i]==NULL)
@@ -682,6 +688,10 @@
 	    xmlNewNsProp(nc1,ns,BAD_CAST capabilities[vid][i],BAD_CAST tmp1->value);
 	}
-	else
-	  xmlNewNsProp(nc1,ns,BAD_CAST capabilities[vid][i],BAD_CAST capabilities[vid][i+1]);
+	else{
+	  if(i==3 && vid==1 && sType!=NULL && strstr(sType->value,"HPC")!=NULL)
+	    xmlNewNsProp(nc1,ns,BAD_CAST capabilities[vid][i],BAD_CAST "async-execute dismiss");
+	  else
+	    xmlNewNsProp(nc1,ns,BAD_CAST capabilities[vid][i],BAD_CAST capabilities[vid][i+1]);
+	}
       }
     }
@@ -690,13 +700,18 @@
     printDescription(nc1,ns_ows,serv->name,serv->content,vid);
     tmp1=serv->metadata;
-    while(tmp1!=NULL){
-      nc2 = xmlNewNode(ns_ows, BAD_CAST "Metadata");
-      xmlNewNsProp(nc2,ns_xlink,BAD_CAST tmp1->name,BAD_CAST tmp1->value);
-      xmlAddChild(nc1,nc2);
-      tmp1=tmp1->next;
-    }
-
+
+    addMetadata(tmp1,doc,nc1,ns_ows,ns_xlink,vid);
+    tmp1=serv->additional_parameters;
+    int fromDb=-1;
+    map* test=getMap(serv->content,"fromDb");
+    if(test!=NULL && strncasecmp(test->value,"true",4)==0)
+      fromDb=1;
+    addAdditionalParameters(tmp1,doc,nc1,ns_ows,ns_xlink,fromDb);
+
+    if(nc3!=NULL)
+      xmlAddChild(nc1,nc3);
     xmlAddChild(nc,nc1);
   }
+
 }
 
@@ -708,6 +723,7 @@
  * @param content the servive main content created from the zcfg file
  * @param vid the version identifier (0 for 1.0.0 and 1 for 2.0.0)
- */
-void attachAttributes(xmlNodePtr n,xmlNsPtr ns,map* content,int vid){
+ * @param serviceType string containing the current service type
+ */
+void attachAttributes(xmlNodePtr n,xmlNsPtr ns,map* content,int vid,map* serviceType){
   int limit=7;
   for(int i=1;i<limit;i+=2){
@@ -728,9 +744,210 @@
     }
     else{
-      if(vid==0 && i>=2)
-	xmlNewProp(n,BAD_CAST capabilities[vid][i],BAD_CAST capabilities[vid][i+1]);
+      if(i==3 && vid==1 && serviceType!=NULL && strstr(serviceType->value,"HPC")!=NULL)
+	xmlNewNsProp(n,ns,BAD_CAST capabilities[vid][i],BAD_CAST "async-execute dismiss");
       else
-	xmlNewNsProp(n,ns,BAD_CAST capabilities[vid][i],BAD_CAST capabilities[vid][i+1]);
-    }
+	if(vid==0 && i>=2)
+	  xmlNewProp(n,BAD_CAST capabilities[vid][i],BAD_CAST capabilities[vid][i+1]);
+	else
+	  xmlNewNsProp(n,ns,BAD_CAST capabilities[vid][i],BAD_CAST capabilities[vid][i+1]);
+    }
+  }
+}
+
+/**
+ * Add a Metadata node to any existing node.
+ * @param meta the map defining the additional parameters
+ * @param doc the XML document used
+ * @param nb the node to add the additional parameters
+ * @param ns_ows the OWS namespace
+ * @param ns_xlink the xlink namespace
+ * @param vid the version of WPS to use (0 for 1.0.0 and 1 for 2.0)
+ */
+void addMetadata(map* meta,xmlDocPtr doc,xmlNodePtr nc,xmlNsPtr ns_ows,xmlNsPtr ns_xlink,int vid){
+  int hasTitle=-1;
+  int hasValue=-1;
+  xmlNodePtr nc1;
+  map* oMeta=meta;
+  int isAdditionalParameters=-1;
+  int level=0;
+  map* test=getMap(meta,"title");
+  if(test!=NULL)
+    level+=1;
+  test=getMap(meta,"href");
+  if(test!=NULL)
+    level+=1;
+  test=getMap(meta,"role");
+  if(test!=NULL)
+    level+=1;
+  if(count(oMeta)>level+1)
+    isAdditionalParameters=1;
+  char *ctitle=NULL;
+  while(meta!=NULL){
+    if(hasTitle<0)
+      if(isAdditionalParameters<0)
+	nc1 = xmlNewNode(ns_ows, BAD_CAST "Metadata");
+      else
+	if(hasValue<0)
+	  nc1 = xmlNewNode(ns_ows, BAD_CAST "AdditionalParameters");
+    if(strncasecmp(meta->name,"title",5)==0 ||
+       strcasecmp(meta->name,"href")==0 ||
+       strcasecmp(meta->name,"role")==0 ){
+      int index=5;
+      if(strncasecmp(meta->name,"title",5)==0){
+	index=6;
+	hasTitle=1;
+	if(ctitle!=NULL && strcasecmp(meta->value,ctitle)!=0){
+	  xmlAddChild(nc,nc1);
+	  nc1 = xmlNewNode(ns_ows, BAD_CAST "AdditionalParameters");
+	  free(ctitle);
+	  ctitle=NULL;
+	}
+	if(ctitle==NULL){
+	  char *tmp=(char*)malloc((strlen(meta->name)+1)*sizeof(char));
+	  snprintf(tmp,index,"%s",meta->name);
+	  xmlNewNsProp(nc1,ns_xlink,BAD_CAST tmp,BAD_CAST meta->value);
+	  free(tmp);
+	}	  
+	if(ctitle!=NULL)
+	  free(ctitle);
+	ctitle=zStrdup(meta->value);
+      }
+    }else{
+      xmlNodePtr nc2 = xmlNewNode(ns_ows, BAD_CAST "AdditionalParameter");
+      xmlNodePtr nc3 = xmlNewNode(ns_ows, BAD_CAST "Name");
+      xmlAddChild(nc3,xmlNewText(BAD_CAST meta->name));
+      xmlNodePtr nc4 = xmlNewNode(ns_ows, BAD_CAST "Value");
+      xmlAddChild(nc4,xmlNewText(BAD_CAST meta->value));
+      xmlAddChild(nc2,nc3);
+      xmlAddChild(nc2,nc4);
+      xmlAddChild(nc1,nc2);
+      hasTitle=-1;
+    }
+    meta=meta->next;
+    if(hasTitle<0){
+      hasValue=1;
+      if(isAdditionalParameters){
+	if(vid==0){
+	  meta=NULL;
+	  break;
+	}else
+	  xmlAddChild(nc,nc1);
+      }
+    }
+  }
+  if(oMeta!=NULL && hasValue<0 && nc1!=NULL){
+    xmlAddChild(nc,nc1);
+  }
+}
+
+/**
+ * Add AdditionalParameters nodes to any existing node.
+ * @param meta the map defining the additional parameters
+ * @param doc the XML document used
+ * @param nb the node to add the additional parameters
+ * @param ns_ows the OWS namespace
+ * @param ns_xlink the xlink namespace
+ * @param fromDb 1 if the metadata has been extracted from the metadb, 
+ * 0 otherwise
+ */
+void addAdditionalParameters(map* meta,xmlDocPtr doc,xmlNodePtr nc,xmlNsPtr ns_ows,xmlNsPtr ns_xlink,int fromDb){
+  int hasTitle=-1;
+  int hasValue=-1;
+  int toAddAtEnd=-1;
+  int cnt=0;
+  xmlNodePtr* ncr=NULL;
+  xmlNodePtr nc1;
+  map* oMeta=meta;
+  int isAdditionalParameters=-1;
+  int level=0;
+  map* test=getMap(meta,"title");
+  map* otitle=getMap(meta,"title");
+  map* length=getMap(meta,"length");
+  int len=0;
+  char *ctitle=NULL;
+    
+  if(test!=NULL)
+    level+=1;
+  test=getMap(meta,"href");
+  if(test!=NULL)
+    level+=1;
+  test=getMap(meta,"role");
+  if(test!=NULL)
+    level+=1;
+  if(count(oMeta)>level+1)
+    isAdditionalParameters=1;
+
+  while(meta!=NULL){
+    if(hasTitle<0 && hasValue<0){
+      nc1 = xmlNewNode(ns_ows, BAD_CAST "AdditionalParameters");
+    }
+    if(strncasecmp(meta->name,"title",5)==0 ||
+       strcasecmp(meta->name,"href")==0 ||
+       strcasecmp(meta->name,"role")==0 ){
+      int index=5;
+      if(strncasecmp(meta->name,"title",5)==0){
+	index=6;
+	hasTitle=1;
+	if(ctitle!=NULL && strcasecmp(meta->value,ctitle)!=0){
+	  xmlNodePtr ncTmp = xmlDocCopyNodeList(doc,nc1);
+	  xmlAddChild(nc,ncTmp);
+	  xmlFreeNode(nc1);
+	  toAddAtEnd=1;
+	  cnt++;
+	  nc1 = xmlNewNode(ns_ows, BAD_CAST "AdditionalParameters");
+	  free(ctitle);
+	  ctitle=NULL;
+	}
+	if(ctitle==NULL){
+	  char *tmp=(char*)malloc((strlen(meta->name)+1)*sizeof(char));
+	  snprintf(tmp,index,"%s",meta->name);
+	  xmlNewNsProp(nc1,ns_xlink,BAD_CAST tmp,BAD_CAST meta->value);
+	  free(tmp);
+	}	  
+	if(ctitle!=NULL)
+	  free(ctitle);
+	ctitle=zStrdup(meta->value);
+      }else{
+	xmlNewNsProp(nc1,ns_xlink,BAD_CAST meta->name,BAD_CAST meta->value);
+      }
+    }else{
+      if(strncasecmp(meta->name,"length",6)!=0 && strncasecmp(meta->name,"fromDb",6)!=0){
+	xmlNodePtr nc2 = xmlNewNode(ns_ows, BAD_CAST "AdditionalParameter");
+	xmlNodePtr nc3 = xmlNewNode(ns_ows, BAD_CAST "Name");
+	xmlAddChild(nc3,xmlNewText(BAD_CAST meta->name));
+	xmlAddChild(nc2,nc3);
+	if(fromDb<0){
+	  char *mptr;
+	  char* meta_values=strtok_r(meta->value,",",&mptr);
+	  while(meta_values!=NULL){
+	    xmlNodePtr nc4 = xmlNewNode(ns_ows, BAD_CAST "Value");
+	    xmlAddChild(nc4,xmlNewText(BAD_CAST meta_values));
+	    xmlAddChild(nc2,nc4);
+	    meta_values=strtok_r(NULL,",",&mptr);
+	  }
+	}else{
+	  xmlNodePtr nc4 = xmlNewNode(ns_ows, BAD_CAST "Value");
+	  xmlAddChild(nc4,xmlNewCDataBlock(doc,BAD_CAST meta->value,strlen(meta->value)));
+	  xmlAddChild(nc2,nc4);
+	}
+	xmlAddChild(nc1,nc2);
+      }
+      hasTitle=-1;
+    }
+    meta=meta->next;
+    if(hasTitle<0){
+      //xmlAddChild(nc,nc1);
+      hasValue=1;
+    }/*else
+       if(ctitle!=NULL)
+       free(ctitle);*/
+  }
+  if(length!=NULL)
+    len=atoi(length->value);
+  if(otitle!=NULL)
+    len=1;
+  if(cnt<len){
+    xmlAddChild(nc,nc1);
+    free(ctitle);
   }
 }
@@ -792,5 +1009,5 @@
  * @return the generated wps:ProcessOfferings xmlNodePtr 
  */
-void printDescribeProcessForProcess(registry *reg, maps* m,xmlNodePtr nc,service* serv){
+void printDescribeProcessForProcess(registry *reg, maps* m,xmlDocPtr doc,xmlNodePtr nc,service* serv){
   xmlNsPtr ns,ns_ows,ns_xlink;
   xmlNodePtr n,nc1;
@@ -798,4 +1015,9 @@
   map* version=getMapFromMaps(m,"main","rversion");
   int vid=getVersionId(version->value);
+  int fromDb=-1;
+  map* serviceType=getMap(serv->content,"serviceType");
+  map* test=getMap(serv->content,"fromDb");
+  if(test!=NULL && strncasecmp(test->value,"true",4)==0)
+    fromDb=1;
 
   n=nc;
@@ -811,5 +1033,5 @@
   if(vid==0){
     nc = xmlNewNode(NULL, BAD_CAST "ProcessDescription");
-    attachAttributes(nc,ns,serv->content,vid);
+    attachAttributes(nc,ns,serv->content,vid,NULL);
   }
   else{
@@ -828,5 +1050,5 @@
       }
     }
-    attachAttributes(nc2,NULL,serv->content,vid);
+    attachAttributes(nc2,NULL,serv->content,vid,serviceType);
     map* level=getMap(serv->content,"level");
     if(level!=NULL && strcasecmp(level->value,"generic")==0)
@@ -843,7 +1065,5 @@
     tmp1=serv->metadata;
     while(tmp1!=NULL){
-      nc1 = xmlNewNode(ns_ows, BAD_CAST "Metadata");
-      xmlNewNsProp(nc1,ns_xlink,BAD_CAST tmp1->name,BAD_CAST tmp1->value);
-      xmlAddChild(nc,nc1);
+      addMetadata(tmp1,doc,nc,ns_ows,ns_xlink,vid);
       tmp1=tmp1->next;
     }
@@ -855,5 +1075,10 @@
     }
   }else{
+    tmp1=serv->metadata;
+    addMetadata(tmp1,doc,nc,ns_ows,ns_xlink,vid);
     addInheritedMetadata(nc,ns_ows,ns_xlink,reg,m,serv);
+    tmp1=serv->additional_parameters;
+    if(vid!=0)
+      addAdditionalParameters(tmp1,doc,nc,ns_ows,ns_xlink,fromDb);
   }
 
@@ -862,9 +1087,9 @@
     if(vid==0){
       nc1 = xmlNewNode(NULL, BAD_CAST "DataInputs");
-      printFullDescription(1,e,"Input",ns,ns_ows,nc1,vid);
+      printFullDescription(doc,1,e,"Input",ns,ns_ows,nc1,vid,fromDb,NULL);
       xmlAddChild(nc,nc1);
     }
     else{
-      printFullDescription(1,e,"wps:Input",ns,ns_ows,nc,vid);
+      printFullDescription(doc,1,e,"wps:Input",ns,ns_ows,nc,vid,fromDb,NULL);
     }
   }
@@ -873,9 +1098,9 @@
   if(vid==0){
     nc1 = xmlNewNode(NULL, BAD_CAST "ProcessOutputs");
-    printFullDescription(0,e,"Output",ns,ns_ows,nc1,vid);
+    printFullDescription(doc,0,e,"Output",ns,ns_ows,nc1,vid,fromDb,NULL);
     xmlAddChild(nc,nc1);
   }
   else{
-    printFullDescription(0,e,"wps:Output",ns,ns_ows,nc,vid);
+    printFullDescription(doc,0,e,"wps:Output",ns,ns_ows,nc,vid,fromDb,serviceType);
   }
   if(vid==0)
@@ -899,6 +1124,8 @@
  * @param nc1 the XML node to use to add the created tree
  * @param vid the WPS version id (0 for 1.0.0, 1 for 2.0.0)
- */
-void printFullDescription(int in,elements *elem,const char* type,xmlNsPtr ns,xmlNsPtr ns_ows,xmlNodePtr nc1,int vid){
+ * @param fromDb 1 in case the metadata comes from the DB, -1 in other cases
+ * @param serviceType the serviceType found in the ZCFG file or the DB
+ */
+void printFullDescription(xmlDocPtr doc,int in,elements *elem,const char* type,xmlNsPtr ns,xmlNsPtr ns_ows,xmlNodePtr nc1,int vid,int fromDb,const map* serviceType){
   xmlNsPtr ns1=NULL;
   if(vid==1)
@@ -913,4 +1140,5 @@
     int isAnyValue=1;
     nc2 = xmlNewNode(NULL, BAD_CAST type);
+    // Extract min/max Occurence information
     if(strstr(type,"Input")!=NULL){
       tmp1=getMap(e->content,"minOccurs");
@@ -935,4 +1163,7 @@
 
     if(e->format!=NULL){
+#ifdef USE_HPC	    
+    DEFAULT_OUT:
+#endif
       const char orderedFields[13][14]={
 	"mimeType",
@@ -952,5 +1183,5 @@
       //Build the (Literal/Complex/BoundingBox)Data node
       if(strncmp(type,"Output",6)==0){
-	if(strncasecmp(e->format,"LITERALDATA",strlen(e->format))==0)
+	if(strncasecmp(e->format,"LITERAL",7)==0)
 	  nc3 = xmlNewNode(ns1, BAD_CAST "LiteralOutput");
 	else if(strncasecmp(e->format,"COMPLEXDATA",strlen(e->format))==0)
@@ -998,5 +1229,13 @@
 		strcmp(e->format,"BoundingBoxData")==0){
 	  datatype=2;
-	  nc5 = xmlNewNode(NULL, BAD_CAST "Default");
+	  if(vid==0)
+	    nc5 = xmlNewNode(NULL, BAD_CAST "Default");
+	  else{
+	    xmlNodePtr nc6 = xmlNewNode(ns1, BAD_CAST "Format");
+	    xmlNewProp(nc6,BAD_CAST "mimeType",BAD_CAST "text/xml");
+	    xmlNewProp(nc6,BAD_CAST "default",BAD_CAST "true");
+	    xmlAddChild(nc3,nc6);
+	    nc5 = xmlNewNode(NULL, BAD_CAST "SupportedCRS");
+	  }
 	}
 	else{
@@ -1039,7 +1278,8 @@
 	    while(token!=NULL){
 	      nc7 = xmlNewNode(ns_ows, BAD_CAST "Value");
-	      char *tmps=strdup(token);
+	      char *tmps=zStrdup(token);
 	      tmps[strlen(tmps)]=0;
-	      xmlAddChild(nc7,xmlNewText(BAD_CAST tmps));
+	      nc8 = xmlNewText(BAD_CAST tmps);
+	      xmlAddChild(nc7,nc8);
 	      free(tmps);
 	      xmlAddChild(nc6,nc7);
@@ -1207,7 +1447,13 @@
 		 strncasecmp(tmp1->name,"range",5)!=0){
 		if(datatype!=1){
-		  char *tmp2=zCapitalize1(tmp1->name);
-		  nc9 = xmlNewNode(NULL, BAD_CAST tmp2);
-		  free(tmp2);
+		  if(datatype==2 && vid==1){
+		    nc9 = xmlNewNode(ns, BAD_CAST "SupportedCRS");
+		    xmlNewProp(nc9,BAD_CAST "default",BAD_CAST "true");
+		  }
+		  else{
+		    char *tmp2=zCapitalize1(tmp1->name);
+		    nc9 = xmlNewNode(NULL, BAD_CAST tmp2);
+		    free(tmp2);
+		  }
 		}
 		else{
@@ -1218,17 +1464,21 @@
 		xmlAddChild(nc9,xmlNewText(BAD_CAST tmp1->value));
 		if(vid==0 || oI>=3){
-		  if(vid==0 || oI!=4)
-		    xmlAddChild(nc5,nc9);
+		  if(vid==0 || oI!=4){
+		    if(datatype==2 && vid==1)
+		      xmlAddChild(nc3,nc9);
+		    else
+		      xmlAddChild(nc5,nc9);
+		  }
 		  if(oI==4 && vid==1){
 		    xmlNewProp(nc9,BAD_CAST "default",BAD_CAST "true");
 		  }
 		}
-		else
-		  xmlFree(nc9);
+		else{
+		  xmlFreeNode(nc9);
+		}
 		if(strcasecmp(tmp1->name,"uom")==0)
 		  hasUOM1=true;
 		hasUOM=true;
-	      }else 	  
-		tmp1=tmp1->next;
+	      }
 	    }
 	}
@@ -1245,19 +1495,26 @@
 	  }else{
 	    if(hasUOM1==false && vid==0){
-	      xmlFreeNode(nc5);
-	      if(datatype==1)
+	      if(nc5!=NULL)
+		xmlFreeNode(nc5);
+	      if(datatype==1){
 		xmlFreeNode(nc4);
+	      }
 	    }
-	    else
+	    else{
 	      xmlAddChild(nc3,nc5);
+	    }
 	  }
 	}else{
-	  xmlAddChild(nc3,nc5);
+	  if(vid==0)
+	    xmlAddChild(nc3,nc5);
+	  else
+	    xmlFreeNode(nc5);
 	}
       
-	if(datatype!=1 && default1<0){
+	if(datatype==0 && default1<0){
 	  xmlFreeNode(nc5);
-	  if(datatype!=2)
+	  if(datatype!=2){
 	    xmlFreeNode(nc4);
+	  }
 	}
 
@@ -1310,20 +1567,6 @@
 	      nc9 = xmlNewNode(ns_ows, BAD_CAST tmp2);
 	      free(tmp2);
-	      //xmlNewProp(nc9, BAD_CAST "default", BAD_CAST "true");
 	      xmlAddChild(nc9,xmlNewText(BAD_CAST tmp1->value));
 	      xmlAddChild(nc5,nc9);
-	      /*struct iotype * _ltmp=e->supported;
-		while(_ltmp!=NULL){
-		tmp1=getMap(_ltmp->content,"uom");
-		if(tmp1!=NULL){
-		char *tmp2=zCapitalize(tmp1->name);
-		nc9 = xmlNewNode(ns_ows, BAD_CAST tmp2);
-		free(tmp2);
-		xmlAddChild(nc9,xmlNewText(BAD_CAST tmp1->value));
-		xmlAddChild(nc5,nc9);
-		}
-		_ltmp=_ltmp->next;
-		}*/
-	    
 	    }
 	  }
@@ -1340,15 +1583,12 @@
 	xmlNsPtr ns_xlink=usedNs[xlinkId];
 
-	while(metadata!=NULL){
-	  nc6=xmlNewNode(ns_ows, BAD_CAST "Metadata");
-	  xmlNewNsProp(nc6,ns_xlink,BAD_CAST metadata->name,BAD_CAST metadata->value);
-	  xmlAddChild(nc2,nc6);
-	  metadata=metadata->next;
-	}
+	addMetadata(metadata,doc,nc2,ns_ows,ns_xlink,vid);
+	if(vid!=0)
+	  addAdditionalParameters(e->additional_parameters,doc,nc2,ns_ows,ns_xlink,fromDb);
 
       }
 
       _tmp=e->supported;
-      if(_tmp==NULL && datatype!=1)
+      if(_tmp==NULL && datatype==0)
 	_tmp=e->defaults;
 
@@ -1396,7 +1636,12 @@
 	       strcasecmp(tmp1->name,"extension")!=0){
 	      if(datatype!=1){
-		char *tmp2=zCapitalize1(tmp1->name);
-		nc6 = xmlNewNode(NULL, BAD_CAST tmp2);
-		free(tmp2);
+		if(datatype==2 && vid==1){
+		  nc6 = xmlNewNode(ns, BAD_CAST "SupportedCRS");
+		}
+		else{
+		  char *tmp2=zCapitalize1(tmp1->name);
+		  nc6 = xmlNewNode(NULL, BAD_CAST tmp2);
+		  free(tmp2);
+		}
 	      }
 	      else{
@@ -1422,11 +1667,17 @@
 	      }
 	      if(vid==0 || oI>=3){
-		if(vid==0 || oI!=4)
-		  xmlAddChild(nc5,nc6);
-		else
-		  xmlFree(nc6);
+		if(vid==0 || oI!=4){
+		  if(datatype==2 && vid==1)
+		    xmlAddChild(nc3,nc6);
+		  else
+		    xmlAddChild(nc5,nc6);
+		}
+		else{
+		  xmlFreeNode(nc6);
+		}
 	      }
-	      else
-		xmlFree(nc6);
+	      else{
+		xmlFreeNode(nc6);
+	      }
 	    }
 	    tmp1=tmp1->next;
@@ -1439,9 +1690,10 @@
 	    }
 	    else{
-	      xmlAddChild(nc3,nc5);
+	      if(datatype!=2)
+		xmlAddChild(nc3,nc5);
 	    }
 
 	  }else{
-	    if(datatype!=1)
+	    if(datatype==2 && vid==0)
 	      xmlAddChild(nc3,nc5);
 	  }
@@ -1459,6 +1711,8 @@
 	  }
 	  else
-	    if(datatype!=1)
+	    if(datatype==0){
+	      xmlFreeNode(nc4);
 	      xmlAddChild(nc3,nc5);
+	    }
 
 	_tmp=_tmp->next;
@@ -1466,6 +1720,7 @@
 
       if(hasSupported==0){
-	if(datatype==0 && vid!=0)
+	if(datatype==0 && vid!=0){
 	  xmlFreeNode(nc4);
+	}
 	xmlFreeNode(nc5);
       }
@@ -1478,4 +1733,5 @@
 	}
 	else{
+	  xmlFreeNode(nc4);
 	  xmlAddChild(nc3,nc5);
 	}
@@ -1491,25 +1747,26 @@
     }else{
       if(e->child!=NULL && vid!=0){
-	printFullDescription(in,e->child,type,ns,ns_ows,nc2,vid);
-      }
-    }
-    
+	printFullDescription(doc,in,e->child,type,ns,ns_ows,nc2,vid,fromDb,NULL);
+      }
+    }
     if(e->child!=NULL && vid==0){
       elements* children=dupElements(e->child);
       elements* cursor=children;
       while(cursor!=NULL){
-	char* tmp=strdup(cursor->name);
-	free(cursor->name);
-	cursor->name=(char*)malloc((strlen(cursor->name)+strlen(e->name)+2)*sizeof(char));
-	sprintf(cursor->name,"%s.%s",e->name,tmp);
+	elements* ccursor=cursor;
+	char* tmp=zStrdup(ccursor->name);
+	free(ccursor->name);
+	ccursor->name=(char*)malloc((strlen(tmp)+strlen(e->name)+2)*sizeof(char));
+	sprintf(ccursor->name,"%s.%s",e->name,tmp);
 	cursor=cursor->next;
       }
-      printFullDescription(in,children,type,ns,ns_ows,nc2,vid);
-      xmlAddChild(nc1,nc2);
+      printFullDescription(doc,in,children,type,ns,ns_ows,nc1,vid,fromDb,serviceType);
       freeElements(&children);
       free(children);
-    }else
-      xmlAddChild(nc1,nc2);
-    
+    }else{
+      if(nc2!=NULL){
+	xmlAddChild(nc1,nc2);
+      }
+    }
     e=e->next;
   }
@@ -1528,5 +1785,5 @@
  * @param outputs the outputs generated by the service
  */
-void printProcessResponse(maps* m,map* request, int pid,service* serv,const char* service,int status,maps* inputs,maps* outputs){
+void printProcessResponse(maps* m,map* request, int pid,service* serv,const char* service,int status,maps* inputs,maps* outputs){	
   xmlNsPtr ns,ns_ows,ns_xlink;
   xmlNodePtr nr,n,nc,nc1=NULL,nc3;
@@ -1549,5 +1806,5 @@
   char stored_path[1024];
   memset(stored_path,0,1024);
-    
+  
   if(vid==0){
     char tmp[256];
@@ -1734,5 +1991,5 @@
     }
   }
-
+  
   /**
    * Display the process output only when requested !
@@ -1744,12 +2001,12 @@
     maps* mcursor=outputs;
     elements* scursor=serv->outputs;
-    map* testResponse=getMap(request,"RawDataOutput");
+    map* testResponse=getMap(request,"RawDataOutput");	
     if(testResponse==NULL)
       testResponse=getMap(request,"ResponseDocument");
-    while(mcursor!=NULL){
+    while(mcursor!=NULL){		
       map* tmp0=getMap(mcursor->content,"inRequest");
-      scursor=getElements(serv->outputs,mcursor->name);
-      if(scursor!=NULL){
-	if(testResponse==NULL || tmp0==NULL){
+      scursor=getElements(serv->outputs,mcursor->name);	  
+      if(scursor!=NULL){		  
+	if(testResponse==NULL || tmp0==NULL){		
 	  if(vid==0)
 	    printIOType(doc,nc,ns,ns_ows,ns_xlink,scursor,mcursor,"Output",vid);
@@ -1758,11 +2015,10 @@
 	}
 	else
-
-	  if(tmp0!=NULL && strncmp(tmp0->value,"true",4)==0){
+	  if(tmp0!=NULL && strncmp(tmp0->value,"true",4)==0){		  
 	    if(vid==0)
 	      printIOType(doc,nc,ns,ns_ows,ns_xlink,scursor,mcursor,"Output",vid);
 	    else
 	      printIOType(doc,n,ns,ns_ows,ns_xlink,scursor,mcursor,"Output",vid);
-	  }
+	  }	
       }else
 	/**
@@ -1775,9 +2031,8 @@
 	  printIOType(doc,n,ns,ns_ows,ns_xlink,scursor,mcursor,"Output",vid);
       mcursor=mcursor->next;
-    }
+    }	
     if(vid==0)
       xmlAddChild(n,nc);
-  }
-
+  }  
   if(vid==0 && 
      hasStoredExecuteResponse==true 
@@ -1834,4 +2089,5 @@
 #endif
   }
+
   printDocument(m,doc,pid);
 
@@ -1891,5 +2147,5 @@
   else{
     /*
-    dumpElements(e);
+      dumpElements(e);
     */
     return;
@@ -1900,5 +2156,5 @@
        || strncasecmp(tmp->name,"SCHEMA",strlen(tmp->name))==0
        || strncasecmp(tmp->name,"UOM",strlen(tmp->name))==0)
-    xmlNewProp(nc1,BAD_CAST tmp->name,BAD_CAST tmp->value);
+      xmlNewProp(nc1,BAD_CAST tmp->name,BAD_CAST tmp->value);
     tmp=tmp->next;
   }
@@ -1927,6 +2183,5 @@
  * @param type the type
  */
-void printIOType(xmlDocPtr doc,xmlNodePtr nc,xmlNsPtr ns_wps,xmlNsPtr ns_ows,xmlNsPtr ns_xlink,elements* e,maps* m,const char* type,int vid){
-
+void printIOType(xmlDocPtr doc,xmlNodePtr nc,xmlNsPtr ns_wps,xmlNsPtr ns_ows,xmlNsPtr ns_xlink,elements* e,maps* m,const char* type,int vid){	
   xmlNodePtr nc1,nc2,nc3;
   nc1=xmlNewNode(ns_wps, BAD_CAST type);
@@ -1935,6 +2190,5 @@
     tmp=e->content;
   else
-    tmp=m->content;
-
+    tmp=m->content;  
   if(vid==0){
     nc2=xmlNewNode(ns_ows, BAD_CAST "Identifier");
@@ -1976,11 +2230,11 @@
     xmlNewProp(nc1,BAD_CAST "id",BAD_CAST (e!=NULL?e->name:m->name));
   }
-
+  
   // IO type nested outputs
-  if(m->child!=NULL){
+  if(m->child!=NULL){	  
     maps* curs=m->child;
     elements* ecurs=getElements(e,(e!=NULL?e->name:m->name));
     ecurs=ecurs->child;
-    while(curs!=NULL){
+    while(curs!=NULL/* && ecurs!=NULL*/){
       ecurs=getElements(ecurs,(curs->name));
       map* inRequest=getMap(curs->content,"inRequest");
@@ -1992,11 +2246,11 @@
     }
   }
-  else{
+  else{	  
     map *tmpMap=getMap(m->content,"Reference");
-    if(tmpMap==NULL){
+    if(tmpMap==NULL){		
       nc2=xmlNewNode(ns_wps, BAD_CAST "Data");
-      if(e!=NULL && e->format!=NULL){
-	if(strncasecmp(e->format,"LiteralOutput",strlen(e->format))==0)
-	  nc3=xmlNewNode(ns_wps, BAD_CAST "LiteralData");
+      if(e!=NULL && e->format!=NULL){		  
+		  if (strncasecmp(e->format, "LiteralOutput", strlen(e->format)) == 0)		  			  
+			  nc3 = xmlNewNode(ns_wps, BAD_CAST "LiteralData");		  
 	else
 	  if(strncasecmp(e->format,"ComplexOutput",strlen(e->format))==0)
@@ -2005,8 +2259,8 @@
 	    nc3=xmlNewNode(ns_wps, BAD_CAST "BoundingBoxData");
 	  else
-	    nc3=xmlNewNode(ns_wps, BAD_CAST e->format);
-      }
-      else {
-	map* tmpV=getMapFromMaps(m,"format","value");
+	    nc3=xmlNewNode(ns_wps, BAD_CAST e->format);		  
+      }
+      else {		  
+	map* tmpV=getMapFromMaps(m,"format","value");	
 	if(tmpV!=NULL)
 	  nc3=xmlNewNode(ns_wps, BAD_CAST tmpV->value);
@@ -2014,6 +2268,6 @@
 	  nc3=xmlNewNode(ns_wps, BAD_CAST "LiteralData");
       } 
-      tmp=m->content;
-      
+      tmp=m->content;	  
+
       while(tmp!=NULL){
 	if(strcasecmp(tmp->name,"mimeType")==0 ||
@@ -2021,6 +2275,5 @@
 	   strcasecmp(tmp->name,"schema")==0 ||
 	   strcasecmp(tmp->name,"datatype")==0 ||
-	   strcasecmp(tmp->name,"uom")==0) {
-	  
+	   strcasecmp(tmp->name,"uom")==0) {	
 	  if(vid==0)
 	    xmlNewProp(nc3,BAD_CAST tmp->name,BAD_CAST tmp->value);
@@ -2033,7 +2286,8 @@
 	  }
 	}
+
 	if(vid==0)
 	  xmlAddChild(nc2,nc3);
-	tmp=tmp->next;
+	tmp=tmp->next;	
       }
       if(e!=NULL && e->format!=NULL && strcasecmp(e->format,"BoundingBoxData")==0) {
@@ -2046,10 +2300,11 @@
 	}
       }
-      else {
-	if(e!=NULL)
-	  tmp=getMap(e->defaults->content,"mimeType");
+      else {		  
+		  //if (e != NULL) {
+		  if (e != NULL && e->defaults != NULL) { // knut: add extra NULL pointer check in case user omits <Default> block in config file			  
+			  tmp = getMap(e->defaults->content, "mimeType");
+		  }
 	else
-	  tmp=NULL;
-	
+	  tmp=NULL;	
 	map* tmp1=getMap(m->content,"encoding");
 	map* tmp2=getMap(m->content,"mimeType");
@@ -2106,5 +2361,5 @@
 	     strstr(tmp2->value, "json") != NULL ||            //    (will not be parsed by XML reader) 
 	     strstr(tmp2->value, "ecmascript") != NULL
-	   ) {
+	     ) {
 	    xmlAddChild((vid==0?nc3:nc2),xmlNewCDataBlock(doc,BAD_CAST tmp3->value,strlen(tmp3->value)));
 	  }   
@@ -2112,5 +2367,5 @@
 	    if (strstr(tmp2->value, "xml") != NULL ||                 // if XML-based format
 		// include for backwards compatibility,
-	      // although correct mime type is ...kml+xml:		   
+		// although correct mime type is ...kml+xml:		   
 		strstr(tmp2->value, "google-earth.kml") != NULL
 		) { 
@@ -2241,5 +2496,7 @@
   else
     exceptionCode="501 Internal Server Error";
-
+  tmp=getMapFromMaps(m,"lenv","status_code");
+  if(tmp!=NULL)
+    exceptionCode=tmp->value;
   if(m!=NULL){
     map *tmpSid=getMapFromMaps(m,"lenv","sid");
@@ -2332,8 +2589,12 @@
 
     tmp=getMapArray(s,"text",cnt);
+    if(tmp==NULL)
+      tmp=getMapArray(s,"message",cnt);
     nc1 = xmlNewNode(ns, BAD_CAST "ExceptionText");
     if(tmp!=NULL){
       xmlNodePtr txt=xmlNewText(BAD_CAST tmp->value);
       xmlAddChild(nc1,txt);
+      if(cnt==0)
+	setMapInMaps(m,"lenv","message",tmp->value);
     }
     else{
@@ -2381,10 +2642,9 @@
 void outputResponse(service* s,maps* request_inputs,maps* request_outputs,
 		    map* request_inputs1,int cpid,maps* m,int res){
-		
 #ifdef DEBUG
   dumpMaps(request_inputs);
   dumpMaps(request_outputs);
   fprintf(stderr,"printProcessResponse\n");
-#endif
+#endif  
   map* toto=getMap(request_inputs1,"RawDataOutput");
   int asRaw=0;
@@ -2396,7 +2656,18 @@
   if(tmpSess!=NULL){
     map *_tmp=getMapFromMaps(m,"lenv","cookie");
+    maps *tmps=getMaps(m,"senv");
     char* sessId=NULL;
     if(_tmp!=NULL){
       printf("Set-Cookie: %s; HttpOnly\r\n",_tmp->value);
+      map *_tmp1=getMapFromMaps(m,"senv","ecookie_length");
+      if(_tmp1!=NULL){
+	int len=atoi(_tmp1->value);
+	int cnt=0;
+	for(cnt=0;cnt<len;cnt++){
+	  map* _tmp2=getMapArray(tmps->content,"ecookie",cnt);
+	  if(_tmp2!=NULL)
+	    printf("Set-Cookie: %s; HttpOnly\r\n",_tmp2->value);
+	}
+      }
       printf("P3P: CP=\"IDC DSP COR ADM DEVi TAIi PSA PSD IVAi IVDi CONi HIS OUR IND CNT\"\r\n");
       char session_file_path[100];
@@ -2406,5 +2677,5 @@
       else
 	sprintf(session_file_path,"%s",strstr(_tmp->value,"=")+1);
-      sessId=strdup(session_file_path);
+      sessId=zStrdup(session_file_path);
     }else{
       maps* t=getMaps(m,"senv");
@@ -2412,5 +2683,5 @@
       while(p!=NULL){
 	if(strstr(p->name,"ID")!=NULL){
-	  sessId=strdup(p->value);
+	  sessId=zStrdup(p->value);
 	  break;
 	}
@@ -2435,5 +2706,4 @@
     }
   }
- 		 
   if(res==SERVICE_FAILED){
     map *lenv;
@@ -2462,5 +2732,13 @@
     return;
   }
-	
+
+  if(res!=SERVICE_SUCCEEDED){	  
+    printProcessResponse(m,request_inputs1,cpid,
+                         s, s->name,res,  // replace serviceProvider with serviceName in stored response file name
+                         request_inputs,
+                         request_outputs);
+    return;
+  }
+      
   map *tmp1=getMapFromMaps(m,"main","tmpPath");
   if(asRaw==0){
@@ -2473,4 +2751,5 @@
     map* usid=getMapFromMaps(m,"lenv","usid");
     int itn=0;
+    int error=-1;
   NESTED0:
     while(tmpI!=NULL){
@@ -2483,5 +2762,5 @@
 #endif
       map *gfile=getMap(tmpI->content,"generated_file");
-      char *file_name;
+      char *file_name=NULL;	  
       if(gfile!=NULL){
 	gfile=getMap(tmpI->content,"expected_generated_file");
@@ -2491,99 +2770,124 @@
 	readGeneratedFile(m,tmpI->content,gfile->value);
 	file_name=zStrdup((gfile->value)+strlen(tmp1->value));
-      }
-
+      }	  
       toto=getMap(tmpI->content,"asReference");
 #ifdef USE_MS
-      if(toto!=NULL && strcasecmp(toto->value,"true")==0 && testMap==NULL)
+      map* geodatatype=getMap(tmpI->content,"geodatatype");
+      if(toto!=NULL && strcasecmp(toto->value,"true")==0 &&
+	 (testMap==NULL ||
+	  strncasecmp(testMap->value,"true",4)!=0 ||
+	  (geodatatype!=NULL && strcasecmp(geodatatype->value,"other")==0) ) ) 
 #else
-      if(toto!=NULL && strcasecmp(toto->value,"true")==0)
+	if(toto!=NULL && strcasecmp(toto->value,"true")==0)
 #endif
-	{
-	  elements* in=getElements(s->outputs,tmpI->name);
-	  if(in==NULL && s->outputs->child!=NULL){
-	    in=getElements(s->outputs->child,tmpI->name);
+	  {		
+	    elements* in=getElements(s->outputs,tmpI->name);
+	    if(in==NULL && s->outputs->child!=NULL){
+	      in=getElements(s->outputs->child,tmpI->name);
+	    }
+	    char *format=NULL;
+	    if(in!=NULL && in->format!=NULL){
+	      format=in->format;
+	    }else
+	      format=(char*)"LiteralData";
+	    if(format!=NULL && strcasecmp(format,"BoundingBoxData")==0){
+	      addToMap(tmpI->content,"extension","xml");
+	      addToMap(tmpI->content,"mimeType","text/xml");
+	      addToMap(tmpI->content,"encoding","UTF-8");
+	      addToMap(tmpI->content,"schema","http://schemas.opengis.net/ows/1.1.0/owsCommon.xsd");
+	    }		
+	    char *file_path=NULL;
+	    if(gfile==NULL) {
+	      map *ext=getMap(tmpI->content,"extension");
+	      char file_ext[32];
+	    
+	      if( ext != NULL && ext->value != NULL) {
+		strncpy(file_ext, ext->value, 32);
+	      }
+	      else {
+		// Obtain default file extension (see mimetypes.h).	      
+		// If the MIME type is not recognized, txt is used as the default extension
+		map* mtype=getMap(tmpI->content,"mimeType");
+		getFileExtension(mtype != NULL ? mtype->value : NULL, file_ext, 32);
+	      }
+	      if(file_name!=NULL)
+		free(file_name);
+	      file_name=(char*)malloc((strlen(s->name)+strlen(usid->value)+strlen(file_ext)+strlen(tmpI->name)+45)*sizeof(char));
+	      sprintf(file_name,"ZOO_DATA_%s_%s_%s_%d.%s",s->name,tmpI->name,usid->value,itn,file_ext);
+	      itn++;
+	      file_path=(char*)malloc((strlen(tmp1->value)+strlen(file_name)+2)*sizeof(char));
+	      sprintf(file_path,"%s/%s",tmp1->value,file_name);
+
+	      FILE *ofile=fopen(file_path,"wb");
+	      if(ofile==NULL){
+		char tmpMsg[1024];
+		sprintf(tmpMsg,_("Unable to create the file \"%s\" for storing the %s final result."),file_name,tmpI->name);
+		errorException(m,tmpMsg,"InternalError",NULL);
+		free(file_name);
+		free(file_path);
+		return;
+	      }
+
+	      toto=getMap(tmpI->content,"value");
+	      if(toto==NULL){
+		char tmpMsg[1024];
+		sprintf(tmpMsg,_("No value found for the requested output %s."),tmpI->name);
+		errorException(m,tmpMsg,"InternalError",NULL);
+		fclose(ofile);
+		free(file_name);
+		free(file_path);
+		return;
+	      }
+	      if(strcasecmp(format,"BoundingBoxData")!=0){
+		map* size=getMap(tmpI->content,"size");
+		if(size!=NULL && toto!=NULL)
+		  fwrite(toto->value,1,(atoi(size->value))*sizeof(char),ofile);
+		else
+		  if(toto!=NULL && toto->value!=NULL)
+		    fwrite(toto->value,1,strlen(toto->value)*sizeof(char),ofile);
+	      }else{
+		printBoundingBoxDocument(m,tmpI,ofile);
+	      }
+	      fclose(ofile);
+	    }
+
+	    map *tmp2=getMapFromMaps(m,"main","tmpUrl");
+	    map *tmp3=getMapFromMaps(m,"main","serverAddress");
+	    char *file_url=NULL;
+	    if(strncasecmp(tmp2->value,"http://",7)==0 ||
+	       strncasecmp(tmp2->value,"https://",8)==0){
+	      file_url=(char*)malloc((strlen(tmp2->value)+strlen(file_name)+2)*sizeof(char));
+	      sprintf(file_url,"%s/%s",tmp2->value,file_name);
+	    }else{
+	      file_url=(char*)malloc((strlen(tmp3->value)+strlen(tmp2->value)+strlen(file_name)+3)*sizeof(char));
+	      sprintf(file_url,"%s/%s/%s",tmp3->value,tmp2->value,file_name);
+	    }
+	    addToMap(tmpI->content,"Reference",file_url);
+	    if(file_name!=NULL)
+	      free(file_name);
+	    if(file_url!=NULL)
+	      free(file_url);
+	    file_name=NULL;
 	  }
-	  char *format=NULL;
-	  if(in!=NULL && in->format!=NULL){
-	    format=in->format;
-	  }else
-	    format=(char*)"LiteralData";
-	  if(format!=NULL && strcasecmp(format,"BoundingBoxData")==0){
-	    addToMap(tmpI->content,"extension","xml");
-	    addToMap(tmpI->content,"mimeType","text/xml");
-	    addToMap(tmpI->content,"encoding","UTF-8");
-	    addToMap(tmpI->content,"schema","http://schemas.opengis.net/ows/1.1.0/owsCommon.xsd");
+#ifdef USE_MS
+	else{
+	  if(testMap!=NULL){
+	    map* nbFeatures;
+	    setMapInMaps(m,"lenv","state","out");
+	    setReferenceUrl(m,tmpI);
+	    nbFeatures=getMap(tmpI->content,"nb_features");
+	    geodatatype=getMap(tmpI->content,"geodatatype");
+	    if((nbFeatures!=NULL && atoi(nbFeatures->value)==0) ||
+	       (geodatatype!=NULL && strcasecmp(geodatatype->value,"other")==0)){
+	      error=1;
+	      res=SERVICE_FAILED;
+	    }
 	  }
-
-	  if(gfile==NULL) {
-	    map *ext=getMap(tmpI->content,"extension");
-	    char *file_path;
-	    char file_ext[32];
-
-	    if( ext != NULL && ext->value != NULL) {
-	      strncpy(file_ext, ext->value, 32);
-	    }
-	    else {
-	      // Obtain default file extension (see mimetypes.h).	      
-	      // If the MIME type is not recognized, txt is used as the default extension
-	      map* mtype=getMap(tmpI->content,"mimeType");
-	      getFileExtension(mtype != NULL ? mtype->value : NULL, file_ext, 32);
-	    }
-
-	    file_name=(char*)malloc((strlen(s->name)+strlen(usid->value)+strlen(file_ext)+strlen(tmpI->name)+45)*sizeof(char));
-	    sprintf(file_name,"%s_%s_%s_%d.%s",s->name,tmpI->name,usid->value,itn,file_ext);
-	    itn++;
-	    file_path=(char*)malloc((strlen(tmp1->value)+strlen(file_name)+2)*sizeof(char));
-	    sprintf(file_path,"%s/%s",tmp1->value,file_name);
-
-	    FILE *ofile=fopen(file_path,"wb");
-	    if(ofile==NULL){
-	      char tmpMsg[1024];
-	      sprintf(tmpMsg,_("Unable to create the file \"%s\" for storing the %s final result."),file_name,tmpI->name);
-	      errorException(m,tmpMsg,"InternalError",NULL);
-	      free(file_name);
-	      free(file_path);
-	      return;
-	    }
-	    free(file_path);
-
-	    toto=getMap(tmpI->content,"value");
-	    if(strcasecmp(format,"BoundingBoxData")!=0){
-	      map* size=getMap(tmpI->content,"size");
-	      if(size!=NULL && toto!=NULL)
-		fwrite(toto->value,1,(atoi(size->value))*sizeof(char),ofile);
-	      else
-		if(toto!=NULL && toto->value!=NULL)
-		  fwrite(toto->value,1,strlen(toto->value)*sizeof(char),ofile);
-	    }else{
-	      printBoundingBoxDocument(m,tmpI,ofile);
-	    }
-	    fclose(ofile);
-
-	  }
-
-	  map *tmp2=getMapFromMaps(m,"main","tmpUrl");
-	  map *tmp3=getMapFromMaps(m,"main","serverAddress");
-	  char *file_url;
-	  if(strncasecmp(tmp2->value,"http://",7)==0 ||
-	     strncasecmp(tmp2->value,"https://",8)==0){
-	    file_url=(char*)malloc((strlen(tmp2->value)+strlen(file_name)+2)*sizeof(char));
-	    sprintf(file_url,"%s/%s",tmp2->value,file_name);
-	  }else{
-	    file_url=(char*)malloc((strlen(tmp3->value)+strlen(tmp2->value)+strlen(file_name)+3)*sizeof(char));
-	    sprintf(file_url,"%s/%s/%s",tmp3->value,tmp2->value,file_name);
-	  }
-	  addToMap(tmpI->content,"Reference",file_url);
-	  free(file_name);
-	  free(file_url);
-	  
-	}
-#ifdef USE_MS
-      else{
-	if(testMap!=NULL){
-	  setReferenceUrl(m,tmpI);
-	}
-      }
-#endif
+	}
+#endif	
+      if(file_name!=NULL){
+	free(file_name);
+	file_name=NULL;
+      }
       tmpI=tmpI->next;
     }
@@ -2593,13 +2897,21 @@
       if(tmpI!=NULL)
 	goto NESTED0;
-    }
+    }    
 #ifdef DEBUG
     fprintf(stderr,"SERVICE : %s\n",s->name);
     dumpMaps(m);
+#endif	
+    if(error<0)
+      printProcessResponse(m,request_inputs1,cpid,
+			   s, s->name,res,  // replace serviceProvider with serviceName in stored response file name
+			   request_inputs,
+			   request_outputs);
+    else{
+      maps* tmpMaps=getMaps(m,"lenv");
+#ifdef USE_CALLBACK
+      invokeCallback(m,NULL,NULL,7,0);
 #endif
-    printProcessResponse(m,request_inputs1,cpid,
-			 s, s->name,res,  // replace serviceProvider with serviceName in stored response file name
-			 request_inputs,
-			 request_outputs);
+      printExceptionReportResponse(m,tmpMaps->content);
+    }
   }
   else{
Index: trunk/zoo-project/zoo-kernel/response_print.h
===================================================================
--- trunk/zoo-project/zoo-kernel/response_print.h	(revision 889)
+++ trunk/zoo-project/zoo-kernel/response_print.h	(revision 917)
@@ -39,4 +39,5 @@
 #include <libintl.h>
 #include <locale.h>
+
 /**
  * ZOO-Kernel internal messages translation function
@@ -63,5 +64,4 @@
 #include <sys/stat.h>
 #include <sys/types.h>
-#include "cgic.h"
 #ifndef WIN32
 #include <sys/ipc.h>
@@ -80,5 +80,6 @@
 #endif
 #ifndef WIN32
-#include <xlocale.h>
+//#include <locale.h>
+#include <locale.h> // knut: this appears to be a non-standard header file that has been removed in newer versions of glibc; it may be sufficient to include <locale.h> (see above) 
 #endif
 #include "ulinet.h"
@@ -94,4 +95,6 @@
 #include <libxml/parser.h>
 #include <libxml/xpath.h>
+
+#include "cgic.h"
 
 #ifdef __cplusplus
@@ -209,7 +212,7 @@
   xmlNodePtr printWPSHeader(xmlDocPtr,maps*,const char*,const char*,const char*,int);
   xmlNodePtr printGetCapabilitiesHeader(xmlDocPtr,maps*,const char*);
-  void printGetCapabilitiesForProcess(registry*,maps*,xmlNodePtr,service*);
-  void printDescribeProcessForProcess(registry*,maps*,xmlNodePtr,service*);
-  void printFullDescription(int,elements*,const char*,xmlNsPtr,xmlNsPtr,xmlNodePtr,int);
+  void printGetCapabilitiesForProcess(registry*,maps*,xmlDocPtr,xmlNodePtr,service*);
+  void printDescribeProcessForProcess(registry*,maps*,xmlDocPtr,xmlNodePtr,service*);
+  void printFullDescription(xmlDocPtr,int,elements*,const char*,xmlNsPtr,xmlNsPtr,xmlNodePtr,int,int,const map*);
   void printDocument(maps*,xmlDocPtr,int);
   void printDescription(xmlNodePtr,xmlNsPtr,const char*,map*,int);
@@ -220,4 +223,6 @@
   void printOutputDefinitions(xmlDocPtr,xmlNodePtr,xmlNsPtr,xmlNsPtr,elements*,maps*,const char*);
   void printStatusInfo(maps*,map*,char*);
+  void addAdditionalParameters(map*,xmlDocPtr,xmlNodePtr,xmlNsPtr,xmlNsPtr,int);
+  void addMetadata(map*,xmlDocPtr,xmlNodePtr,xmlNsPtr,xmlNsPtr,int);
 
   void outputResponse(service*,maps*,maps*,map*,int,maps*,int);
Index: trunk/zoo-project/zoo-kernel/server_internal.c
===================================================================
--- trunk/zoo-project/zoo-kernel/server_internal.c	(revision 889)
+++ trunk/zoo-project/zoo-kernel/server_internal.c	(revision 917)
@@ -26,4 +26,5 @@
 #include "service_internal.h"
 #include "response_print.h"
+//#include "service_callback.h"
 #include "mimetypes.h"
 #ifndef WIN32
@@ -366,27 +367,33 @@
  */
 void readGeneratedFile(maps* m,map* content,char* filename){
+  char rsize[1024];
   FILE * file=fopen(filename,"rb");
   if(file==NULL){
-    fprintf(stderr,"Failed to open file %s for reading purpose.\n",filename);
     setMapInMaps(m,"lenv","message","Unable to read produced file. Please try again later");
     return ;
   }
   fseek(file, 0, SEEK_END);
-  long count = ftell(file);
+  zStatStruct f_status;
+  int s=zStat(filename, &f_status);
+  sprintf(rsize,"%lld",f_status.st_size);
   rewind(file);
-  struct stat file_status; 
-  stat(filename, &file_status);
-  map* tmpMap1=getMap(content,"value");
-  if(tmpMap1==NULL){
-    addToMap(content,"value","");
-    tmpMap1=getMap(content,"value");
-  }
-  free(tmpMap1->value);
-  tmpMap1->value=(char*) malloc((count+1)*sizeof(char));  
-  fread(tmpMap1->value,1,count,file);
-  tmpMap1->value[count]=0;
-  fclose(file);
-  char rsize[1000];
-  sprintf(rsize,"%ld",count);
+  if(getMap(content,"storage")==NULL){
+    map* memUse=getMapFromMaps(m,"main","memory");
+    if(memUse==NULL || strncmp(memUse->value,"load",4)==0){
+      map* tmpMap1=getMap(content,"value");
+      if(tmpMap1==NULL){
+	addToMap(content,"value","");
+	tmpMap1=getMap(content,"value");
+      }
+      free(tmpMap1->value);
+      tmpMap1->value=(char*) malloc((f_status.st_size+1)*sizeof(char));
+      if(tmpMap1->value==NULL){
+	setMapInMaps(m,"lenv","message","Unable to allocate the memory required to read the produced file.");
+      }
+      fread(&tmpMap1->value,1,f_status.st_size,file);
+      tmpMap1->value[f_status.st_size]=0;
+    }
+  }
+  fclose(file);  
   addToMap(content,"size",rsize);
 }
@@ -423,4 +430,5 @@
 void dumpMapsValuesToFiles(maps** main_conf,maps** in){
   map* tmpPath=getMapFromMaps(*main_conf,"main","tmpPath");
+  map* tmpUrl=getMapFromMaps(*main_conf,"main","tmpUrl");
   map* tmpSid=getMapFromMaps(*main_conf,"lenv","usid");
   maps* inputs=*in;
@@ -445,7 +453,13 @@
 	  if(cSize!=NULL){
 	    length=atoi(cSize->value);
-	  }
+	  }else
+	    length=strlen(cValue->value);
 	  writeFile(val,cValue->value,length);
 	  setMapArray(cMap,"cache_file",k,val);
+	  free(val);
+	  val=(char*)malloc((strlen(tmpUrl->value)+strlen(inputs->name)+strlen(tmpSid->value)+strlen(file_ext)+16)*sizeof(char));
+	  sprintf(val,"%s/Input_%s_%s_%d.%s",tmpUrl->value,inputs->name,tmpSid->value,k,file_ext);
+	  setMapArray(cMap,"cache_url",k,val);
+	  setMapArray(cMap,"byValue",k,"true");
 	  free(val);
 	}
@@ -461,7 +475,13 @@
 	if(cSize!=NULL){
 	  length=atoi(cSize->value);
-	}
+	}else
+	  length=strlen(cValue->value);
 	writeFile(val,cValue->value,length);
 	addToMap(cMap,"cache_file",val);
+	free(val);
+	val=(char*)malloc((strlen(tmpUrl->value)+strlen(inputs->name)+strlen(tmpSid->value)+strlen(file_ext)+16)*sizeof(char));
+	sprintf(val,"%s/Input_%s_%s_%d.%s",tmpUrl->value,inputs->name,tmpSid->value,0,file_ext);
+	addToMap(cMap,"cache_url",val);
+	addToMap(cMap,"byValue",val);
 	free(val);
       }
@@ -638,4 +658,11 @@
 	}
 	if(res==NULL){
+	  map* tmpMaxO0=getMap(tmpInputs->content,"useMapserver");
+	  if(tmpMaxO0!=NULL){
+	    if(tmpMaps2->content==NULL)
+	      tmpMaps2->content=createMap("useMapserver",tmpMaxO0->value);
+	    else
+	      addToMap(tmpMaps2->content,"useMapserver",tmpMaxO0->value);
+	  }
 	  map* tmpMaxO=getMap(tmpInputs->content,"maxOccurs");
 	  if(tmpMaxO!=NULL){
@@ -701,5 +728,5 @@
       }
     }
-    else { 
+    else /*toto*/{ 
       iotype* tmpIoType=NULL;
       if(tmpMaps->content!=NULL){
@@ -711,24 +738,16 @@
 	   * content map.
 	   */
-	  map* tmpMap1=getMap(tmpInputs->content,"minOccurs");
-	  if(tmpMap1!=NULL){
-	    if(tmpMaps->content==NULL)
-	      tmpMaps->content=createMap("minOccurs",tmpMap1->value);
-	    else
-	      addToMap(tmpMaps->content,"minOccurs",tmpMap1->value);
-	  }
-	  map* tmpMaxO=getMap(tmpInputs->content,"maxOccurs");
-	  if(tmpMaxO!=NULL){
-	    if(tmpMaps->content==NULL)
-	      tmpMaps->content=createMap("maxOccurs",tmpMaxO->value);
-	    else
-	      addToMap(tmpMaps->content,"maxOccurs",tmpMaxO->value);
-	  }
-	  map* tmpMaxMB=getMap(tmpInputs->content,"maximumMegabytes");
-	  if(tmpMaxMB!=NULL){
-	    if(tmpMaps->content==NULL)
-	      tmpMaps->content=createMap("maximumMegabytes",tmpMaxMB->value);
-	    else
-	      addToMap(tmpMaps->content,"maximumMegabytes",tmpMaxMB->value);
+	  char* keys[4]={
+	    "minOccurs",
+	    "maxOccurs",
+	    "maximumMegabytes",
+	    "useMapserver"
+	  };
+	  int i=0;
+	  for(i=0;i<4;i++){
+	    map* tmpMap1=getMap(tmpInputs->content,keys[i]);
+	    if(tmpMap1!=NULL){
+	      addToMap(tmpMaps->content,keys[i],tmpMap1->value);
+	    }
 	  }
 	  /**
@@ -743,5 +762,5 @@
 	      map* tmpV=getMap(tmpI->content,"value");
 	      if(tmpV!=NULL){
-		char *tmpVS=strdup(tmpV->value);
+		char *tmpVS=zStrdup(tmpV->value);
 		map* tmp=parseBoundingBox(tmpVS);
 		free(tmpVS);
@@ -780,5 +799,5 @@
 	      map* length=getMap(tmpMaps->content,"length");
 	      int i;
-	      char *tcn=strdup(tmpContent->name);
+	      char *tcn=zStrdup(tmpContent->name);
 	      for(i=1;i<atoi(length->value);i++){
 #ifdef DEBUG
@@ -806,7 +825,8 @@
 	 */
 	if(tmpIoType!=NULL){
-	  map* tmpCheck=getMap(tmpIoType->content,"useMapServer");
-	  if(tmpCheck!=NULL){
+	  map* tmpCheck=getMap(tmpIoType->content,"useMapserver");
+	  if(tmpCheck!=NULL && strncasecmp(tmpCheck->value,"true",4)==0){
 	    // Get the default value
+	    addToMap(tmpMaps->content,"useMapserver","true");
 	    tmpIoType=getIoTypeFromElement(tmpInputs,tmpInputs->name,NULL);
 	    tmpCheck=getMap(tmpMaps->content,"mimeType");
@@ -834,9 +854,17 @@
 	addToMap(tmpMaps->content,"inRequest","true");
       elements* tmpElements=getElements(in,tmpMaps->name);
-      if(tmpElements!=NULL && tmpElements->child!=NULL){
+      if(/*tmpMaps->child!=NULL && */tmpElements!=NULL && tmpElements->child!=NULL){
 	char *res=addDefaultValues(&tmpMaps->child,tmpElements->child,m,type,err);
 	if(strlen(res)>0){
 	  return res;
 	}
+      }
+    }
+    if(tmpInputs->child!=NULL){
+      tmpInputss=tmpInputs->next;
+      tmpInputs=tmpInputs->child;
+      if(tmpMaps!=NULL){
+	out1=tmpMaps->child;
+	out1s=tmpMaps;
       }
     }
@@ -972,5 +1000,5 @@
     if(isRunning(conf,pid)>0){		
       if(strncasecmp(req,"GetResult",strlen(req))==0){
-	errorException (conf, _("The result for the requested JobID has not yet been generated. "),
+	errorException (conf, _("The result for the requested JobID has not yet been generated. The service is currently running."),
 			"ResultNotReady", pid);
 	return;
@@ -981,6 +1009,6 @@
 	  char* tmpStr=_getStatus(conf,pid);
 	  if(tmpStr!=NULL && strncmp(tmpStr,"-1",2)!=0){
-	    char *tmpStr1=strdup(tmpStr);
-	    char *tmpStr0=strdup(strstr(tmpStr,"|")+1);
+	    char *tmpStr1=zStrdup(tmpStr);
+	    char *tmpStr0=zStrdup(strstr(tmpStr,"|")+1);
 	    free(tmpStr);
 	    tmpStr1[strlen(tmpStr1)-strlen(tmpStr0)-1]='\0';
@@ -1000,9 +1028,11 @@
 	  printf("%s",result);
 	  fflush(stdout);
+	  free(sid);
 	  freeMap(&statusInfo);
 	  free(statusInfo);
+	  free(result);
 	  return;
 	}else{
-	  errorException (conf, _("The result for the requested JobID has not yet been generated. "),
+	  errorException (conf, _("The result for the requested JobID has not yet been generated. The service ends but it still needs to produce the outputs."),
 			  "ResultNotReady", pid);
 	  freeMap(&statusInfo);
@@ -1015,6 +1045,6 @@
 	  char* tmpStr=_getStatus(conf,pid);
 	  if(tmpStr!=NULL && strncmp(tmpStr,"-1",2)!=0){
-	    char *tmpStr1=strdup(tmpStr);
-	    char *tmpStr0=strdup(strstr(tmpStr,"|")+1);
+	    char *tmpStr1=zStrdup(tmpStr);
+	    char *tmpStr0=zStrdup(strstr(tmpStr,"|")+1);
 	    free(tmpStr);
 	    tmpStr1[strlen(tmpStr1)-strlen(tmpStr0)-1]='\0';
@@ -1026,4 +1056,5 @@
 	}
     }
+    free(sid);
     printStatusInfo(conf,statusInfo,req);
     freeMap(&statusInfo);
@@ -1083,5 +1114,5 @@
 	if(strstr(dp->d_name,pid)!=0){
 	  sprintf(fileName,"%s/%s",r_inputs->value,dp->d_name);
-	  if(unlink(fileName)!=0){
+	  if(zUnlink(fileName)!=0){
 	    errorException (conf, 
 			    _("The job cannot be removed, a file cannot be removed"),
@@ -1095,4 +1126,9 @@
     removeService(conf,pid);
 #endif
+    /* No need to call 7_1 when an execution is dismissed.
+      fprintf(stderr,"************************* %s %d \n\n",__FILE__,__LINE__);
+      invokeCallback(conf,NULL,NULL,7,1);
+      fprintf(stderr,"************************* %s %d \n\n",__FILE__,__LINE__);
+    */
     map* statusInfo=createMap("JobID",pid);
     addToMap(statusInfo,"Status","Dismissed");
Index: trunk/zoo-project/zoo-kernel/service.c
===================================================================
--- trunk/zoo-project/zoo-kernel/service.c	(revision 889)
+++ trunk/zoo-project/zoo-kernel/service.c	(revision 917)
@@ -2,5 +2,5 @@
  * Author : Gérald FENOY
  *
- * Copyright (c) 2015 GeoLabs SARL
+ * Copyright (c) 2015-2019 GeoLabs SARL
  *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -28,5 +28,7 @@
 #include <ctime>
 #include <chrono>
+#ifdef WIN32
 #include <process.h>
+#endif
 
 #if defined(_MSC_VER) && _MSC_VER < 1800
@@ -102,6 +104,9 @@
     fprintf(stderr," * CONTENT [%s] \n",tmp->name);
     dumpMap(tmp->content);
-    fprintf(stderr," * CHILD [%s] \n",tmp->name);
-    dumpMaps(tmp->child);
+    if(tmp->child!=NULL){
+      fprintf(stderr," * CHILD [%s] \n",tmp->name);
+      dumpMaps(tmp->child);
+      fprintf(stderr," * /CHILD [%s] \n",tmp->name);
+    }
     tmp=tmp->next;
   }
@@ -125,7 +130,7 @@
     fflush(file);
     tmp=tmp->next;
-    cnt++;
     if(limit>=0 && cnt==limit)
       tmp=NULL;
+    cnt++;
   }
   fflush(file);
@@ -144,4 +149,16 @@
   fflush(file);
   fclose(file);
+}
+
+/**
+ * Create a new iotype*
+ *
+ * @return a pointer to the allocated iotype 
+ */
+iotype* createIoType(){
+  iotype* io=(iotype*)malloc(IOTYPE_SIZE);
+  io->content=NULL;
+  io->next=NULL;
+  return io;
 }
 
@@ -179,9 +196,25 @@
  * Count number of map in a map
  *
- * @param m the maps to count
+ * @param m the map to count
  * @return number of map in a map
  */
 int count(map* m){
   map* tmp=m;
+  int c=0;
+  while(tmp!=NULL){
+    c++;
+    tmp=tmp->next;
+  }
+  return c;
+}
+
+/**
+ * Count number of maps in a maps
+ *
+ * @param m the maps to count
+ * @return number of maps in a maps
+ */
+int maps_length(maps* m){
+  maps* tmp=m;
   int c=0;
   while(tmp!=NULL){
@@ -401,26 +434,49 @@
     if(tmp->metadata!=NULL)
       free(tmp->metadata);
+    freeMap(&tmp->additional_parameters);
+    if(tmp->additional_parameters!=NULL)
+      free(tmp->additional_parameters);
     if(tmp->format!=NULL)
       free(tmp->format);
+    freeElements(&tmp->child);
     if(tmp->child!=NULL){
-      freeElements(&tmp->child);
       free(tmp->child);
     }
-    freeIOType(&tmp->defaults);
-    if(tmp->defaults!=NULL)
+    if(tmp->defaults!=NULL){
+      freeIOType(&tmp->defaults);
       free(tmp->defaults);
-    freeIOType(&tmp->supported);
+    }
     if(tmp->supported!=NULL){
+      freeIOType(&tmp->supported);
       free(tmp->supported);
     }
-    freeElements(&tmp->next);
-    if(tmp->next!=NULL)
+    if(tmp->next!=NULL){
+      freeElements(&tmp->next);
       free(tmp->next);
-  }
+    }
+  }
+}
+
+
+/**
+ * Allocate memory for a service.
+ * Require to call free after calling this function.
+ *
+ * @return the service
+ */
+service* createService(){
+  service *s1 = (service *) malloc (SERVICE_SIZE);
+  s1->name=NULL;
+  s1->content=NULL;
+  s1->metadata=NULL;
+  s1->additional_parameters=NULL;
+  s1->inputs=NULL;
+  s1->outputs=NULL;
+  return s1;
 }
 
 /**
  * Free allocated memory of a service.
- * Require to call free on e after calling this function.
+ * Require to be invoked for every createService call.
  *
  * @param s the service to free
@@ -437,4 +493,7 @@
     if(tmp->metadata!=NULL)
       free(tmp->metadata);
+    freeMap(&tmp->additional_parameters);
+    if(tmp->additional_parameters!=NULL)
+      free(tmp->additional_parameters);
     freeElements(&tmp->inputs);
     if(tmp->inputs!=NULL)
@@ -454,19 +513,19 @@
  */
 void addToMap(map* m,const char* n,const char* v){
-  if (m != NULL) { // knut: add NULL-pointer check
-    if(hasKey(m,n)==false){
-      map* _cursor=m;
-      while(_cursor->next!=NULL){
-        _cursor=_cursor->next;
-      }
-      _cursor->next=createMap(n,v);
-    }
-    else{
-      map *tmp=getMap(m,n);
-      if(tmp->value!=NULL)
-        free(tmp->value);
-      tmp->value=zStrdup(v);
-    }
-  }
+    if (m != NULL) { // knut: add NULL-pointer check
+        if (hasKey(m, n) == false) {
+            map* _cursor = m;
+            while (_cursor->next != NULL) {
+                _cursor = _cursor->next;
+            }
+            _cursor->next = createMap(n, v);
+        }
+        else {
+            map *tmp = getMap(m, n);
+            if (tmp->value != NULL)
+                free(tmp->value);
+            tmp->value = zStrdup(v);
+        }
+    }
 }
 
@@ -506,4 +565,7 @@
  */
 map* addToMapWithSize(map* m,const char* n,const char* v,int size){
+  char sin[128];
+  char sname[10]="size";
+  map *tmp;
   if(hasKey(m,n)==false){
     map* _cursor=m;
@@ -514,8 +576,7 @@
     }
   }
-  char sname[10]="size";
   if(strlen(n)>5)
     sprintf(sname,"size_%s",n+6);
-  map *tmp=getMap(m,n);
+  tmp=getMap(m,n);
   if(tmp->value!=NULL)
     free(tmp->value);
@@ -524,5 +585,4 @@
     memmove(tmp->value,v,size*sizeof(char));
   tmp->value[size]=0;
-  char sin[128];
   sprintf(sin,"%d",size);
   addToMap(m,sname,sin);
@@ -545,12 +605,8 @@
     }
     else{
-#ifdef DEBUG
-      fprintf(stderr,"_CURSOR\n");
-      dumpMap(_cursor);
-#endif
-      while(_cursor->next!=NULL)
-	_cursor=_cursor->next;
       map* tmp1=getMap(*mo,tmp->name);
       if(tmp1==NULL){
+	while(_cursor->next!=NULL)
+	  _cursor=_cursor->next;
 	_cursor->next=createMap(tmp->name,tmp->value);
       }
@@ -561,8 +617,4 @@
     _cursor=*mo;
     tmp=tmp->next;
-#ifdef DEBUG
-    fprintf(stderr,"MO\n");
-    dumpMap(*mo);
-#endif
   }
 }
@@ -678,4 +730,5 @@
   map* size=getMap(in,"size");
   map *lout=*out;
+  map *tmpVin,*tmpVout;
   if(size!=NULL && pos>0){
     char tmp[11];
@@ -683,6 +736,6 @@
     size=getMap(in,tmp);
     sprintf(tmp,"value_%d",pos);
-    map* tmpVin=getMap(in,tmp);
-    map* tmpVout=getMap(lout,tmp);
+    tmpVin=getMap(in,tmp);
+    tmpVout=getMap(lout,tmp);
     free(tmpVout->value);
     tmpVout->value=(char*)malloc((atoi(size->value)+1)*sizeof(char));
@@ -691,6 +744,6 @@
   }else{
     if(size!=NULL){
-      map* tmpVin=getMap(in,"value");
-      map* tmpVout=getMap(lout,"value");
+      tmpVin=getMap(in,"value");
+      tmpVout=getMap(lout,"value");
       free(tmpVout->value);
       tmpVout->value=(char*)malloc((atoi(size->value)+1)*sizeof(char));
@@ -712,4 +765,11 @@
   map* size=getMap(in,"size");
   map* length=getMap(in,"length");
+  map* toload=getMap(in,"to_load");
+  if(toload!=NULL && strcasecmp(toload->value,"false")==0){
+#ifdef DEBUG
+    fprintf(stderr,"NO LOAD %s %d \n",__FILE__,__LINE__);
+#endif
+    return ;
+  }
   if(length!=NULL){
     int len=atoi(length->value);
@@ -734,11 +794,11 @@
   maps* res=NULL;
   if(_cursor!=NULL){
+    map* mc=_cursor->content;
+    maps* mcs=_cursor->child;
     res=createMaps(_cursor->name);
-    map* mc=_cursor->content;
     if(mc!=NULL){
       addMapToMap(&res->content,mc);
       loadMapBinaries(&res->content,mc);
     }
-    maps* mcs=_cursor->child;
     if(mcs!=NULL){
       res->child=dupMaps(&mcs);
@@ -764,7 +824,7 @@
     }
     else{
+      maps* tmp1=getMaps(*mo,tmp->name);
       while(_cursor->next!=NULL)
 	_cursor=_cursor->next;
-      maps* tmp1=getMaps(*mo,tmp->name);
       if(tmp1==NULL){
 	_cursor->next=dupMaps(&tmp);
@@ -797,4 +857,5 @@
 map* getMapArray(map* m,const char* key,int index){
   char tmp[1024];
+  map* tmpMap;
   if(index>0)
     sprintf(tmp,"%s_%d",key,index);
@@ -804,5 +865,5 @@
   fprintf(stderr,"** KEY %s\n",tmp);
 #endif
-  map* tmpMap=getMap(m,tmp);
+  tmpMap=getMap(m,tmp);
 #ifdef DEBUG
   if(tmpMap!=NULL)
@@ -823,7 +884,8 @@
 void setMapArray(map* m,const char* key,int index,const char* value){
   char tmp[1024];
+  map* tmpSize;
   if(index>0){
+    map* len=getMap(m,"length");
     sprintf(tmp,"%s_%d",key,index);
-    map* len=getMap(m,"length");
     if((len!=NULL && atoi(len->value)<index+1) || len==NULL){
       char tmp0[5];
@@ -832,12 +894,14 @@
     }
   }
-  else
+  else{
     sprintf(tmp,"%s",key);
-  map* tmpSize=getMapArray(m,"size",index);
+    addToMap(m,"length","1");
+  }
+  tmpSize=getMapArray(m,"size",index);
   if(tmpSize!=NULL && strncasecmp(key,"value",5)==0){
+    map* ptr=getMapOrFill(&m,tmp,(char *)"");
 #ifdef DEBUG
     fprintf(stderr,"%s\n",tmpSize->value);
 #endif
-    map* ptr=getMapOrFill(&m,tmp,(char *)"");
     free(ptr->value);
     ptr->value=(char*)malloc((atoi(tmpSize->value)+1)*sizeof(char));
@@ -846,4 +910,18 @@
   else
     addToMap(m,tmp,value);
+}
+
+/**
+ * Add a key and an integer value to an existing map array.
+ *
+ * @param m the map to add the KVP
+ * @param n the key to add
+ * @param index the index of the MapArray 
+ * @param v the corresponding value to add
+ */
+void addIntToMapArray(map* m,const char* n,int index,const int v){
+  char svalue[10];
+  sprintf(svalue,"%d",v);
+  setMapArray(m,n,index,svalue);
 }
 
@@ -881,15 +959,6 @@
   maps* tmp=mi;    
   maps* _cursor=getMaps(*mo,tmp->name);
-
-  if(_cursor==NULL)
-    return -1;
-
-  map* tmpLength=getMap(_cursor->content,"length");
   char tmpLen[10];
   int len=1;
-  if(tmpLength!=NULL){
-    len=atoi(tmpLength->value);
-  }
-
   char *tmpV[14]={
     (char*)"size",
@@ -906,9 +975,19 @@
     (char*)"isCached",
     (char*)"LowerCorner",
-    (char*)"UpperCorner"    
+    (char*)"UpperCorner"
   };
+  int i=0;
+  map* tmpLength;
+  
+  if(_cursor==NULL)
+    return -1;
+
+  tmpLength=getMap(_cursor->content,"length");
+  if(tmpLength!=NULL){
+    len=atoi(tmpLength->value);
+  }
+
   sprintf(tmpLen,"%d",len+1);
   addToMap(_cursor->content,"length",tmpLen);
-  int i=0;
   for(i=0;i<14;i++){
     map* tmpVI=getMap(tmp->content,tmpV[i]);
@@ -967,4 +1046,5 @@
   res->content=NULL;
   res->metadata=NULL;
+  res->additional_parameters=NULL;  
   res->format=NULL;
   res->defaults=NULL;
@@ -981,9 +1061,10 @@
  * @return a pointer to the allocated elements
  */
-elements* createElements(char* name){
+elements* createElements(const char* name){
   elements* res=(elements*)malloc(ELEMENTS_SIZE);
   res->name=zStrdup(name);
   res->content=NULL;
   res->metadata=NULL;
+  res->additional_parameters=NULL;
   res->format=NULL;
   res->defaults=NULL;
@@ -1020,4 +1101,6 @@
   elements* tmp=e;
   while(tmp!=NULL){
+    iotype* tmpio=tmp->defaults;
+    int ioc=0;
     fprintf(stderr,"ELEMENT [%s]\n",tmp->name);
     fprintf(stderr," > CONTENT [%s]\n",tmp->name);
@@ -1025,7 +1108,7 @@
     fprintf(stderr," > METADATA [%s]\n",tmp->name);
     dumpMap(tmp->metadata);
+    fprintf(stderr," > ADDITIONAL PARAMETERS [%s]\n",tmp->name);
+    dumpMap(tmp->additional_parameters);
     fprintf(stderr," > FORMAT [%s]\n",tmp->format);
-    iotype* tmpio=tmp->defaults;
-    int ioc=0;
     while(tmpio!=NULL){
       fprintf(stderr," > DEFAULTS [%s] (%i)\n",tmp->name,ioc);
@@ -1060,8 +1143,10 @@
   int i;
   while(tmp!=NULL){
+    map* mcurs=tmp->content;
+    int ioc=0;
+    iotype* tmpio;
     for(i=0;i<2+(4*level);i++)
       fprintf(stderr," ");
     fprintf(stderr,"%s:\n",tmp->name);
-    map* mcurs=tmp->content;
     while(mcurs!=NULL){
       for(i=0;i<4+(4*level);i++)
@@ -1091,6 +1176,5 @@
 	dumpElementsAsYAML(tmp->child,level+1);
     }
-    iotype* tmpio=tmp->defaults;
-    int ioc=0;
+    tmpio=tmp->defaults;
     while(tmpio!=NULL){
       for(i=0;i<6+(4*level);i++)
@@ -1142,5 +1226,5 @@
   elements* cursor=e;
   elements* tmp=NULL;
-  if(cursor!=NULL){
+  if(cursor!=NULL && cursor->name!=NULL){
 #ifdef DEBUG
     fprintf(stderr,">> %s %i\n",__FILE__,__LINE__);
@@ -1149,17 +1233,19 @@
 #endif
     tmp=(elements*)malloc(ELEMENTS_SIZE);
-    tmp->name=zStrdup(e->name);
+    tmp->name=zStrdup(cursor->name);
     tmp->content=NULL;
-    addMapToMap(&tmp->content,e->content);
+    addMapToMap(&tmp->content,cursor->content);
     tmp->metadata=NULL;
-    addMapToMap(&tmp->metadata,e->metadata);
-    if(e->format!=NULL)
-      tmp->format=zStrdup(e->format);
+    addMapToMap(&tmp->metadata,cursor->metadata);
+    tmp->additional_parameters=NULL;
+    addMapToMap(&tmp->additional_parameters,cursor->additional_parameters);
+    if(cursor->format!=NULL)
+      tmp->format=zStrdup(cursor->format);
     else
       tmp->format=NULL;
-    if(e->defaults!=NULL){
+    if(cursor->defaults!=NULL){
       tmp->defaults=(iotype*)malloc(IOTYPE_SIZE);
       tmp->defaults->content=NULL;
-      addMapToMap(&tmp->defaults->content,e->defaults->content);
+      addMapToMap(&tmp->defaults->content,cursor->defaults->content);
       tmp->defaults->next=NULL;
 #ifdef DEBUG
@@ -1169,11 +1255,11 @@
     }else
       tmp->defaults=NULL;
-    if(e->supported!=NULL){
+    if(cursor->supported!=NULL && cursor->supported->content!=NULL){
+      iotype *tmp2=cursor->supported->next;
       tmp->supported=(iotype*)malloc(IOTYPE_SIZE);
       tmp->supported->content=NULL;
-      addMapToMap(&tmp->supported->content,e->supported->content);
+      addMapToMap(&tmp->supported->content,cursor->supported->content);
       tmp->supported->next=NULL;
-      iotype *tmp2=e->supported->next;
-      while(tmp2!=NULL){
+            while(tmp2!=NULL){
 	addMapToIoType(&tmp->supported,tmp2->content);
 #ifdef DEBUG
@@ -1190,5 +1276,8 @@
     else
       tmp->child=NULL;
-    tmp->next=dupElements(cursor->next);
+    if(cursor->next!=NULL)
+      tmp->next=dupElements(cursor->next);
+    else
+      tmp->next=NULL;
   }
   return tmp;
@@ -1205,5 +1294,5 @@
   elements* tmp=e;
   if(*m==NULL){
-    *m=dupElements(tmp);
+    (*m)=dupElements(tmp);
   }else{
     addToElements(&(*m)->next,tmp);
@@ -1237,6 +1326,10 @@
     fprintf(stderr,"CONTENT MAP\n");
     dumpMap(s->content);
-    fprintf(stderr,"CONTENT METADATA\n");
+    if(s->metadata!=NULL)
+      fprintf(stderr,"CONTENT METADATA\n");
     dumpMap(s->metadata);
+    if(s->additional_parameters!=NULL)
+      fprintf(stderr,"CONTENT AdditionalParameters\n");
+    dumpMap(s->additional_parameters);
   }
   if(s->inputs!=NULL){
@@ -1296,4 +1389,6 @@
   res->metadata=NULL;
   addMapToMap(&res->metadata,s->metadata);
+  res->additional_parameters=NULL;
+  addMapToMap(&res->additional_parameters,s->additional_parameters);
   res->inputs=dupElements(s->inputs);
   res->outputs=dupElements(s->outputs);
@@ -1309,6 +1404,6 @@
   registry* p=r;
   while(p!=NULL){
+    services* s=p->content;
     fprintf(stderr,"%s \n",p->name);
-    services* s=p->content;
     s=p->content;
     while(s!=NULL){
@@ -1509,11 +1604,12 @@
  */
 void inheritance(registry *r,service** s){
+  service* ls=*s;
+  map *profile,*level;
   if(r==NULL)
     return;
-  service* ls=*s;
-  if(ls->content==NULL)
+  if(ls==NULL || ls->content==NULL)
     return;
-  map* profile=getMap(ls->content,"extend");
-  map* level=getMap(ls->content,"level");
+  profile=getMap(ls->content,"extend");
+  level=getMap(ls->content,"level");
   if(profile!=NULL&&level!=NULL){
     service* s1;
@@ -1550,4 +1646,5 @@
   memset(tmp,0,1024*10*10);
   while(tm!=NULL){
+    map* tc=tm->content;
     if(i>=10)
       break;
@@ -1556,5 +1653,4 @@
     strcpy(tmp[i][j],tm->name);
     j++;
-    map* tc=tm->content;
     while(tc!=NULL){
       if(j>=30)
@@ -1609,10 +1705,10 @@
  * @return true if map has a value or false if value is missing/empty/NULL
  */
-bool nonempty( map* map ) {
-    return ( map != NULL && map->value != NULL && strlen(map->value) > 0 && strcmp(map->value, "NULL") != 0 );
-}
-
-/**
- * Verify that a particular map value exists in a maps 
+bool nonempty(map* map) {
+	return (map != NULL && map->value != NULL && strlen(map->value) > 0 && strcmp(map->value, "NULL") != 0);
+}
+
+/**
+ * Verify that a particular map value exists in a maps
  * data structure, and obtain that value
  *
@@ -1620,11 +1716,13 @@
  * @param node name of maps node to search
  * @param key name of map node to find
- * @param address to the map* if it exists, otherwise NULL
+ * @param kvp address to the map* if it exists, otherwise NULL
  * @return true if map has a value or false if value is missing/NULL
- */
-bool hasvalue( maps* source, const char* node, const char* key, map** kvp ) {
-    *kvp = getMapFromMaps(source, node, key);
-    return ( *kvp != NULL && (*kvp)->value != NULL && 
-             strlen((*kvp)->value) > 0 && strcmp((*kvp)->value, "NULL") != 0 );
+ *
+ * @note The map assigned to kvp is owned by the source maps
+ */
+bool hasvalue(maps* source, const char* node, const char* key, map** kvp) {
+	*kvp = getMapFromMaps(source, node, key);
+	return (*kvp != NULL && (*kvp)->value != NULL &&
+		strlen((*kvp)->value) > 0 && strcmp((*kvp)->value, "NULL") != 0);
 }
 
@@ -1633,75 +1731,75 @@
  *
  * @param conf reference to configuration maps
- * @param service name of service 
+ * @param service name of service
  * @param exc WPSException code
  * @param message exception text (default: exception text in WPS specification)
  */
-void setErrorMessage( maps*& conf, const char* service, WPSException exc, const char* message ) {
-  
-  if (message == NULL) {
-    message = WPSExceptionText[exc];
-  } 
-
-	size_t len = strlen( service ) + strlen(": ") + strlen( message ) + strlen(": ") + strlen(WPSExceptionCode[exc]) + 16;
-	char* msg = (char*) malloc( len * sizeof(char) );
+void setErrorMessage(maps*& conf, const char* service, WPSException exc, const char* message) {
+
+	if (message == NULL) {
+		message = WPSExceptionText[exc];
+	}
+
+	size_t len = strlen(service) + strlen(": ") + strlen(message) + strlen(": ") + strlen(WPSExceptionCode[exc]) + 16;
+	char* msg = (char*)malloc(len * sizeof(char));
 
 	if (msg != NULL) {
-		snprintf( msg, len*sizeof(char), "\n%s: %s: %s\n", service, message, WPSExceptionCode[exc] );
-		setMapInMaps( conf, "lenv", "message", msg );
-		free( msg );
-	}	
+		snprintf(msg, len * sizeof(char), "\n%s: %s: %s\n", service, message, WPSExceptionCode[exc]);
+		setMapInMaps(conf, "lenv", "message", msg);
+		free(msg);
+	}
 }
 
 void logMessage(const char* source, const char* function, int line, const char* file, const char* message) { //, const char* source, const char* function, int line) {
-  
-  size_t msglen = 512;
-  const char empty[] = "";
-  
-  FILE* log;
-  
-  // system time, process time [nanoseconds]   
-  unsigned long long sys_t, proc_t;
-  
-  // processor time consumed by the program:
-  clock_t t = clock();
-    
-  // system time:
-  std::chrono::system_clock::time_point now = std::chrono::system_clock::now();
-  
-  std::time_t now_t = std::chrono::system_clock::to_time_t( now );
-  std::tm* tm = localtime( &now_t );
+
+	size_t msglen = 512;
+	const char empty[] = "";
+
+	FILE* log;
+
+	// system time, process time [nanoseconds]   
+	unsigned long long sys_t, proc_t;
+
+	// processor time consumed by the program:
+	clock_t t = clock();
+
+	// system time:
+	std::chrono::system_clock::time_point now = std::chrono::system_clock::now();
+
+	std::time_t now_t = std::chrono::system_clock::to_time_t(now);
+	std::tm* tm = localtime(&now_t);
 	char* str = asctime(tm);
-  str[strlen(str)-1] = '\0'; // remove newline
-  
-  sys_t = std::chrono::duration_cast<std::chrono::nanoseconds>(now.time_since_epoch()).count();
-  //proc_t = (unsigned long long)(1.0e9*t/CLOCKS_PER_SEC);
-  proc_t = t;
-  
-  if ( message != NULL ) {
-     msglen += strlen(message);
-  }  
-  else {
-    message = empty;
-  }
-  //getLastErrorMessage(); // cgiScriptName  
-  char* text = (char*) malloc( sizeof(char)*msglen );
-  
-  snprintf( text, msglen, "pid: %d %s line %d %s() %s systime: %lld ns ticks: %lld %s\n", 
-    _getpid(), source, line, function, str, sys_t, proc_t, message ); // __FILE__ __LINE__ __func__ //
-  
-  if ( file != NULL && (log = fopen( file, "a+" )) != NULL ) {
-    fputs( text, log );
-    fclose( log );
-  }
-  else {
-    #ifdef MSG_LOG_FILE
-    if ( (log = fopen( MSG_LOG_FILE, "a+" )) != NULL ) {
-      fputs( text, log );
-      fclose( log );
-    }      
-    #endif
-  }
-  
-  if ( text != NULL ) free( text );
+	str[strlen(str) - 1] = '\0'; // remove newline
+
+	sys_t = std::chrono::duration_cast<std::chrono::nanoseconds>(now.time_since_epoch()).count();
+	//proc_t = (unsigned long long)(1.0e9*t/CLOCKS_PER_SEC);
+	proc_t = t;
+
+	if (message != NULL) {
+		msglen += strlen(message);
+	}
+	else {
+		message = empty;
+	}
+	//getLastErrorMessage(); // cgiScriptName  
+	char* text = (char*)malloc(sizeof(char)*msglen);
+
+	snprintf(text, msglen, "pid: %d %s line %d %s() %s systime: %lld ns ticks: %lld %s\n",
+		zGetpid(), source, line, function, str, sys_t, proc_t, message); // __FILE__ __LINE__ __func__ //
+
+	if (file != NULL && (log = fopen(file, "a+")) != NULL) {
+		fputs(text, log);
+		fclose(log);
+	}
+	else {
+#ifdef MSG_LOG_FILE
+		if ((log = fopen(MSG_LOG_FILE, "a+")) != NULL) {
+			fputs(text, log);
+			fclose(log);
+		}
+#endif
+	}
+
+	if (text != NULL) free(text);
 }
 
@@ -1710,23 +1808,3 @@
 // zooLog;
 // zooLogMsg(NULL, getLastErrorMessage()); 
-// zooLogMsg(log.txt, getLastErrorMessage()); 
-
-#ifdef WIN32
-#ifndef USE_MS
-char *strcasestr (char const *a, char const *b)
-  {
-    char *x = zStrdup (a);
-    char *y = zStrdup (b);
- 
-      x = _strlwr (x);
-      y = _strlwr (y);
-    char *pos = strstr (x, y);
-    char *ret = pos == NULL ? NULL : (char *) (a + (pos - x));
-      free (x);
-      free (y);
-      return ret;
-  };
-#else
-   ;
-#endif
-#endif
+// zooLogMsg("log.txt", getLastErrorMessage()); 
Index: trunk/zoo-project/zoo-kernel/service.h
===================================================================
--- trunk/zoo-project/zoo-kernel/service.h	(revision 889)
+++ trunk/zoo-project/zoo-kernel/service.h	(revision 917)
@@ -2,5 +2,5 @@
  * Author : Gérald FENOY
  *
- * Copyright (c) 2009-2015 GeoLabs SARL
+ * Copyright (c) 2009-2019 GeoLabs SARL
  *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -34,41 +34,33 @@
 #endif
 
+ // knut: add bool if necessary
+#ifndef __cplusplus
+#ifndef WIN32
+#include <stdbool.h>
+#else
+typedef int bool;
+#define false 0
+#define true 1	
+#endif
+#endif
+#ifndef __bool_true_false_are_defined
+#define __bool_true_false_are_defined 1
+#endif
+
 #ifdef WIN32
-#ifndef USE_MS
-ZOO_DLL_EXPORT char *strcasestr (char const *,char const *);
-#endif
-#endif
-
-// knut: add bool if necessary
-#ifndef __cplusplus
-  #ifndef WIN32
-    #include <stdbool.h>
-  #else
-    typedef int bool;
-    #define false 0
-    #define true 1	
-  #endif
-#endif
-#ifndef __bool_true_false_are_defined
-  #define __bool_true_false_are_defined 1
-#endif
-
-#ifdef WIN32
+#define strtok_r strtok_s
 #define strncasecmp _strnicmp
 #define strcasecmp _stricmp
-#define strtok_r strtok_s
 #if defined(_MSC_VER) && _MSC_VER < 1900
 #define snprintf _snprintf
 #endif
-/* knut: see new definition of bool above
-#if defined(_MSC_VER) && _MSC_VER < 1800
-#define false 0
-#define true 1
-#define bool int
-#endif
-*/
 #define zStrdup _strdup
 #define zMkdir _mkdir
+#define zGetpid _getpid
 #define zOpen _open
+#define zClose _close
+#define zUnlink _unlink
+#define zDup _dup
+#define zDup2 _dup2
 #define zWrite _write
 #define zSleep Sleep
@@ -80,9 +72,9 @@
 static int zGettimeofday(struct ztimeval* tp, void* tzp)
 {
-  struct _timeb theTime;	
   if (tp == 0) {
     return -1;
   }
   
+  struct _timeb theTime;
   _ftime(&theTime);
   tp->tv_sec = theTime.time;
@@ -92,4 +84,7 @@
 }
 
+#define zStatStruct struct _stati64
+#define zStat _stati64
+
 #else
 /**
@@ -106,11 +101,30 @@
 #define zOpen open
 /**
+ * The crossplatform close alias
+ */
+#define zClose close
+/**
+ * The crossplatform unlink alias
+ */
+#define zUnlink unlink
+/**
+ * The crossplatform dup alias
+ */
+#define zDup dup
+/**
+ * The crossplatform dup2 alias
+ */
+#define zDup2 dup2
+/**
  * The crossplatform write alias
  */
 #define zWrite write
+#include "unistd.h"
 /**
  * The crossplatform sleep alias
  */
-#define zSleep sleep
+static int zSleep(const long millisecond){
+  return usleep(millisecond*1000);
+}
 /**
  * The crossplatform gettimeofday alias
@@ -121,4 +135,12 @@
  */
 #define ztimeval timeval
+/**
+ * The crossplatform getpid alias
+ */
+#define zGetpid getpid
+
+#define zStatStruct struct stat64
+#define zStat stat64
+
 #endif 
 
@@ -140,5 +162,5 @@
 #ifndef WIN32
 #include <ctype.h>
-//#include <stdbool.h> // knut: see new definition of bool above
+#include <stdbool.h>
 #endif
 
@@ -167,5 +189,5 @@
  * The memory size to create an elements
  */
-#define ELEMENTS_SIZE (sizeof(char*)+(((2*sizeof(char*))+sizeof(maps*))*2)+sizeof(char*)+(((2*sizeof(char*))+sizeof(iotype*))*2)+(2*sizeof(elements*)))
+#define ELEMENTS_SIZE (sizeof(char*)+(((2*sizeof(char*))+sizeof(maps*))*3)+sizeof(char*)+((sizeof(map*) + sizeof(iotype*))*2)+(2*sizeof(elements*)))
 /**
  * The memory size to create a map
@@ -187,5 +209,5 @@
  */
 //#define SERVICE_SIZE (ELEMENTS_SIZE*2)+(MAP_SIZE*2)+sizeof(char*)
-#define SERVICE_SIZE sizeof(char*) + 2*sizeof(map*) + 2*sizeof(elements*)
+#define SERVICE_SIZE sizeof(char*) + 3*sizeof(map*) + 2*sizeof(elements*)
 /**
  * The memory size to create a services
@@ -221,4 +243,8 @@
 #ifdef WIN32
 #define NULLMAP ((map*) 0)
+// knut: see new definition above
+//#define bool int
+//#define true 1
+//#define false 0
 #else
 #define NULLMAP NULL
@@ -256,4 +282,5 @@
     struct map* content; //!< the content map
     struct map* metadata; //!< the metadata map
+    struct map* additional_parameters; //!< the additional parameters map
     char* format; //!< the format: LiteralData or ComplexData or BoundingBoxData
     struct iotype* defaults; //!< the default iotype 
@@ -270,4 +297,5 @@
     struct map* content; //!< the content map
     struct map* metadata; //!< the metadata map
+    struct map* additional_parameters; //!< the additional parameters map
     struct elements* inputs; //!< the inputs elements
     struct elements* outputs; //!< the outputs elements
@@ -290,89 +318,89 @@
     struct registry* next; //!< the next registry pointer
   } registry;
-  
+
   // knut
   enum WPSException {
-    /*
-    * StatusOK is not a WPS exception, it is added
-    * here for convenience.
-    */      
-    StatusOK,                 
-    /*
-    * See WPS 1.0 specification, Table 38 and Table 62.
-    */
-    MissingParameterValue,    
-    InvalidParameterValue,
-    NoApplicableCode,
-    NotEnoughStorage,
-    ServerBusy,
-    FileSizeExceeded,
-    StorageNotSupported,
-    VersionNegotiationFailed,
-    /*
-    * See WPS 2.0 specification, Tables 41, 46, 48, and 50.
-    */
-    NoSuchProcess,
-    NoSuchMode,
-    NoSuchInput,
-    NoSuchOutput,
-    DataNotAccessible,
-    SizeExceeded,
-    TooManyInputs,
-    TooManyOutputs,
-    NoSuchFormat,
-    WrongInputData,
-    InternalServerError,
-    NoSuchJob,
-    ResultNotReady
-  }; 
-  
+	  /*
+	  * StatusOK is not a WPS exception, it is added
+	  * here for convenience.
+	  */
+	  StatusOK,
+	  /*
+	  * See WPS 1.0 specification, Table 38 and Table 62.
+	  */
+	  MissingParameterValue,
+	  InvalidParameterValue,
+	  NoApplicableCode,
+	  NotEnoughStorage,
+	  ServerBusy,
+	  FileSizeExceeded,
+	  StorageNotSupported,
+	  VersionNegotiationFailed,
+	  /*
+	  * See WPS 2.0 specification, Tables 41, 46, 48, and 50.
+	  */
+	  NoSuchProcess,
+	  NoSuchMode,
+	  NoSuchInput,
+	  NoSuchOutput,
+	  DataNotAccessible,
+	  SizeExceeded,
+	  TooManyInputs,
+	  TooManyOutputs,
+	  NoSuchFormat,
+	  WrongInputData,
+	  InternalServerError,
+	  NoSuchJob,
+	  ResultNotReady
+  };
+
   static const char* const WPSExceptionCode[] = {
-    "StatusOK",
-    "MissingParameterValue", 
-    "InvalidParameterValue",
-    "NoApplicableCode",
-    "NotEnoughStorage",
-    "ServerBusy",
-    "FileSizeExceeded",
-    "StorageNotSupported",
-    "VersionNegotiationFailed",
-    "NoSuchProcess",
-    "NoSuchMode",
-    "NoSuchInput",
-    "NoSuchOutput",
-    "DataNotAccessible",
-    "SizeExceeded",
-    "TooManyInputs",
-    "TooManyOutputs",
-    "NoSuchFormat",
-    "WrongInputData",
-    "InternalServerError",
-    "NoSuchJob",
-    "ResultNotReady"    
-  };      
+	"StatusOK",
+	"MissingParameterValue",
+	"InvalidParameterValue",
+	"NoApplicableCode",
+	"NotEnoughStorage",
+	"ServerBusy",
+	"FileSizeExceeded",
+	"StorageNotSupported",
+	"VersionNegotiationFailed",
+	"NoSuchProcess",
+	"NoSuchMode",
+	"NoSuchInput",
+	"NoSuchOutput",
+	"DataNotAccessible",
+	"SizeExceeded",
+	"TooManyInputs",
+	"TooManyOutputs",
+	"NoSuchFormat",
+	"WrongInputData",
+	"InternalServerError",
+	"NoSuchJob",
+	"ResultNotReady"
+  };
 
   static const char* const WPSExceptionText[] = {
-    "No problem detected",
-    "Operation request does not include a parameter value, and this server did not declare a default value for that parameter.", 
-    "Operation request contains an invalid parameter value.",
-    "No other exceptionCode specified by this service and server applies to this exception.",
-    "The server does not have enough space available to store the inputs and outputs associated with the request.",
-    "The server is too busy to accept and queue the request at this time.",
-    "The file size of one of the input parameters was too large for this process to handle.",
-    "Execute operation request included transmission=”reference” for one of the outputs, but storage is not offered by this server.",
-    "Service version for a ComplexData xlink:href input was not supported by the referenced server, and version negotiation failed.",
-    "One of the identifiers passed does not match with any of the processes offered by this server.",
-    "The process does not permit the desired execution mode.",
-    "One or more of the input identifiers passed does not match with any of the input identifiers of this process.",
-    "One or more of the output identifiers passed does not match with any of the input identifiers of this process.",
-    "One of the referenced input data sets was inaccessible.",
-    "The size of one of the input parameters was too large for this process to handle.",
-    "Too many input items have been specified.",
-    "Too many output items have been specified.",
-    "One or more of the input or output formats specified in the request did not match with any of the formats defined for that particular input or output.",
-    "One or more of inputs for which the service was able to retrieve the data but could not read it.",
-    "",
-    "The JobID from the request does not match any of the Jobs running on this server.",
-    "The result for the requested JobID has not yet been generated."
+	"No problem detected",
+	"Operation request does not include a parameter value, and this server did not declare a default value for that parameter.",
+	"Operation request contains an invalid parameter value.",
+	"No other exceptionCode specified by this service and server applies to this exception.",
+	"The server does not have enough space available to store the inputs and outputs associated with the request.",
+	"The server is too busy to accept and queue the request at this time.",
+	"The file size of one of the input parameters was too large for this process to handle.",
+	"Execute operation request included transmission=”reference” for one of the outputs, but storage is not offered by this server.",
+	"Service version for a ComplexData xlink:href input was not supported by the referenced server, and version negotiation failed.",
+	"One of the identifiers passed does not match with any of the processes offered by this server.",
+	"The process does not permit the desired execution mode.",
+	"One or more of the input identifiers passed does not match with any of the input identifiers of this process.",
+	"One or more of the output identifiers passed does not match with any of the input identifiers of this process.",
+	"One of the referenced input data sets was inaccessible.",
+	"The size of one of the input parameters was too large for this process to handle.",
+	"Too many input items have been specified.",
+	"Too many output items have been specified.",
+	"One or more of the input or output formats specified in the request did not match with any of the formats defined for that particular input or output.",
+	"One or more of inputs for which the service was able to retrieve the data but could not read it.",
+	"",
+	"The JobID from the request does not match any of the Jobs running on this server.",
+	"The result for the requested JobID has not yet been generated."
   };
 
@@ -392,8 +420,7 @@
   ZOO_DLL_EXPORT void freeMap(map**);
   ZOO_DLL_EXPORT void freeMaps(maps** mo);
-  
-
+  ZOO_DLL_EXPORT iotype* createIoType();
   ZOO_DLL_EXPORT elements* createEmptyElements();
-  ZOO_DLL_EXPORT elements* createElements(char*);
+  ZOO_DLL_EXPORT elements* createElements(const char*);
   ZOO_DLL_EXPORT void setElementsName(elements**,char*);
   ZOO_DLL_EXPORT bool hasElement(elements*,const char*);
@@ -402,7 +429,9 @@
   ZOO_DLL_EXPORT void freeElements(elements**);
   ZOO_DLL_EXPORT void setServiceName(service**,char*);
+  ZOO_DLL_EXPORT service* createService();
   ZOO_DLL_EXPORT void freeService(service**);
   ZOO_DLL_EXPORT void addToMap(map*,const char*,const char*);
   ZOO_DLL_EXPORT void addIntToMap(map*,const char*,const int);
+  ZOO_DLL_EXPORT void addIntToMapArray(map*,const char*,int,const int);
   ZOO_DLL_EXPORT map* addToMapWithSize(map*,const char*,const char*,int);
   ZOO_DLL_EXPORT void addMapToMap(map**,map*);
@@ -446,9 +475,11 @@
   ZOO_DLL_EXPORT bool nonempty(map* map);
   ZOO_DLL_EXPORT bool hasvalue(maps* source, const char* node, const char* key, map** kvp);
+#ifdef __cplusplus
   ZOO_DLL_EXPORT void setErrorMessage(maps*& conf, const char* service, WPSException exc, const char* message = NULL);
-  ZOO_DLL_EXPORT void logMessage(const char* source, const char* function, int line, const char* file = NULL, const char* message = NULL);  
+  ZOO_DLL_EXPORT void logMessage(const char* source, const char* function, int line, const char* file = NULL, const char* message = NULL);
+#endif
   #define zooLogMsg(file,message) logMessage(__FILE__, __func__, __LINE__, (file), (message)) 
   #define zooLog logMessage(__FILE__, __func__, __LINE__)  
-  
+
 #ifdef __cplusplus
 }
Index: trunk/zoo-project/zoo-kernel/service_callback.c
===================================================================
--- trunk/zoo-project/zoo-kernel/service_callback.c	(revision 917)
+++ trunk/zoo-project/zoo-kernel/service_callback.c	(revision 917)
@@ -0,0 +1,878 @@
+/*
+ * Author : Gérald FENOY
+ *
+ *  Copyright 2017-2019 GeoLabs SARL. All rights reserved.
+ *
+ * This work was supported by public funds received in the framework of GEOSUD,
+ * a project (ANR-10-EQPX-20) of the program "Investissements d'Avenir" managed 
+ * by the French National Research Agency
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "service_callback.h"
+#include "service_json.h"
+#include "service_internal_ms.h"
+#include "sqlapi.h"
+#include <pthread.h>
+#include <libxml/tree.h>
+#include <libxml/parser.h>
+#include <libxml/xpath.h>
+#include <libxml/xpathInternals.h>
+
+#include <libxslt/xslt.h>
+#include <libxslt/xsltInternals.h>
+#include <libxslt/transform.h>
+#include <libxslt/xsltutils.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+  /**
+   * Parameter definition to be used for sending parameters to a thread.
+   */
+  typedef struct {
+    maps *conf;      //!< the main configuration file
+    map *url;        //!< the callback url maps
+    json_object *res;//!< the JSON object to post 
+    int step;        //!< the current step [0,6]
+    int state;       //!< the current state [0,1]
+  } local_params;
+
+  /**
+   * Number of threads
+   */
+  int nbThreads=0;
+  /**
+   * Current step
+   */
+  int cStep=0;
+  /**
+   * Is there any ongoing HTTP request
+   */
+  int isOngoing=0;
+  /**
+   * Threads array
+   */
+  pthread_t* myThreads=NULL;
+  /**
+   * Steps array
+   */
+  bool steps[7][2]={
+    {false,false},
+    {false,false},
+    {false,false},
+    {false,false},
+    {false,false},
+    {false,false},
+    {false,false}
+  };
+  /**
+   * Arguments array to give to the _invokeCallback thread's function
+   */
+  local_params** local_arguments;
+  
+  /**
+   * Check if a service name is prohibited, meaning that the Kernel doesn't have
+   * to invoke the callback for this specific service.
+   *
+   * @param conf the main configuration file maps
+   * @param serviceName the serviceName
+   * @return a bool true if the service is prohibited, false in other case
+   */
+  bool isProhibited(maps* conf,const char* serviceName){
+    map* plist=getMapFromMaps(conf,"callback","prohibited");
+    if(plist!=NULL){
+      char *tmp=plist->value;
+      char *tmpS=strtok(tmp,",");
+      while(tmpS!=NULL){
+	if(strcmp(serviceName,tmpS)==0)
+	  return true;
+	tmpS=strtok(NULL,",");
+      }
+    }
+    return false;
+  }
+
+  /**
+   * Practically invoke the callback, meaning sending the HTTP POST request.
+   * 
+   * @param args local_params containing all the variables required
+   */
+  void* _invokeCallback(void* args){
+    local_params* arg=(local_params*)args;
+    HINTERNET hInternet,res1;
+    const struct tm *tm;
+    size_t len;
+    time_t now;
+    char *tmp1;
+    map *tmpStatus;
+    maps* tmpConf=createMaps("main");
+    tmpConf->content=createMap("memory","load");
+    hInternet=InternetOpen("ZooWPSClient\0",
+			   INTERNET_OPEN_TYPE_PRECONFIG,
+			   NULL,NULL, 0);
+    if(!CHECK_INET_HANDLE(hInternet)){
+      InternetCloseHandle (&hInternet);
+      return NULL;
+    }
+    char *URL=(char*)malloc((strlen(arg->url->value)+5)*sizeof(char));
+    sprintf(URL,"%s%d_%d/",arg->url->value,arg->step,arg->state);
+    const char* jsonStr=json_object_to_json_string_ext(arg->res,JSON_C_TO_STRING_PLAIN);
+    hInternet.waitingRequests[0] = zStrdup(URL);
+    free(URL);
+#ifdef CALLBACK_DEBUG
+    now = time ( NULL );
+    tm = localtime ( &now );
+    tmp1 = (char*)malloc((TIME_SIZE+1)*sizeof(char));
+    len = strftime ( tmp1, TIME_SIZE, "%Y-%m-%dT%I:%M:%SZ", tm );
+    fprintf(stderr,"************************* From thread %d %s %d: REQUEST PARAMETERS cStep %d %d\n",pthread_self(),__FILE__,__LINE__,cStep,isOngoing);
+    fprintf(stderr," * JSON: [%s] \n",jsonStr);
+    fprintf(stderr," * URL: %s/ \n\n",hInternet.waitingRequests[0]);
+    fprintf(stderr," * DATE: %s/ \n\n",tmp1);
+    fprintf(stderr,"************************* From thread %d %s %d: REQUEST PARAMETERS\n",pthread_self(),__FILE__,__LINE__);
+    free(tmp1);
+#endif
+    while( (arg->step!=7 || isOngoing>0) &&
+	   ( cStep!=arg->step || (arg->state!=0 && steps[arg->step][0]==false) )
+	   ){
+      zSleep(100);
+    }
+    isOngoing=1;
+#ifdef CALLBACK_DEBUG
+    fprintf(stderr,"************************* From thread %d %s %d: REQUEST START\n\n",pthread_self(),__FILE__,__LINE__);
+    int i=0;
+    for(i=0;i<7;i++){
+      fprintf(stderr,"%d) %d %d\n",i,steps[i][0],steps[i][1]);
+    }
+#endif
+    
+    now = time ( NULL );
+    tm = localtime ( &now );
+    
+    tmp1 = (char*)malloc((TIME_SIZE+1)*sizeof(char));
+    len = strftime ( tmp1, TIME_SIZE, "%Y-%m-%dT%I:%M:%SZ", tm );
+
+#ifdef CALLBACK_DEBUG    
+    fprintf(stderr,"************************* From thread %d %s %d: REQUEST START (%s)\n",pthread_self(),__FILE__,__LINE__,tmp1);
+    fflush(stderr);
+#endif    
+    free(tmp1);
+    res1 = InternetOpenUrl (&hInternet,
+			    hInternet.waitingRequests[0], 
+			    (char*)jsonStr, strlen(jsonStr),
+			    INTERNET_FLAG_NO_CACHE_WRITE,
+			    0,tmpConf);
+    AddHeaderEntries(&hInternet,arg->conf);
+    //curl_easy_setopt(hInternet.ihandle[hInternet.nb].handle, CURLOPT_VERBOSE, 1);x
+    processDownloads(&hInternet);
+    freeMaps(&tmpConf);
+    free(tmpConf);
+    now = time ( NULL );
+    tm = localtime ( &now );
+    tmp1 = (char*)malloc((TIME_SIZE+1)*sizeof(char));
+    len = strftime ( tmp1, TIME_SIZE, "%Y-%m-%dT%I:%M:%SZ", tm );
+    
+#ifdef CALLBACK_DEBUG    
+    fprintf(stderr,"************************* From thread %d %s %d: REQUEST END (%s)\n\n",pthread_self(),__FILE__,__LINE__,tmp1);
+#endif
+    free(tmp1);
+    char *tmp = (char *) malloc ((hInternet.ihandle[0].nDataLen + 1)
+				 * sizeof (char));
+    if (tmp == NULL)
+      {
+	setMapInMaps(arg->conf,"lenv","message",_("Unable to allocate memory"));
+	setMapInMaps(arg->conf,"lenv","code","InternalError");
+	return NULL;
+      }
+    size_t bRead;
+    InternetReadFile (hInternet.ihandle[0],
+		      (LPVOID) tmp,
+		      hInternet.
+		      ihandle[0].nDataLen,
+		      &bRead);
+    tmp[hInternet.ihandle[0].nDataLen] = 0;
+    json_object_put(arg->res);
+    InternetCloseHandle(&hInternet);
+    isOngoing=0;
+    if(cStep==0 || cStep==6 || arg->state==1)
+      cStep=arg->step+1;
+#ifdef CALLBACK_DEBUG
+    now = time ( NULL );
+    tm = localtime ( &now );
+    tmp1 = (char*)malloc((TIME_SIZE+1)*sizeof(char));
+    len = strftime ( tmp1, TIME_SIZE, "%Y-%m-%dT%I:%M:%SZ", tm );
+    fprintf(stderr,"************************* From thread %d %s %d: RESPONSE CONTENT (%s)\n",pthread_self(),__FILE__,__LINE__,tmp1);
+    for(i=0;i<7;i++){
+      fprintf(stderr,"%d) %d %d\n",i,steps[i][0],steps[i][1]);
+    }
+    fprintf(stderr,"Result: \n%s\n\n",tmp);
+    fprintf(stderr,"************************* From thread %d %s %d\n\n",pthread_self(),__FILE__,__LINE__);
+    fflush(stderr);
+    free(tmp1);
+#endif
+    steps[arg->step][arg->state]=true;
+    free(tmp);
+#ifdef CALLBACK_DEBUG
+    fprintf(stderr,"************************* From thread %d %s %d: EXIT\n\n",pthread_self(),__FILE__,__LINE__);
+    fflush(stderr);
+#endif
+    pthread_exit(NULL);
+  }
+  
+  /**
+   * Invoke the callback in case there is a [callback] section containing a url parameter
+   * 
+   * @param m the maps containing the main configuration file definitions
+   * @param inputs the inputs defined in the request (can be null if not yet initialized)
+   * @param inputs the outputs provided in the request (can be null if not yet initialized)
+   * @param step the step number, steps are defined as: 
+   *  0: Analyze creation
+   *  1: Fetching Data Inputs 
+   *  2: Uploading data inputs to cluster
+   *  3: Creating Job Script
+   *  4: Submitting Job to Cluster
+   *  5: Downloading processed output from cluster
+   *  6: Finalize
+   *  7: Dismiss or Error
+   * @param state 0 in case the step starts, 1 when it ends
+   * @return bool true in case of success, false in other cases
+   */
+  bool invokeCallback(maps* conf,maps* inputs,maps* outputs,int step,int state){
+    map* url=getMapFromMaps(conf,"callback","url");
+    if(url==NULL)
+      return false;
+      
+    maps* lenv=getMaps(conf,"lenv");
+    map* sname=getMap(lenv->content,"identifier");
+    if(sname!=NULL && isProhibited(conf,sname->value))
+      return false;
+      
+    json_object *res=json_object_new_object();
+
+    map* sid=getMapFromMaps(conf,"lenv","usid");
+    if(sid!=NULL){
+      json_object *jsStr=json_object_new_string(sid->value);
+      json_object_object_add(res,"jobid",jsStr);
+    }
+    const struct tm *tm;
+    size_t len;
+    time_t now;
+    char *tmp1;
+    map *tmpStatus;
+  
+    now = time ( NULL );
+    tm = localtime ( &now );
+
+    tmp1 = (char*)malloc((TIME_SIZE+1)*sizeof(char));
+    len = strftime ( tmp1, TIME_SIZE, "%Y-%m-%dT%H:%M:%SZ", tm );
+    json_object *jsStr0=json_object_new_string(tmp1);
+    json_object_object_add(res,"datetime",jsStr0);
+    free(tmp1);
+    
+    switch(step){
+    case 0: {
+      // Create a new analyze
+      maps* lenv=getMaps(conf,"lenv");
+      sid=getMapFromMaps(conf,"renv","xrequest");
+      if(sid!=NULL){
+	json_object *jsStr=json_object_new_string(sid->value);
+	json_object_object_add(res,"request_execute_content",jsStr);
+      }
+      sid=getMapFromMaps(conf,"lenv","identifier");
+      if(sid!=NULL){
+	json_object *jsStr=json_object_new_string(sid->value);
+	json_object_object_add(res,"process_identifier",jsStr);
+      }
+      // Save the Execute request on disk 
+      map* tmpPath=getMapFromMaps(conf,"main","tmpPath");
+      map* req=getMapFromMaps(conf,"renv","xrequest");
+      sid=getMapFromMaps(conf,"lenv","usid");
+      char* executePath=(char*)malloc((strlen(tmpPath->value)+strlen(sid->value)+14)*sizeof(char));
+      sprintf(executePath,"%s/execute_%s.xml",tmpPath->value,sid->value);
+      FILE* saveExecute=fopen(executePath,"wb");
+      fwrite(req->value,1,strlen(req->value)*sizeof(char),saveExecute);
+      fflush(saveExecute);
+      fclose(saveExecute);
+      setMapInMaps(conf,"lenv","execute_file",executePath);
+      free(executePath);
+      break;
+    }
+      
+    case 1: {
+      // Update the execute request stored on disk at step 0,0 to modify the references used.
+      if(state==1){
+	maps* curs=inputs;
+	xmlInitParser();
+	map* xmlPath=getMapFromMaps(conf,"lenv","execute_file");
+	while(curs!=NULL){
+	  map* length=getMap(curs->content,"length");
+	  map* useMS=getMap(curs->content,"useMapserver");
+	  if(length==NULL){
+	    addToMap(curs->content,"length","1");
+	    length=getMap(curs->content,"length");
+	  }
+	  int len=atoi(length->value);
+	  for(int ii=0;ii<len;ii++){
+	    if(getMapArray(curs->content,"byValue",ii)!=NULL && getMapArray(curs->content,"mimeType",ii)!=NULL && useMS!=NULL && strncasecmp(useMS->value,"true",4)==0){
+	      map* tmpMap=getMapArray(curs->content,"value",ii);
+	      char tmpStr[100];
+	      sprintf(tmpStr,"%d",strlen(tmpMap->value));
+	      setMapArray(curs->content,"size",ii,tmpStr);
+	      tmpMap=getMapArray(curs->content,"mimeType",ii);
+	      setMapArray(curs->content,"fmimeType",ii,tmpMap->value);
+	      tmpMap=getMapArray(curs->content,"cache_file",ii);
+	      setMapArray(curs->content,"generated_file",ii,tmpMap->value);
+	      setMapArray(curs->content,"storage",ii,tmpMap->value);
+	      setReferenceUrl(conf,curs);
+	      addIntToMap(curs->content,"published_id",ii+1);
+	      const char *params[7];
+	      int xmlLoadExtDtdDefaultValue;
+	      int hasFile=-1;
+	      map* xslPath=getMapFromMaps(conf,"callback","template");
+	      map* filePath=getMapArray(curs->content,"ref_wfs_link",ii);
+	      if(filePath==NULL)
+		filePath=getMap(curs->content,"ref_wcs_link");
+	      char* inputName=curs->name;
+	      if(xslPath==NULL || xmlPath==NULL || filePath==NULL)
+		break;
+	      char *tmpParam=(char*)malloc((strlen(curs->name)+11)*sizeof(char));
+	      char *tmpParam1=(char*)malloc((strlen(filePath->value)+11)*sizeof(char));
+	      char tmpParam2[16];
+	      sprintf(tmpParam2,"string(\"%d\")",ii);
+	      setMapArray(curs->content,"href",ii,filePath->value);
+	      setMapArray(curs->content,"xlink:href",ii,filePath->value);
+	      tmpMap=getMapArray(curs->content,"cache_url",ii);
+	      if(tmpMap!=NULL)
+		setMapArray(curs->content,"xlink:href",ii,tmpMap->value);
+	      else
+		setMapArray(curs->content,"xlink:href",ii,filePath->value);
+	      sprintf(tmpParam,"string(\"%s\")",curs->name);
+	      sprintf(tmpParam1,"string(\"%s\")",filePath->value);
+	      sprintf(tmpParam2,"string(\"%d\")",ii);
+	      params[0]="attr";
+	      params[1]=tmpParam;
+	      params[2]="value";
+	      params[3]=tmpParam1;//filePath->value;
+	      params[4]="cnt";
+	      params[5]=tmpParam2;
+	      params[6]=NULL;
+	      fprintf(stderr, "## XSLT PARAMETERS ATTR: %s VALUE: %s INDEX: %s\n",
+		      tmpParam,tmpParam1,tmpParam2);
+	      fflush(stderr);
+	      xmlSubstituteEntitiesDefault(1);
+	      xmlLoadExtDtdDefaultValue = 0;
+	      xsltStylesheetPtr cur = NULL;
+	      xmlDocPtr doc, res;
+	      cur = xsltParseStylesheetFile(BAD_CAST xslPath->value);
+	      doc = xmlParseFile(xmlPath->value);
+	      fflush(stderr);
+	      res = xsltApplyStylesheet(cur, doc, params);
+	      xmlChar *xmlbuff;
+	      int buffersize;
+	      xmlDocDumpFormatMemory(res, &xmlbuff, &buffersize, 1);
+	      // Store the executeRequest in file again
+	      free(tmpParam);
+	      free(tmpParam1);
+	      fprintf(stderr," # Request / XSLT: %s\n",xmlbuff);
+	      fflush(stderr);
+	      FILE* saveExecute=fopen(xmlPath->value,"wb");
+	      if(saveExecute!=NULL){
+		fwrite(xmlbuff,1,buffersize,saveExecute);
+		fflush(saveExecute);
+		fclose(saveExecute);
+	      }
+	      xmlFree(xmlbuff);
+	      xmlFreeDoc(doc);
+	      xsltFreeStylesheet(cur);
+	    }
+	  }
+	  addIntToMap(curs->content,"published_id",0);
+	  curs=curs->next;
+	}
+	xmlCleanupParser();
+	FILE* f0=fopen(xmlPath->value,"rb");
+	if(f0!=NULL){
+	  long flen;
+	  char *fcontent;
+	  fseek (f0, 0, SEEK_END);
+	  flen = ftell (f0);
+	  fseek (f0, 0, SEEK_SET);
+	  fcontent = (char *) malloc ((flen + 1) * sizeof (char));
+	  fread(fcontent,flen,1,f0);
+	  fcontent[flen]=0;
+	  fclose(f0);
+	  map *schema=getMapFromMaps(conf,"database","schema");
+	  map* sid=getMapFromMaps(conf,"lenv","usid");
+	  char *req=(char*)malloc((flen+strlen(schema->value)+strlen(sid->value)+66)*sizeof(char));
+	  sprintf(req,"UPDATE %s.services set request_execute_content=$$%s$$ WHERE uuid=$$%s$$",schema->value,fcontent,sid->value);
+#ifdef RELY_ON_DB
+	  execSql(conf,1,req);
+#endif
+	  free(fcontent);
+	  free(req);
+	}
+      }
+
+      // Fetching data inputs
+      maps* curs=inputs;
+      dumpMaps(curs);
+      char *keys[11][2]={
+	{
+	  "xlink:href",
+	  "ref_download_link"
+	},
+	{
+	  "cache_file",
+	  "cachefile"
+	},
+	{
+	  "fmimeType",
+	  "mimetype"
+	},
+	{
+	  "size",
+	  "size"
+	},
+	{
+	  "ref_wms_link",
+	  "ref_wms_link"
+	},
+	{
+	  "ref_wfs_link",
+	  "ref_wfs_link"
+	},
+	{
+	  "ref_wcs_link",
+	  "ref_wcs_link"
+	},
+	{
+	  "ref_wcs_link",
+	  "ref_wcs_link"
+	},
+	{
+	  "ref_wcs_preview_link",
+	  "ref_wcs_preview_link"
+	},
+	{
+	  "geodatatype",
+	  "datatype"
+	},
+	{
+	  "wgs84_extent",
+	  "boundingbox"
+	}	
+      };
+      json_object *res1=json_object_new_object();
+      while(curs!=NULL){
+	if(getMap(curs->content,"length")==NULL){
+	  addToMap(curs->content,"length","1");
+	}
+	map* length=getMap(curs->content,"length");
+	int len=atoi(length->value);
+	json_object *res3;
+	int hasRef=-1;
+	for(int ii=0;ii<len;ii++){
+	  map* tmpMap=getMapArray(curs->content,"cache_file",ii);
+	  sid=getMapArray(curs->content,"ref_wms_link",ii);
+	  json_object *res2=json_object_new_object();
+	  if(tmpMap!=NULL){
+	    if(sid==NULL){
+	      setMapArray(curs->content,"generated_file",ii,tmpMap->value);
+	      setMapArray(curs->content,"storage",ii,tmpMap->value);
+	    }
+	    struct stat buf;
+	    char timeStr[ 100 ] = "";
+	    if (stat(tmpMap->value, &buf)==0){
+	      strftime(timeStr, 100, "%d-%m-%Y %H:%M:%S", localtime( &buf.st_mtime));
+	      json_object *jsStr=json_object_new_string(timeStr);
+	      json_object_object_add(res2,"creation_date",jsStr);
+	    }
+	    tmpMap=getMapArray(curs->content,"fmimeType",ii);
+	    if(tmpMap!=NULL){
+	      setMapArray(curs->content,"mimeType",ii,tmpMap->value);
+	    }
+	    setReferenceUrl(conf,curs);
+	  }else{	  
+	  }
+	  addIntToMap(curs->content,"published_id",ii+1);
+	  int i=0;
+	  for(;i<11;i++){
+	    sid=getMapArray(curs->content,keys[i][0],ii);
+	    if(sid!=NULL){
+	      json_object *jsStr=json_object_new_string(sid->value);
+	      json_object_object_add(res2,keys[i][1],jsStr);
+	      if(i==0){
+		hasRef=1;
+		json_object *jsStr1=json_object_new_string(getProvenance(conf,sid->value));
+		json_object_object_add(res2,"dataOrigin",jsStr1);
+	      }
+	    }
+	  }
+	  if(len>1){
+	    if(ii==0)
+	      res3=json_object_new_array();
+	    json_object_array_add(res3,res2);
+	  }else
+	    res3=res2;
+	}
+	if(hasRef<0)
+	  json_object_put(res3);
+	else{
+	  json_object_object_add(res1,curs->name,json_object_get(res3));
+	  json_object_put(res3);
+	}
+	addIntToMap(curs->content,"published_id",0);
+	curs=curs->next;
+      }
+      json_object_object_add(res,"inputs",res1);
+      break;
+    }
+      
+    case 2: {
+      // Uploading data input to cluster
+      maps* in=getMaps(conf,"uploadQueue");
+      if(in!=NULL){
+	maps* curs=in;
+	map* length=getMapFromMaps(in,"uploadQueue","length");
+	if(length!=NULL){
+	  json_object *res1=json_object_new_object();
+	  int limit=atoi(length->value);
+	  int i=0;
+	  maps* uploadQueue=getMaps(in,"uploadQueue");
+	  map* tmp=uploadQueue->content;
+	  for(;i<limit;i++){
+	    map* tmp0=getMapArray(tmp,"input",i);
+	    map* tmp1=getMapArray(tmp,"localPath",i);
+	    map* tmp2=getMapArray(tmp,"targetPath",i);
+	    if(tmp0!=NULL && tmp1!=NULL && tmp2!=NULL){
+	      json_object *res2=json_object_new_object();
+	      json_object *jsStr=json_object_new_string(tmp1->value);
+	      json_object_object_add(res2,"local_path",jsStr);
+	      jsStr=json_object_new_string(tmp2->value);
+	      json_object_object_add(res2,"target_path",jsStr);
+	      json_object *res4=json_object_object_get(res1,tmp0->value);
+	      if(json_object_is_type(res4,json_type_null)){
+		json_object_object_add(res1,tmp0->value,res2);
+	      }else{
+		if(json_object_is_type(res4,json_type_object) && !json_object_is_type(res4, json_type_array)){
+		  json_object *res3=json_object_new_array();
+		  json_object_array_add(res3,json_object_get(res4));
+		  json_object_array_add(res3,res2);
+		  json_object_object_del(res1,tmp0->value);
+		  json_object_object_add(res1,tmp0->value,res3);
+		}else
+		  json_object_array_add(res4,res2);
+	      }
+	    }
+	  }
+	  json_object_object_add(res,"inputs",res1);
+	}
+      }
+      break;
+    }
+      
+    case 3: {
+      // Generating job script
+      sid=getMapFromMaps(conf,"lenv","local_script");
+      if(sid!=NULL){
+	json_object *jsStr=json_object_new_string(sid->value);
+	json_object_object_add(res,"script",jsStr);
+      }
+      break;
+    }
+      
+    case 4: {
+      // Submitting job to cluster
+      sid=getMapFromMaps(conf,"lenv","remote_script");
+      if(sid!=NULL){
+	json_object *jsStr=json_object_new_string(sid->value);
+	json_object_object_add(res,"script",jsStr);
+      }
+      break;
+    }
+      
+    case 5: {
+      // Downloading process outputs from cluster
+      maps* curs=outputs;
+      dumpMaps(curs);
+      char *keys[10][2]={
+	{
+	  "Reference",
+	  "ref"
+	},
+	{
+	  "generated_file",
+	  "cachefile"
+	},
+	{
+	  "mimeType",
+	  "mimetype"
+	},
+	{
+	  "size",
+	  "size"
+	},
+	{
+	  "geodatatype",
+	  "datatype"
+	},
+	{
+	  "wgs84_extent",
+	  "boundingbox"
+	},
+	{
+	  "ref_wms_link",
+	  "ref_wms_link"
+	},
+	{
+	  "ref_wcs_link",
+	  "ref_wcs_link"
+	},
+	{
+	  "ref_wcs_preview_link",
+	  "ref_wcs_preview_link"
+	},
+	{
+	  "ref_wfs_link",
+	  "ref_wfs_link"
+	}	
+      };
+      char* specifics[5][2]={
+	{
+	  "download_link",
+	  "ref_download_link"
+	},
+	{
+	  "wms_link",
+	  "ref_wms_link"
+	},
+	{
+	  "wfs_link",
+	  "ref_wfs_link"
+	},
+	{
+	  "wcs_link",
+	  "ref_wcs_link"
+	},
+	{
+	  "wcs_link",
+	  "ref_wcs_preview_link"
+	}
+      };
+      json_object *res1=json_object_new_object();
+      while(curs!=NULL){	
+	json_object *res2=json_object_new_object();
+	int i=0;
+	int hasRef=-1;
+	for(;i<10;i++){
+	  sid=getMap(curs->content,keys[i][0]);
+	  if(sid!=NULL){
+	    json_object *jsStr=json_object_new_string(sid->value);
+	    json_object_object_add(res2,keys[i][1],jsStr);
+	    if(i==0){
+	      hasRef=1;
+	      json_object_object_add(res2,"ref_download_link",jsStr);
+	    }
+	    if(i==1){
+	      struct stat buf;
+	      char timeStr[ 100 ] = "";
+	      if (stat(sid->value, &buf)==0){
+		strftime(timeStr, 100, "%d-%m-%Y %H:%M:%S", localtime( &buf.st_mtime));
+		json_object *jsStr=json_object_new_string(timeStr);
+		json_object_object_add(res2,"creation_date",jsStr);
+	      }
+	    }
+	  }
+	}
+	if(hasRef>0)
+	  json_object_object_add(res1,curs->name,res2);
+	else{
+	  maps* curs0=curs->child;
+	  int i=0;
+	  int bypass=-1;
+	  for(i=0;i<5;i++){
+	    maps* specificMaps;
+	    if((specificMaps=getMaps(curs0,specifics[i][0]))!=NULL){
+	      int hasRef0=-1;
+	      int i0=0;
+	      for(;i0<6;i0++){
+		sid=getMap(specificMaps->content,keys[i0][0]);
+		if(sid!=NULL){
+		  json_object *jsStr=json_object_new_string(sid->value);
+		  if(i0==0){
+		    json_object_object_add(res2,specifics[i][1],jsStr);
+		  }
+		  else
+		    json_object_object_add(res2,keys[i0][1],jsStr);
+		  hasRef0=1;
+		  bypass=1;
+		  if(i==1){
+		    struct stat buf;
+		    char timeStr[ 100 ] = "";
+		    if (stat(sid->value, &buf)==0){
+		      strftime(timeStr, 100, "%d-%m-%Y %H:%M:%S", localtime( &buf.st_mtime));
+		      json_object *jsStr=json_object_new_string(timeStr);
+		      json_object_object_add(res2,"creation_date",jsStr);
+		    }
+		  }
+		}
+	      }	      
+	    }
+	  }
+	  if(bypass<0)
+	    while(curs0!=NULL){
+	      json_object *res3=json_object_new_object();
+	      int i0=0;
+	      int hasRef0=-1;
+	      for(;i0<10;i0++){
+		sid=getMap(curs0->content,keys[i0][0]);
+		if(sid!=NULL){
+		  json_object *jsStr=json_object_new_string(sid->value);
+		  json_object_object_add(res3,keys[i0][1],jsStr);
+		  hasRef0=1;
+		}
+	      }
+	      if(hasRef0<0)
+		json_object_put(res3);
+	      else
+		json_object_object_add(res2,curs0->name,res3);
+	      curs0=curs0->next;
+	    }
+	  json_object_object_add(res1,curs->name,res2);
+	}
+	curs=curs->next;
+      }
+      json_object_object_add(res,"outputs",res1);
+      break;
+    }
+      
+    case 6: {
+      // Finalize HPC
+      char *keys[6][2]={
+	{
+	  //"SubmitTime",
+	  "Submit",
+	  "hpc_submission_date"
+	},
+	{
+	  "JobId",
+	  "hpc_job_identifier"
+	},
+	{
+	  "JobName",
+	  "hpc_job_name"
+	},
+	{
+	  //"StartTime",
+	  "Start",
+	  "hpc_start_date"
+	},
+	{
+	  //"EndTime",
+	  "End",
+	  "hpc_end_date"
+	},
+	{
+	  //"JobState",
+	  "State",
+	  "hpc_status"
+	}	
+      };
+      int i=0;
+      if(getMaps(conf,"henv")!=NULL){
+	for(i=0;i<6;i++){
+	  sid=getMapFromMaps(conf,"henv",keys[i][0]);
+	  if(sid!=NULL){
+	    json_object *jsStr=json_object_new_string(sid->value);
+	    json_object_object_add(res,keys[i][1],jsStr);
+	  }
+	}
+      }
+      if((sid=getMapFromMaps(conf,"henv","billing_nb_cpu"))!=NULL){
+        json_object *jsStr=json_object_new_string(sid->value);
+	json_object_object_add(res,"hpc_cpu_usage",jsStr);
+      }else{
+	json_object *jsStr=json_object_new_string("1");
+	json_object_object_add(res,"hpc_cpu_usage",jsStr);
+      }
+      json_object *jsStr=json_object_new_string("succeeded");
+      json_object_object_add(res,"wps_status",jsStr);
+      break;
+    }
+      
+    case 7: {
+      // Error or Dismiss
+      sid=getMapFromMaps(conf,"lenv","message");
+      if(sid!=NULL){
+	json_object *jsStr=json_object_new_string(sid->value);
+	json_object_object_add(res,"message",jsStr);
+      }
+      json_object *jsStr;
+      if(state==1)
+	jsStr=json_object_new_string("dismissed");
+      else
+	jsStr=json_object_new_string("failed");
+      json_object_object_add(res,"wps_status",jsStr);
+      break;
+    }
+    others: {
+	break;
+      }
+    }
+
+    if(local_arguments==NULL)
+      local_arguments=(local_params**)malloc(sizeof(local_params*));
+    else
+      local_arguments=(local_params**)realloc(local_arguments,(nbThreads+1)*sizeof(local_params*));
+    local_arguments[nbThreads]=(local_params*)malloc(MAPS_SIZE+MAP_SIZE+sizeof(json_object*)+(2*sizeof(int)));	
+    local_arguments[nbThreads]->conf=conf;
+    local_arguments[nbThreads]->url=url;
+    local_arguments[nbThreads]->res=res;
+    local_arguments[nbThreads]->step=step;
+    local_arguments[nbThreads]->state=state;
+    if(myThreads==NULL)
+      myThreads=(pthread_t*)malloc((nbThreads+1)*sizeof(pthread_t));
+    else
+      myThreads=(pthread_t*)realloc(myThreads,(nbThreads+1)*sizeof(pthread_t));
+    if(pthread_create(&myThreads[nbThreads], NULL, _invokeCallback, (void*)local_arguments[nbThreads])==-1){
+      setMapInMaps(conf,"lenv","message",_("Unable to create a new thread"));
+      return false;
+    }
+    nbThreads++;
+    return true;
+  }
+
+  /**
+   * Wait for the threads to end then, clean used memory.
+   */
+  void cleanupCallbackThreads(){
+    int i=0;
+    for(i=0;i<nbThreads;i++){
+      pthread_join(myThreads[i],NULL);
+      free(local_arguments[i]);
+    }
+    free(local_arguments);
+    free(myThreads);
+  }
+
+#ifdef __cplusplus
+}
+#endif
Index: trunk/zoo-project/zoo-kernel/service_callback.h
===================================================================
--- trunk/zoo-project/zoo-kernel/service_callback.h	(revision 917)
+++ trunk/zoo-project/zoo-kernel/service_callback.h	(revision 917)
@@ -0,0 +1,49 @@
+/*
+ * Author : Gérald FENOY
+ *
+ *  Copyright 2014 GeoLabs SARL. All rights reserved.
+ *
+ * This work was supported by public funds received in the framework of GEOSUD,
+ * a project (ANR-10-EQPX-20) of the program "Investissements d'Avenir" managed 
+ * by the French National Research Agency
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef ZOO_CALLBACK_H
+#define ZOO_CALLBACK_H 1
+
+#pragma once
+
+#include <stdio.h>
+#include <ctype.h>
+#include <service.h>
+#include <ulinet.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+  bool invokeCallback(maps*,maps*,maps*,int,int);
+  void cleanupCallbackThreads();
+  
+#ifdef __cplusplus
+}
+#endif
+#endif
Index: trunk/zoo-project/zoo-kernel/service_conf.y
===================================================================
--- trunk/zoo-project/zoo-kernel/service_conf.y	(revision 889)
+++ trunk/zoo-project/zoo-kernel/service_conf.y	(revision 917)
@@ -33,5 +33,7 @@
 static bool wait_maincontent=true;
 static bool wait_mainmetadata=false;
+static bool wait_mainap=false;
 static bool wait_metadata=false;
+static bool wait_ap=false;
 static bool wait_nested=false;
 static bool wait_inputs=false;
@@ -156,15 +158,16 @@
     current_content=NULL;
     my_service->metadata=NULL;
+    my_service->additional_parameters=NULL;
     wait_maincontent=false;
   }
   if(strncasecmp($2,"EndNested",9)==0){
 #ifdef DEBUG_SERVICE_CONF
-      fprintf(stderr,"(ENDNESTED - %d) \n",__LINE__);
-      fflush(stderr);
-#endif
-      nested_level-=1;
-      if(nested_level==0){
-	wait_nested=false;
-      }
+    fprintf(stderr,"(ENDNESTED - %d) \n",__LINE__);
+    fflush(stderr);
+#endif
+    nested_level-=1;
+    if(nested_level==0){
+      wait_nested=false;
+    }
   }
 
@@ -229,25 +232,56 @@
     }
     else
-      if(strncasecmp($2,"MetaData",8)==0){
-	previous_data=current_data;
-	current_data=3;
-	if(current_element!=NULL){
-#ifdef DEBUG_SERVICE_CONF
-	  fprintf(stderr,"add current_content to current_element->content\n");
-	  fprintf(stderr,"LINE %d",__LINE__);
-#endif
-	  addMapToMap(&current_element->content,current_content);
-	  freeMap(&current_content);
-	  free(current_content);
-	  if(previous_data==1 || previous_data==2)
-	    wait_metadata=true;
-	  else
-	    wait_mainmetadata=true;
-	}
-	else{
-	  if(previous_data==1 || previous_data==2)
-	    wait_metadata=true;
-	  else
-	    wait_mainmetadata=true;
+      if(strncasecmp($2,"MetaData",8)==0 ||
+	 strncasecmp($2,"AdditionalParameters",8)==0){
+	if(strncasecmp($2,"AdditionalParameters",8)==0){
+	  previous_data=current_data;
+	  current_data=4;
+	  if(current_element!=NULL){
+#ifdef DEBUG_SERVICE_CONF
+	    fprintf(stderr,"add current_content to current_element->content\n");
+	    fprintf(stderr,"LINE %d",__LINE__);
+#endif
+	    if(wait_mainmetadata)
+	      addMapToMap(&my_service->metadata,current_content);
+	    else
+	      if(wait_metadata)
+		addMapToMap(&current_element->metadata,current_content);
+	      else
+		addMapToMap(&current_element->content,current_content);		
+	    freeMap(&current_content);
+	    free(current_content);
+	    if(previous_data==1 || previous_data==2)
+	      wait_ap=true;
+	    else
+	      wait_mainap=true;
+	  }
+	  else{
+	    if(previous_data==1 || previous_data==2)
+	      wait_ap=true;
+	    else
+	      wait_mainap=true;
+	  }
+	}else{
+	  previous_data=current_data;
+	  current_data=3;
+	  if(current_element!=NULL){
+#ifdef DEBUG_SERVICE_CONF
+	    fprintf(stderr,"add current_content to current_element->content\n");
+	    fprintf(stderr,"LINE %d",__LINE__);
+#endif
+	    addMapToMap(&current_element->content,current_content);
+	    freeMap(&current_content);
+	    free(current_content);
+	    if(previous_data==1 || previous_data==2)
+	      wait_metadata=true;
+	    else
+	      wait_mainmetadata=true;
+	  }
+	  else{
+	    if(previous_data==1 || previous_data==2)
+	      wait_metadata=true;
+	    else
+	      wait_mainmetadata=true;
+	  }
 	}
 	current_content=NULL;
@@ -425,4 +459,31 @@
   if(strcmp($3,"DataOutputs")==0){
     current_data=2;
+  }  
+  if(strcmp($3,"AdditionalParameters")==0){
+    if(current_content!=NULL){
+#ifdef DEBUG_SERVICE_CONF
+      fprintf(stderr,"add current_content to current_element->content\n");
+      fprintf(stderr,"LINE %d",__LINE__);
+#endif
+      if(wait_ap){
+	current_element->additional_parameters=NULL;
+	addMapToMap(&current_element->additional_parameters,current_content);
+	current_element->next=NULL;
+	current_element->defaults=NULL;
+	current_element->supported=NULL;
+	current_element->child=NULL;
+      }else{
+	if(wait_mainap){
+	  addMapToMap(&my_service->additional_parameters,current_content);
+	}
+      }
+
+      freeMap(&current_content);
+      free(current_content);
+      current_content=NULL;
+    }
+    current_data=previous_data;
+    wait_mainap=false;
+    wait_ap=false;
   }
   if(strcmp($3,"MetaData")==0){
@@ -866,4 +927,6 @@
   wait_mainmetadata=false;
   wait_metadata=false;
+  wait_mainap=false;
+  wait_ap=false;
   wait_inputs=false;
   wait_defaults=false;
Index: trunk/zoo-project/zoo-kernel/service_internal.c
===================================================================
--- trunk/zoo-project/zoo-kernel/service_internal.c	(revision 889)
+++ trunk/zoo-project/zoo-kernel/service_internal.c	(revision 917)
@@ -2,5 +2,5 @@
  * Author : Gérald FENOY
  *
- * Copyright (c) 2009-2015 GeoLabs SARL
+ * Copyright (c) 2009-2018 GeoLabs SARL
  *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -31,14 +31,193 @@
 #include "service_internal.h"
 
-#ifndef TRUE
-#define TRUE 1
-#endif
-#ifndef FALSE
-#define FALSE -1
-#endif
-
+#ifdef WIN32
+// ref. https://docs.microsoft.com/en-us/windows/desktop/fileio/locking-and-unlocking-byte-ranges-in-files
+__inline int fcntl(int fd, int cmd, ...)
+{
+  va_list a;
+  va_start(a, cmd);
+  switch(cmd)
+    {
+    case F_SETLK:
+      {
+	HANDLE h = (HANDLE)_get_osfhandle(fd);
+	struct flock* l= va_arg(a, struct flock*);
+	OVERLAPPED sOverlapped;
+	sOverlapped.Offset = 0;
+	sOverlapped.OffsetHigh = 0;
+	switch(l->l_type)
+	  {
+	  case F_RDLCK:
+	    {
+	      if (!LockFileEx(h, LOCKFILE_FAIL_IMMEDIATELY, 0, l->l_len, 0, &sOverlapped)) 
+		{
+		  _set_errno(GetLastError() == ERROR_LOCK_VIOLATION ? EAGAIN : EBADF);
+		  return -1;
+		}
+	    }
+	    break;
+	  case F_WRLCK:
+	    {
+	      if (!LockFileEx(h, LOCKFILE_FAIL_IMMEDIATELY|LOCKFILE_EXCLUSIVE_LOCK, 0, l->l_len, 0, &sOverlapped))
+		{
+		  _set_errno(GetLastError() == ERROR_LOCK_VIOLATION ? EAGAIN : EBADF);
+		  return -1;
+		}
+	    }
+	    break;
+	  case F_UNLCK:
+	    {
+	      UnlockFileEx(h, 0, l->l_len, 0, &sOverlapped);
+	    }
+	    break;
+	  default:
+	    _set_errno(ENOTSUP);
+	    return -1;
+	  }
+      }
+      break;
+    default:
+      _set_errno(ENOTSUP);
+      return -1;
+    }
+  return 0;
+}
+#endif
 #define ERROR_MSG_MAX_LENGTH 1024
+
+/**
+ * Lock a file for read, write and upload.
+ * @param conf the main configuration maps
+ * @param filename the file to lock
+ * @param mode define access: 'r' for read, 'w' for write
+ * @return a new zooLock structure on sucess, NULL on failure 
+ */
+struct zooLock* lockFile(maps* conf,const char* filename,const char mode){
+  struct stat f_status;
+  int itn=0;
+  int s;
+  struct zooLock* myLock=(struct zooLock*)malloc(sizeof(struct flock)+sizeof(FILE*)+sizeof(char*));
+  int len=6;
+  char *myTemplate="%s.lock";
+  int res=-1;
+ retryLockFile:
+  myLock->filename=(char*)malloc((strlen(filename)+len)*sizeof(char));
+  sprintf(myLock->filename,myTemplate,filename);
+  s=stat(myLock->filename, &f_status);
+  if(s==0 && mode!='r'){
+    if(itn<ZOO_LOCK_MAX_RETRY){
+      itn++;
+#ifdef DEBUG
+      fprintf(stderr,"(%d) Wait for write lock on %s, tried %d times (sleep) ... \n",zGetpid(),myLock->filename,itn);
+      fflush(stderr);
+#endif
+      zSleep(5);
+      free(myLock->filename);
+      goto retryLockFile;
+    }else{
+      free(myLock->filename);
+      free(myLock);
+      return NULL;
+    }
+  }else{
+    char local_mode[3];
+    memset(local_mode,0,3);
+    if(mode=='w')
+      sprintf(local_mode,"%c+",mode);
+    else
+      sprintf(local_mode,"%c",mode);
+    myLock->lockfile=fopen(myLock->filename,local_mode);
+    char tmp[512];
+    sprintf(tmp,"%d",zGetpid());
+    if(myLock->lockfile==NULL){
+      myLock->lockfile=fopen(myLock->filename,"w+");
+      fwrite(tmp,sizeof(char),strlen(tmp),myLock->lockfile);
+      fflush(myLock->lockfile);
+      fclose(myLock->lockfile);
+      myLock->lockfile=fopen(myLock->filename,local_mode);
+    }/*else
+       fprintf(stderr,"%s %d %d\n",__FILE__,__LINE__,(myLock->lockfile==NULL));*/
+    if(mode!='r'){
+      fwrite(tmp,sizeof(char),strlen(tmp),myLock->lockfile);
+      fflush(myLock->lockfile);
+    }
+    int cnt=0;
+    if(mode=='r'){
+      myLock->lock.l_type = F_RDLCK;
+    }else
+      myLock->lock.l_type = F_WRLCK;
+    myLock->lock.l_whence = 0;
+    myLock->lock.l_start = 0;
+    myLock->lock.l_len = strlen(tmp)*sizeof(char);
+    while (true) {
+      if((res=fcntl(fileno(myLock->lockfile), F_SETLK, &(myLock->lock)))==-1 &&
+	 (errno==EAGAIN || errno==EACCES)){
+	  if(cnt >= ZOO_LOCK_MAX_RETRY){
+	    char message[51];	  
+	    sprintf(message,"Unable to get the lock after %d attempts.\n",cnt);
+	    setMapInMaps(conf,"lenv","message",message);
+	    fclose(myLock->lockfile);
+	    free(myLock->filename);
+	    free(myLock);
+	    return NULL;
+	  }
+#ifdef DEBUG
+	  fprintf(stderr,"(%d) Wait for lock on  %s, tried %d times ... \n",zGetpid(),myLock->filename,cnt);
+	  fflush(stderr);
+#endif
+	  zSleep(1);
+	  cnt++;
+	}else
+	   break;
+    }
+    if(res<0){
+      char *tmp;
+      if(errno==EBADF)
+	tmp="Either: the filedes argument is invalid; you requested a read lock but the filedes is not open for read access; or, you requested a write lock but the filedes is not open for write access.";
+      else
+	if(errno==EINVAL)
+	  tmp="Either the lockp argument doesn’t specify valid lock information, or the file associated with filedes doesn’t support locks.";
+	else
+	  tmp="The system has run out of file lock resources; there are already too many file locks in place.";
+#ifdef DEBUG
+      fprintf(stderr,"Unable to get the lock on %s due to the following error: %s\n",myLock->filename,tmp);
+#endif
+      return NULL;
+    }
+    return myLock;
+  }
+}
+
+/**
+ * Remove a lock.
+ * @param conf the main configuration maps
+ * @param s the zooLock structure
+ * @return 0 on success, -1 on failure.
+ */
+int unlockFile(maps* conf,struct zooLock* s){
+  int res=-1;
+  if(s!=NULL){
+    s->lock.l_type = F_UNLCK;
+    res=fcntl(fileno(s->lockfile), F_SETLK, &s->lock);
+    if(res==-1)
+      return res;
+    fclose(s->lockfile);
+#ifndef WIN32
+    // Check if there is any process locking a file and delete the lock if not.
+    s->lock.l_type = F_WRLCK;
+    if(fcntl(fileno(s->lockfile), F_GETLK, &s->lock)!=-1 && s->lock.l_type == F_UNLCK){
+#endif
+      zUnlink(s->filename);
+#ifndef WIN32
+    }
+#endif
+    free(s->filename);
+    free(s);
+  }
+  return res;
+}
+
 #ifndef RELY_ON_DB
-#include <dirent.h>
+#include "dirent.h"
 
 /**
@@ -148,6 +327,6 @@
 
     //FILE* f0 = fopen (fileName, "r");
-	// knut: open file in binary mode to avoid conversion of line endings (yielding extra bytes) on Windows platforms
-	FILE* f0 = fopen(fileName, "rb"); 
+    // knut: open file in binary mode to avoid conversion of line endings (yielding extra bytes) on Windows platforms
+    FILE* f0 = fopen(fileName, "rb"); 
     if(f0!=NULL){
       fseek (f0, 0, SEEK_END);
@@ -162,5 +341,4 @@
 	free(stat);
       }
-
       return tmps1;
     }
@@ -250,5 +428,5 @@
 		     * sizeof (char));
   sprintf (fbkpid, "%s/%s.status", r_inputs->value, usid->value);
-  unlink(fbkpid);
+  zUnlink(fbkpid);
   free(fbkpid);
 }
@@ -510,4 +688,5 @@
             }
         }
+	setMapInMaps(conf,"lenv","semaphore","Created");
     } else if (errno == EEXIST) { /* someone else got it first */
         int ready = 0;
@@ -529,5 +708,5 @@
 	      fprintf(stderr,"Retry to access the semaphore later ...\n");
 #endif
-	      zSleep(1);
+	      zSleep(1000);
             }
         }
@@ -540,4 +719,5 @@
 	  return -1;
         }
+	setMapInMaps(conf,"lenv","semaphore","Acquired");
     } else {
         return sem_id; /* error, check errno */
@@ -739,2 +919,29 @@
 }
 
+/**
+ * Check if file exists in specified folder
+ *
+ * @param dir the folder in which to search for file
+ * @param name the name of the file (not full path) 
+ * @return a character string with the full path [dir/name], or NULL if the file does not exist
+ *
+ * @attention Caller is responsible for applying free() to the returned pointer
+ */
+char* file_exists(const char* dir, const char* name) {
+	const char* d = (dir != NULL ? dir : ".");
+	if (name != NULL) {
+		size_t length = strlen(d) + strlen(name) + 2; // including file separator and \0 character
+		char* path = (char*)calloc(length, sizeof(char));
+		snprintf(path, length, "%s/%s", d, name);
+
+		struct stat buffer;
+		if (stat(path, &buffer) != 0) {
+			free(path);
+			path = NULL;
+		}
+		return path;
+	}
+	else {
+		return NULL;
+	}
+}
Index: trunk/zoo-project/zoo-kernel/service_internal.h
===================================================================
--- trunk/zoo-project/zoo-kernel/service_internal.h	(revision 889)
+++ trunk/zoo-project/zoo-kernel/service_internal.h	(revision 917)
@@ -63,9 +63,8 @@
  * Number of time the ZOO-Kernel will try to acquire lock
  */
-#define ZOO_LOCK_MAX_RETRY 10
+#define ZOO_LOCK_MAX_RETRY 180
 
 #include <sys/stat.h>
 #include <sys/types.h>
-#include "cgic.h"
 #ifndef WIN32
 #include <sys/ipc.h>
@@ -82,7 +81,9 @@
 #endif
 #ifndef WIN32
-#include <xlocale.h>
+#include <locale.h>
 #endif
 
+#include <fcntl.h>
+  
 #include "service.h"
 
@@ -94,11 +95,46 @@
 #endif
 
+#ifdef WIN32
+// fcntl flock definitions
+#define F_SETLK  8   // Non-Blocking set or clear a lock
+#define F_SETLKW 9   // Blocking set or clear a lock
+#define F_GETLK 10
+#define F_RDLCK  1   // read lock
+#define F_WRLCK  2   // write lock
+#define F_UNLCK  3   // remove lock
+struct flock {
+    short l_type;   // F_RDLCK, F_WRLCK, or F_UNLCK
+    short l_whence; // flag to choose starting offset, must be SEEK_SET
+    long  l_start;  // relative offset, in bytes, must be 0
+    long  l_len;    // length, in bytes; 0 means lock to EOF, must be 0
+    short l_pid;    // unused (returned with the unsupported F_GETLK)
+    short l_xxx;    // reserved for future use
+};
+#endif
+
+/**
+ * The lock structure used by the ZOO-Kernel to ensure atomicity of operations
+ *
+ */ 
+typedef struct zooLock{
+  struct flock lock; //!< The lock
+  FILE* lockfile;    //!< The pointer to the lock file
+  char* filename;    //!< The filename to lock
+} zooLock;
+
+static zooLock** zoo_file_locks=NULL;
+static int zoo_file_locks_cnt=0;
+
 #ifdef __cplusplus
 extern "C" {
 #endif
 
+  
   ZOO_DLL_EXPORT char *readVSIFile(maps*,const char*);
   ZOO_DLL_EXPORT int  setOutputValue( maps*, const char*, char*, size_t);
   ZOO_DLL_EXPORT char* getInputValue( maps*,const char*,size_t*);
+
+  ZOO_DLL_EXPORT struct zooLock* lockFile(maps*,const char*,const char);
+  ZOO_DLL_EXPORT int unlockFile(maps*,struct zooLock*);
 
   ZOO_DLL_EXPORT void unhandleStatus(maps*);
@@ -125,4 +161,6 @@
   ZOO_DLL_EXPORT int unlockShm(semid);
 
+  ZOO_DLL_EXPORT char* file_exists(const char* dir, const char* name); 
+
 #ifdef __cplusplus
 }
Index: trunk/zoo-project/zoo-kernel/service_internal_hpc.c
===================================================================
--- trunk/zoo-project/zoo-kernel/service_internal_hpc.c	(revision 917)
+++ trunk/zoo-project/zoo-kernel/service_internal_hpc.c	(revision 917)
@@ -0,0 +1,1178 @@
+/*
+ * Author : Gérald FENOY
+ *
+ * Copyright (c) 2017 GeoLabs SARL
+ *
+ * This work was supported by public funds received in the framework of GEOSUD,
+ * a project (ANR-10-EQPX-20) of the program "Investissements d'Avenir" managed 
+ * by the French National Research Agency
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ */
+
+#include "service_internal_hpc.h"
+#include "response_print.h"
+#include "server_internal.h"
+#include "service_callback.h"
+#include "mimetypes.h"
+#include <sys/un.h>
+
+typedef struct {
+  maps* conf;
+  char* local_file;
+  char* target_file;
+} local_params;
+
+/**
+ * Add nested outputs to every outputs that is geographic format 
+ * @see isGeographic
+ * @param s the service current definition
+ */ 
+void addNestedOutputs(service** s){
+  if((*s)==NULL){
+    return;
+  }    
+  if(*s==NULL || (*s)->outputs==NULL || (*s)->content==NULL){
+    return;
+  }
+  elements *out=(*s)->outputs;
+  elements* cur=out;
+  map* serviceType=getMap((*s)->content,"ServiceType");
+  if(strncmp(serviceType->value,"HPC",3)!=0)
+    return;
+  while(cur!=NULL && cur->defaults!=NULL){
+    map* mimeType=getMap(cur->defaults->content,"mimeType");
+    map* useMS=getMap(cur->defaults->content,"useMapserver");
+    if(mimeType!=NULL && useMS!=NULL && strncasecmp(useMS->value,"true",4)==0){
+      int geo=isGeographic(mimeType->value);
+      if(geo>0){
+	elements *tmp[3]={
+	  dupElements(cur),
+	  dupElements(cur),
+	  dupElements(cur)
+	};
+	char *geoLink="wcs_link";
+	if(geo==2){
+	  geoLink="wfs_link";
+	}
+	int i=0;
+	for(;i<3;i++){
+	  if(tmp[i]->next!=NULL){
+	    freeElements(&tmp[i]->next);
+	    free(tmp[i]->next);
+	    tmp[i]->next=NULL;
+	  }
+	  free(tmp[i]->name);
+	  if(tmp[i]->format!=NULL)
+	    free(tmp[i]->format);
+	  tmp[i]->format=zStrdup("ComplexData");
+	  freeMap(&tmp[i]->content);
+	  free(tmp[i]->content);
+	  tmp[i]->content=NULL;
+	  switch(i){
+	  case 0:
+	    tmp[i]->name=zStrdup("download_link");
+	    tmp[i]->content=createMap("Title",_("Download link"));
+	    addToMap(tmp[i]->content,"Abstract",_("The download link"));
+	    addToMap(tmp[i]->defaults->content,"useMapserver","false");
+	    if(tmp[i]->supported!=NULL){
+	      freeIOType(&tmp[i]->supported);
+	      free(tmp[i]->supported);
+	      tmp[i]->supported=NULL;
+	    }
+	    break;
+	  case 1:
+	    tmp[i]->name=zStrdup("wms_link");
+	    tmp[i]->content=createMap("Title",_("WMS link"));
+	    addToMap(tmp[i]->content,"Abstract",_("The WMS link"));
+	    if(tmp[i]->supported!=NULL && tmp[i]->supported->next!=NULL){
+	      freeIOType(&tmp[i]->supported->next);
+	      free(tmp[i]->supported->next);
+	      tmp[i]->supported->next=NULL;
+	    }else{
+	      if(tmp[i]->supported!=NULL)
+		addToMap(tmp[i]->supported->content,"useMapserver","true");
+	      addToMap(tmp[i]->defaults->content,"useMapserver","true");
+	    }
+	    break;
+	  case 2:
+	    if(geo==2){
+	      tmp[i]->name=zStrdup("wfs_link");
+	      tmp[i]->content=createMap("Title",_("WFS link"));
+	      addToMap(tmp[i]->content,"Abstract",_("The WFS link"));
+	    }else{
+	      tmp[i]->name=zStrdup("wcs_link");
+	      tmp[i]->content=createMap("Title",_("WCS link"));
+	      addToMap(tmp[i]->content,"Abstract",_("The WCS link"));
+	    }
+	    if(tmp[i]->supported!=NULL && tmp[i]->supported->next!=NULL &&
+	       tmp[i]->supported->next->content!=NULL){
+	      freeIOType(&tmp[i]->supported);
+	      free(tmp[i]->supported);
+	      tmp[i]->supported=NULL;
+	      tmp[i]->supported=createIoType();
+	      iotype* cnext=cur->supported->next;
+	      tmp[i]->supported->content=createMap(cnext->content->name,cnext->content->value);
+	      addMapToMap(&tmp[i]->supported->content,cnext->content->next);
+	      addToMap(tmp[i]->supported->content,"useMapserver","true");
+	    }else
+	      addToMap(tmp[i]->defaults->content,"useMapserver","true");
+	    break;
+	  }
+	}
+	addToElements(&cur->child,tmp[0]);
+	addToElements(&cur->child,tmp[1]);
+	addToElements(&cur->child,tmp[2]);
+	free(cur->format);
+	cur->format=NULL;
+	if(cur->defaults!=NULL){
+	  freeIOType(&cur->defaults);
+	  free(cur->defaults);
+	  cur->defaults=NULL;
+	}
+	if(cur->supported!=NULL){
+	  freeIOType(&cur->supported);
+	  free(cur->supported);
+	  cur->supported=NULL;
+	}
+	freeElements(&tmp[2]);
+	free(tmp[2]);
+	freeElements(&tmp[1]);
+	free(tmp[1]);
+	freeElements(&tmp[0]);
+	free(tmp[0]);
+	//addToMap(cur->content,"internal","true");
+      }      
+    }else{
+      if(mimeType!=NULL){
+        elements *tmp=dupElements(cur);
+        tmp->name=zStrdup("download_link");
+        tmp->content=createMap("Title",_("Download link"));
+        addToMap(tmp->content,"Abstract",_("The download link"));
+        addToMap(tmp->defaults->content,"useMapserver","false");
+        if(tmp->supported!=NULL){
+          freeIOType(&tmp->supported);
+          free(tmp->supported);
+          tmp->supported=NULL;
+        }
+        addToElements(&cur->child,tmp);
+        free(cur->format);
+        cur->format=NULL;
+        if(cur->defaults!=NULL){
+          freeIOType(&cur->defaults);
+          free(cur->defaults);
+          cur->defaults=NULL;
+        }
+        if(cur->supported!=NULL){
+          freeIOType(&cur->supported);
+          free(cur->supported);
+          cur->supported=NULL;
+        }
+        freeElements(&tmp);
+        free(tmp);
+      }
+    }
+    cur=cur->next;
+  }
+  //dumpElements((*s)->outputs);
+}
+
+/**
+ * Acquire a read lock on every files used as input for executing a service.
+ * @param conf the main configuration file map
+ * @return 0 if every file can be locked, -1 if one lock has failed.
+ */
+int addReadLocks(maps** conf){
+  map* queueLengthMap=getMapFromMaps(*conf,"uploadQueue","length");
+  maps* queueMaps=getMaps(*conf,"uploadQueue");
+  if(queueLengthMap!=NULL){
+    int cnt=atoi(queueLengthMap->value);
+    int i=0;
+    for(i=0;i<cnt;i++){
+      map* argv[2]={
+	getMapArray(queueMaps->content,"input",i),
+	getMapArray(queueMaps->content,"localPath",i)
+      };
+      zooLock* lck;
+      if((lck=lockFile(*conf,argv[1]->value,'r'))==NULL){
+	char* templateStr=_("Unable to lock the file for %s in read mode.");
+	char *tmpMessage=(char*)malloc((strlen(templateStr)+strlen(argv[0]->value)+1)*sizeof(char));
+	sprintf(tmpMessage,templateStr,argv[0]->value);
+	setMapInMaps(*conf,"lenv","message",tmpMessage);
+	free(tmpMessage);
+	return -1;
+      }else{
+	if(zoo_file_locks_cnt==0){
+	  zoo_file_locks=(zooLock**)malloc(sizeof(zooLock*));
+	}
+	else{
+	  zoo_file_locks=(zooLock**)realloc(zoo_file_locks,(zoo_file_locks_cnt+1)*sizeof(zooLock*));
+	}
+	zoo_file_locks[zoo_file_locks_cnt]=lck;
+	zoo_file_locks_cnt++;
+      }
+    }
+  }
+  return 0;
+}
+
+/**
+ * Remove all read locks set for files used as input for executing the service.
+ * @param conf the main configuration maps pointer
+ * @return 0 in case of success, -1 if any error occured. In case of error, one
+ * can refer to the message map array from the lenv section.
+ */
+int removeReadLocks(maps** conf){
+  int res=0;
+  int nberr=0;
+  map* queueLengthMap=getMapFromMaps(*conf,"uploadQueue","length");
+  maps* queueMaps=getMaps(*conf,"uploadQueue");
+  if(queueLengthMap!=NULL){
+    int cnt=atoi(queueLengthMap->value);
+    int i=0;
+    for(i=0;i<cnt;i++){
+      if(unlockFile(*conf,zoo_file_locks[i])<1){
+	map* argv=getMapArray(queueMaps->content,"input",i);
+	char* templateStr=_("Unable to unlock the file for %s after execution.");
+	char *tmpMessage=(char*)malloc((strlen(templateStr)+strlen(argv->value)+1)*sizeof(char));
+	sprintf(tmpMessage,templateStr,argv->value);
+	maps* lenv=getMaps(*conf,"lenv");
+	setMapArray(lenv->content,"message",nberr,tmpMessage);
+	free(tmpMessage);
+	res=-1;
+	nberr++;
+      }
+    }
+  }
+  free(zoo_file_locks);
+  return res;
+}
+
+/**
+ * Get the section name depending on number of features and/or pixels of each
+ * inputs and the threshold defined in a section.
+ * It supposes that your inputs has been published using MapServer support, 
+ * implying that the number of features (nb_features), respectively pixels 
+ * (nb_pixels), are defined. The section, identified by confId, should contain
+ * preview_max_features and preview_max_pixels defining the threshold values.
+ * @param conf the main configuration file maps pointer
+ * @param inputs the inputs maps pointer
+ * @param confId the section identifier
+ * @return "preview_conf" in case the numbers are lower than the threshold,
+ * "fullres_conf" in other cases.
+ */
+char* getConfiguration(maps** conf,maps** inputs,const char* confId){
+  maps* input=*inputs;
+  map* max_pixels=getMapFromMaps(*conf,confId,"preview_max_pixels");
+  map* max_features=getMapFromMaps(*conf,confId,"preview_max_features");
+  int i_max_pixels=atoi(max_pixels->value);
+  int i_max_features=atoi(max_features->value);
+  while(input!=NULL && input->content!=NULL){
+    map* tmpMap=getMap(input->content,"geodatatype");
+    if(tmpMap!=NULL){
+      map* currentNb;
+      if(strcasecmp(tmpMap->value,"raster")==0 ){
+	currentNb=getMap(input->content,"nb_pixels");
+	if(atoi(currentNb->value)>i_max_pixels)
+	  return "fullres_conf";
+      }else{
+	if(strcasecmp(tmpMap->value,"vector")==0 ){
+	  currentNb=getMap(input->content,"nb_features");
+	  if(atoi(currentNb->value)>i_max_features)
+	    return "fullres_conf";
+	}
+      }
+    }
+    input=input->next;
+  }
+  return "preview_conf";
+}
+
+/**
+ * Load and run a HPC Application corresponding to the service.
+ *
+ * @param main_conf the conf maps containing the main.cfg settings
+ * @param request the map containing the HTTP request
+ * @param s the service structure
+ * @param real_inputs the maps containing the inputs
+ * @param real_outputs the maps containing the outputs
+ * @return SERVICE_SUCCEEDED in case of success, -1 or SERVICE_FAILED when failing.
+ */
+int zoo_hpc_support(maps** main_conf,map* request,service* s,maps **real_inputs,maps **real_outputs){
+  maps* m=*main_conf;
+  maps* inputs=*real_inputs;
+  maps* outputs=*real_outputs;
+  map* tmp0=getMapFromMaps(*main_conf,"lenv","cwd");
+  char *ntmp=tmp0->value;
+  map* tmp=NULL;
+  int res=-1;
+  // Get the configuration id depending on service type and defined thresholds
+  // then, set the configId key in the lenv section
+  char *serviceType;
+  map* mServiceType=getMap(s->content,"confId");
+  if(mServiceType!=NULL)
+    serviceType=mServiceType->value;
+  else
+    serviceType="HPC";
+  map* tmpPath=getMapFromMaps(*main_conf,"main","tmpPath");
+  map* uuid=getMapFromMaps(*main_conf,"lenv","usid");
+  map* confMap=getMapFromMaps(*main_conf,serviceType,getConfiguration(main_conf,real_inputs,serviceType));
+  char * configurationId=confMap->value;
+  setMapInMaps(*main_conf,"lenv","configId",configurationId);
+  // Dump lenv maps again after having set the configId ...
+  char *flenv =
+    (char *)
+    malloc ((strlen (tmpPath->value) + 
+	     strlen (uuid->value) + 12) * sizeof (char));
+  sprintf (flenv, "%s/%s_lenv.cfg", tmpPath->value, uuid->value);
+  maps* lenvMaps=getMaps(m,"lenv");
+  dumpMapsToFile(lenvMaps,flenv,0);
+  free(flenv);
+
+  map* targetPathMap=getMapFromMaps(*main_conf,configurationId,"remote_data_path");
+  map* targetPersistentPathMap=getMapFromMaps(*main_conf,configurationId,"remote_persistent_data_path");
+  
+  pthread_t threads_pool[50];
+  // Force the HPC services to be called asynchronously
+  map* isAsync=getMapFromMaps(*main_conf,"lenv","async");
+  if(isAsync==NULL){
+    errorException(*main_conf,_("The synchronous mode is not supported by this type of service"),"NoSuchMode",s->name);
+    return -1;
+  }
+
+  maps* input=*real_inputs;
+  char **parameters=NULL;
+  int parameters_cnt=0;
+  while(input!=NULL && input->content!=NULL){
+    map* isInRequest=getMap(input->content,"inRequest");
+    map* minNb=getMap(input->content,"minOccurs");
+    if(getMaps(*real_outputs,input->name)==NULL &&
+       ( (isInRequest!=NULL && strncasecmp(isInRequest->value,"true",4)==0)
+	 || (minNb!=NULL && atoi(minNb->value)>0) ) ){
+      parameters_cnt+=1;
+      if(parameters_cnt==1)
+	parameters=(char**)malloc(parameters_cnt*sizeof(char*));
+      else
+	parameters=(char**)realloc(parameters,parameters_cnt*sizeof(char*));
+      if(getMap(input->content,"mimeType")!=NULL){
+	// Input is ComplexData
+	if(getMap(input->content,"cache_file")==NULL){
+	  // Input data has been passed by value
+	  // TODO: publish input through MapServer / use output publication
+	  dumpMapsValuesToFiles(main_conf,&input);
+	  addToMap(input->content,"toPublish","true");
+	  //addToMap(input->content,"useMapserver","true");
+	}
+	if(getMap(input->content,"cache_file")!=NULL){
+	  map* length=getMap(input->content,"length");
+	  if(length==NULL){
+	    addToMap(input->content,"length","1");
+	    length=getMap(input->content,"length");
+	  }
+	  int len=atoi(length->value);
+	  int i=0;
+	  for(i=0;i<len;i++){
+	    map* tmp=getMapArray(input->content,"cache_file",i);
+	    map* origin=getMapArray(input->content,"origin",i);
+	    char* targetName=strrchr(tmp->value,'/');
+	    char *targetPath;
+	    if(origin!=NULL && strcasecmp(origin->value,"SHARED")==0 && targetPersistentPathMap!=NULL){
+	      targetPath=(char*)malloc((strlen(targetPersistentPathMap->value)+strlen(targetName)+2)*sizeof(char));
+	      sprintf(targetPath,"%s/%s",targetPersistentPathMap->value,targetName);
+	    }
+	    else{
+	      targetPath=(char*)malloc((strlen(targetPathMap->value)+strlen(targetName)+2)*sizeof(char));
+	      sprintf(targetPath,"%s/%s",targetPathMap->value,targetName);
+	    }
+	    setMapArray(input->content,"targetPath",i,targetPath);
+	    setMapArray(input->content,"localPath",i,tmp->value);
+	    map* tmp1=getMapArray(input->content,"value",i);
+	    if(tmp1!=NULL){
+	      free(tmp1->value);
+	      tmp1->value=strdup("empty");
+	    }
+	    if(i==0){
+	      parameters[parameters_cnt-1]=(char*)malloc((strlen(input->name)+strlen(targetPath)+3)*sizeof(char));
+	      sprintf(parameters[parameters_cnt-1],"-%s %s",input->name,targetPath);
+	    }else{
+	      fprintf(stderr,"%s %d\n",__FILE__,__LINE__);
+	      fflush(stderr);
+	      char *tmpStr=zStrdup(parameters[parameters_cnt-1]);
+	      parameters[parameters_cnt-1]=(char*)realloc(parameters[parameters_cnt-1],(strlen(tmpStr)+strlen(targetPath)+2)*sizeof(char));
+	      sprintf(parameters[parameters_cnt-1],"%s %s",tmpStr,targetPath);
+	      free(tmpStr);
+	      fprintf(stderr,"%s %d\n",__FILE__,__LINE__);
+	      fflush(stderr);
+	    }
+	    free(targetPath);
+	  }
+	  addToUploadQueue(main_conf,input);
+	}else{
+	  // ???
+	  fprintf(stderr,"%s %d\n",__FILE__,__LINE__);
+	  fflush(stderr);
+	}
+      }else{
+	// LitteralData and BboxData 
+	if(getMap(input->content,"dataType")!=NULL){
+	  // For LitteralData, simply pass the value
+          map* length=getMap(input->content,"length");
+          if(length!=NULL){
+            char* value=NULL;
+            int len=atoi(length->value);
+            int i=0;
+            for(i=0;i<len;i++){
+              map* val=getMapArray(input->content,"value",i);
+              if(val!=NULL){
+                if(value==NULL){
+                  value=(char*)malloc((strlen(val->value)+3)*sizeof(char));
+                  sprintf(value,"\"%s\"",val->value);
+                }
+                else{
+                  value=(char*)realloc(value,(strlen(value)+strlen(val->value)+4)*sizeof(char));
+                  sprintf(value,"%s \"%s\"",value,val->value);
+                }
+              }
+            }
+            if(value!=NULL){
+              parameters[parameters_cnt-1]=(char*)malloc((strlen(input->name)+strlen(value)+3)*sizeof(char));
+              sprintf(parameters[parameters_cnt-1],"-%s %s",input->name,value);
+            }
+          }else{
+            map* val=getMap(input->content,"value");
+            parameters[parameters_cnt-1]=(char*)malloc((strlen(input->name)+strlen(val->value)+5)*sizeof(char));
+            sprintf(parameters[parameters_cnt-1],"-%s \"%s\"",input->name,val->value);
+          }
+	}
+      }
+    }
+    input=input->next;
+  }
+
+#ifdef HPC_DEBUG
+  fprintf(stderr,"************************* %s %d \n\n",__FILE__,__LINE__);
+#endif
+#ifdef USE_CALLBACK
+  invokeCallback(m,inputs,NULL,1,1);
+  invokeCallback(m,inputs,NULL,2,0);
+#endif  
+  if(getMapFromMaps(m,"lenv","mapError")!=NULL){
+#ifdef USE_CALLBACK
+    invokeCallback(*main_conf,inputs,NULL,7,0);
+#endif
+    return -1;
+  }
+#ifdef HPC_DEBUG
+  fprintf(stderr,"************************* %s %d \n\n",__FILE__,__LINE__);
+  dumpMaps(inputs);
+#endif
+
+  // Upload data on HPC
+  if(runUpload(main_conf)==false){
+    errorException (*main_conf, _("Unable to lock the file for upload!"),
+		    "InternalError", NULL);
+#ifdef HPC_DEBUG
+    fprintf(stderr,"************************* %s %d \n\n",__FILE__,__LINE__);
+#endif
+#ifdef USE_CALLBACK
+    invokeCallback(*main_conf,inputs,NULL,7,0);
+#endif
+#ifdef HPC_DEBUG
+    fprintf(stderr,"************************* %s %d \n\n",__FILE__,__LINE__);
+#endif
+    return -1;
+  }
+#ifdef HPC_DEBUG
+  fprintf(stderr,"************************* %s %d \n\n",__FILE__,__LINE__);
+#endif
+#ifdef USE_CALLBACK
+  invokeCallback(m,inputs,NULL,2,1);
+#endif
+#ifdef HPC_DEBUG
+  fprintf(stderr,"************************* %s %d \n\n",__FILE__,__LINE__);
+#endif
+
+  // Add the filename to generate for every output to parameters
+  input=*real_outputs;
+#ifdef HPC_DEBUG
+  dumpMaps(input);
+#endif
+  while(input!=NULL){
+    // Parse all outputs including inner outputs if required.
+    if(input->child==NULL){
+      // Name every files that should be produced by the service execution
+      map* mime=getMap(input->content,"mimeType");
+      char* targetName;
+      if(mime!=NULL){
+	bool hasExt=false;
+	map* fileExt=getFileExtensionMap(mime->value,&hasExt);
+	targetName=(char*)malloc((strlen(s->name)+strlen(input->name)+strlen(uuid->value)+strlen(fileExt->value)+11)*sizeof(char));
+	sprintf(targetName,"output_%s_%s_%s.%s",s->name,input->name,uuid->value,fileExt->value);
+	freeMap(&fileExt);
+	free(fileExt);
+      }else{
+	targetName=(char*)malloc((strlen(s->name)+strlen(input->name)+strlen(uuid->value)+14)*sizeof(char));
+	sprintf(targetName,"output_%s_%s_%s.tif",s->name,input->name,uuid->value);
+      }
+      char *targetPath=(char*)malloc((strlen(targetPathMap->value)+strlen(targetName)+2)*sizeof(char));
+      sprintf(targetPath,"%s/%s",targetPathMap->value,targetName);
+      map *tmpUrl=getMapFromMaps(*main_conf,"main","tmpUrl");
+      char *targetUrl=(char*)malloc((strlen(tmpUrl->value)+strlen(targetName)+2)*sizeof(char));
+      sprintf(targetUrl,"%s/%s",tmpUrl->value,targetName);
+      free(targetName);
+      setMapInMaps(*real_outputs,input->name,"generated_file",targetPath);
+      addToMap(input->content,"generated_url",targetUrl);
+      free(targetUrl);
+      {
+	parameters_cnt+=1;
+	if(parameters_cnt==1)
+	  parameters=(char**)malloc(parameters_cnt*sizeof(char*));
+	else
+	  parameters=(char**)realloc(parameters,parameters_cnt*sizeof(char*));
+	// We should verify if any optional tag for output is required
+	// (i.e. -out output.tiff *int8*), meaning that we should search
+	// for a corresponding inputs name.
+	map* inValue=getMapFromMaps(*real_inputs,input->name,"value");
+	if(inValue!=NULL){
+	  parameters[parameters_cnt-1]=(char*)malloc((strlen(input->name)+strlen(targetPath)+strlen(inValue->value)+4)*sizeof(char));
+	  sprintf(parameters[parameters_cnt-1],"-%s %s %s",input->name,targetPath,inValue->value);
+	}else{
+	  parameters[parameters_cnt-1]=(char*)malloc((strlen(input->name)+strlen(targetPath)+3)*sizeof(char));
+	  sprintf(parameters[parameters_cnt-1],"-%s %s",input->name,targetPath);
+	}
+      }
+      free(targetPath);
+    }// In other case it means we need to return the cache_file as generated_file
+    else{
+      // Name every files that should be produced by the service execution
+      map* mime=getMap(input->child->content,"mimeType");
+      char* targetName;
+      if(mime!=NULL){
+	bool hasExt=false;
+	map* fileExt=getFileExtensionMap(mime->value,&hasExt);
+	targetName=(char*)malloc((strlen(s->name)+strlen(input->name)+strlen(uuid->value)+strlen(fileExt->value)+11)*sizeof(char));
+	sprintf(targetName,"output_%s_%s_%s.%s",s->name,input->name,uuid->value,fileExt->value);
+	freeMap(&fileExt);
+	free(fileExt);
+      }else{
+	targetName=(char*)malloc((strlen(s->name)+strlen(input->name)+strlen(uuid->value)+14)*sizeof(char));
+	sprintf(targetName,"output_%s_%s_%s.tif",s->name,input->name,uuid->value);
+      }
+      char *targetPath=(char*)malloc((strlen(targetPathMap->value)+strlen(targetName)+2)*sizeof(char));
+      sprintf(targetPath,"%s/%s",targetPathMap->value,targetName);
+      map *tmpUrl=getMapFromMaps(*main_conf,"main","tmpUrl");
+      char *targetUrl=(char*)malloc((strlen(tmpUrl->value)+strlen(targetName)+2)*sizeof(char));
+      sprintf(targetUrl,"%s/%s",tmpUrl->value,targetName);
+      free(targetName);
+      addToMap(input->content,"generated_file",targetPath);
+      addToMap(input->content,"storage",targetPath);
+      addToMap(input->content,"generated_url",targetUrl);
+      free(targetUrl);
+      if(strcasecmp(input->name,"wms_link")!=0&&
+	 strcasecmp(input->name,"wcs_link")!=0 &&
+	 strcasecmp(input->name,"wfs_link")!=0){
+	parameters_cnt+=1;
+	if(parameters_cnt==1)
+	  parameters=(char**)malloc(parameters_cnt*sizeof(char*));
+	else
+	  parameters=(char**)realloc(parameters,parameters_cnt*sizeof(char*));
+	// We should verify if any optional tag for output is required
+	// (i.e. -out output.tiff *int8*), meaning that we should search
+	// for a corresponding inputs name.
+	map* inValue=getMapFromMaps(*real_inputs,input->name,"value");
+	if(inValue!=NULL){
+	  parameters[parameters_cnt-1]=(char*)malloc((strlen(input->name)+strlen(targetPath)+strlen(inValue->value)+4)*sizeof(char));
+	  sprintf(parameters[parameters_cnt-1],"-%s %s %s",input->name,targetPath,inValue->value);
+	}else{
+	  parameters[parameters_cnt-1]=(char*)malloc((strlen(input->name)+strlen(targetPath)+3)*sizeof(char));
+	  sprintf(parameters[parameters_cnt-1],"-%s %s",input->name,targetPath);
+	}
+      }
+      free(targetPath);
+    }
+    input=input->next;
+  }
+  // Produce the SBATCH File locally
+  char *scriptPath=(char*)malloc((strlen(s->name)+strlen(tmpPath->value)+strlen(uuid->value)+10)*sizeof(char));
+  sprintf(scriptPath,"%s/zoo_%s_%s.sh",tmpPath->value,s->name,uuid->value);
+  setMapInMaps(*main_conf,"lenv","local_script",scriptPath);
+#ifdef HPC_DEBUG
+  fprintf(stderr,"************************* %s %d \n\n",__FILE__,__LINE__);
+  fflush(stderr);
+#endif
+#ifdef USE_CALLBACK
+  invokeCallback(m,inputs,NULL,3,0);
+#endif
+#ifdef HPC_DEBUG
+  fprintf(stderr,"************************* %s %d \n\n",__FILE__,__LINE__);
+  fflush(stderr);
+#endif
+  FILE* scriptFile=fopen(scriptPath,"w+");
+  map* headerMap=getMapFromMaps(*main_conf,configurationId,"jobscript_header");
+  if(headerMap!=NULL){
+    // Use the header file if defined in the HPC section of the main.cfg file
+    struct stat f_status;
+    int s=stat(headerMap->value, &f_status);
+    if(s==0){
+      char* fcontent=(char*)malloc(sizeof(char)*(f_status.st_size+1));
+      FILE* f=fopen(headerMap->value,"rb");
+      fread(fcontent,f_status.st_size,1,f);
+      int fsize=f_status.st_size;
+      fcontent[fsize]=0;
+      fclose(f);
+      fprintf(scriptFile,"%s\n### --- ZOO-Service HEADER end --- ###\n\n",fcontent);
+      free(fcontent);
+    }else
+      fprintf(scriptFile,"#!/bin/bash\n\n### *** Default ZOO-Service HEADER (no header found) *** ###\n\n");
+  }else
+    fprintf(scriptFile,"#!/bin/bash\n\n### *** Default ZOO-Service HEADER *** ###\n\n");
+  maps* hpc_opts=getMaps(*main_conf,configurationId);
+  if(hpc_opts!=NULL){
+    map* hpc_opts_content=hpc_opts->content;
+    while(hpc_opts_content!=NULL){
+      if(strncasecmp(hpc_opts_content->name,"sbatch_options_",15)==0)
+	fprintf(scriptFile,"#SBATCH --%s=%s\n",strstr(hpc_opts_content->name,"sbatch_options_")+15,hpc_opts_content->value);
+      hpc_opts_content=hpc_opts_content->next;
+    }
+  }
+  fprintf(scriptFile,"#SBATCH --job-name=ZOO-Project_%s_%s\n\n",uuid->value,s->name);
+  map* mods=getMap(s->content,"hpcModules");
+  if(mods!=NULL)
+    fprintf(scriptFile,"#SBATCH --export=MODULES=%s\n",mods->value);
+
+  map* bodyMap=getMapFromMaps(*main_conf,configurationId,"jobscript_body");
+  if(bodyMap!=NULL){
+    // Use the header file if defined in the HPC section of the main.cfg file
+    struct stat f_status;
+    int s=stat(bodyMap->value, &f_status);
+    if(s==0){
+      char* fcontent=(char*)malloc(sizeof(char)*(f_status.st_size+1));
+      FILE* f=fopen(bodyMap->value,"rb");
+      fread(fcontent,f_status.st_size,1,f);
+      int fsize=f_status.st_size;
+      fcontent[fsize]=0;
+      fclose(f);
+      fprintf(scriptFile,"%s\n### --- ZOO-Service BODY end --- ###\n\n",fcontent);
+      free(fcontent);
+    }else
+      fprintf(scriptFile,"\n### *** Default ZOO-Service BODY (no body found) *** ###\n\n");
+  }else
+    fprintf(scriptFile,"\n### *** Default ZOO-Service BODY *** ###\n\n");
+
+  map* sp=getMap(s->content,"serviceProvider");
+  
+  // Require to produce the command line to be executed
+  fprintf(scriptFile,"\n\necho \"Job started at: $(date)\"\n");
+  fprintf(scriptFile,"echo \"Running service: [%s]\"\n",sp->value);
+  fprintf(scriptFile,"%s ",sp->value);
+  for(int i=0;i<parameters_cnt;i++){
+    fprintf(scriptFile," %s",parameters[i]);
+  }
+  for(int i=parameters_cnt-1;i>=0;i--){
+    free(parameters[i]);
+  }
+  free(parameters);
+  fprintf(scriptFile,"\n");
+  fprintf(scriptFile,"echo \"Job finished at: $(date)\"\n");
+  map* footerMap=getMapFromMaps(*main_conf,configurationId,"jobscript_footer");
+  if(footerMap!=NULL){
+    // Use the footer file if defined in the HPC section of the main.cfg file
+    struct stat f_status;
+    int s=stat(footerMap->value, &f_status);
+    if(s==0){
+      char* fcontent=(char*)malloc(sizeof(char)*(f_status.st_size+1));
+      FILE* f=fopen(footerMap->value,"rb");
+      fread(fcontent,f_status.st_size,1,f);
+      int fsize=f_status.st_size;
+      fcontent[fsize]=0;
+      fclose(f);
+      char* ffcontent=(char*)malloc((strlen(fcontent)+(3*strlen(uuid->value))+1)*sizeof(char));
+      sprintf(ffcontent,fcontent,uuid->value,uuid->value,uuid->value);
+      fprintf(scriptFile,"%s\n### --- ZOO-Service FOOTER end --- ###\n\n",ffcontent);
+      free(fcontent);
+    }else
+      fprintf(scriptFile,"### *** Default ZOO-Service FOOTER (footer file failed to load) *** ###\n\n");
+  }else
+      fprintf(scriptFile,"### *** Default ZOO-Service FOOTER (no footer found) *** ###\n\n");
+  fflush(scriptFile);
+  fclose(scriptFile);
+#ifdef HPC_DEBUG
+  fprintf(stderr,"************************* %s %d \n\n",__FILE__,__LINE__);
+#endif
+#ifdef USE_CALLBACK
+  invokeCallback(m,inputs,NULL,3,1);
+#endif
+#ifdef HPC_DEBUG
+  fprintf(stderr,"************************* %s %d \n\n",__FILE__,__LINE__);
+#endif
+
+  // Upload the SBATCH File to the remote host
+#ifdef HPC_DEBUG
+  fprintf(stderr,"************************* %s %d \n\n",__FILE__,__LINE__);
+#endif
+#ifdef USE_CALLBACK
+  invokeCallback(m,inputs,NULL,4,0);
+#endif
+#ifdef HPC_DEBUG
+  fprintf(stderr,"************************* %s %d \n\n",__FILE__,__LINE__);
+#endif
+  targetPathMap=getMapFromMaps(*main_conf,configurationId,"remote_work_path");
+  if(targetPathMap==NULL){
+    setMapInMaps(*main_conf,"lenv","message",_("There is no remote_work_path defined in your section!"));
+    setMapInMaps(*main_conf,"lenv","status","failed");
+    errorException (*main_conf, _("There is no remote_work_path defined in your section!"),
+		    "InternalError", NULL);
+#ifdef HPC_DEBUG
+    fprintf(stderr,"************************* %s %d \n\n",__FILE__,__LINE__);
+    fflush(stderr);
+#endif
+#ifdef USE_CALLBACK
+    invokeCallback(*main_conf,NULL,NULL,7,0);
+#endif
+#ifdef HPC_DEBUG
+    fprintf(stderr,"************************* %s %d \n\n",__FILE__,__LINE__);
+    fflush(stderr);
+#endif
+    return SERVICE_FAILED;
+  }
+  char* targetName=strrchr(scriptPath,'/');
+  char *targetPath=(char*)malloc((strlen(targetPathMap->value)+strlen(targetName)+2)*sizeof(char));
+  sprintf(targetPath,"%s/%s",targetPathMap->value,targetName);
+  setMapInMaps(*main_conf,"lenv","remote_script",targetPath);
+  SSHCON *test=ssh_connect(*main_conf);
+  int copy0=ssh_copy(*main_conf,scriptPath,targetPath,ssh_get_cnt(*main_conf));
+  unlink(scriptPath);
+  free(scriptPath);
+  if(copy0!=true){
+    setMapInMaps(*main_conf,"lenv","message",_("Unable to upload the script"));
+#ifdef USE_CALLBACK
+    invokeCallback(*main_conf,NULL,NULL,7,0);
+#endif
+    errorException(*main_conf,_("Unable to upload the script"),"NoApplicableCode",NULL);
+    return -1;
+  }
+  // Execute the SBATCH script remotely
+  addReadLocks(main_conf);
+  map* subStr=getMapFromMaps(*main_conf,configurationId,"sbatch_substr");
+  char *command=(char*)malloc((strlen(targetPath)+strlen(targetPathMap->value)+strlen(subStr->value)+strlen(uuid->value)+137)*sizeof(char));
+  sprintf(command,"sbatch %s 2> %s/error_%s.log | sed \"s:%s::g\"",targetPath,targetPathMap->value,uuid->value,subStr->value);
+  if(ssh_exec(*main_conf,command,ssh_get_cnt(m))<=0){
+    // The sbatch command has failed!
+    // Download the error log file from the HPC server
+    char tmpS[1024];
+    free(command);
+    command=(char*)malloc((strlen(targetPathMap->value)+strlen(uuid->value)+11)*sizeof(char));
+    sprintf(command,"%s/error_%s.log",targetPathMap->value,uuid->value);
+    targetName=strrchr(command,'/');
+    free(targetPath);
+    targetPath=(char*)malloc((strlen(tmpPath->value)+strlen(targetName)+2)*sizeof(char));
+    sprintf(targetPath,"%s/%s",tmpPath->value,targetName);
+    if(ssh_fetch(*main_conf,targetPath,command,ssh_get_cnt(m))==0){
+      struct stat f_status;
+      int ts=stat(targetPath, &f_status);
+      if(ts==0) {
+	char* fcontent = NULL;
+	fcontent=(char*)malloc(sizeof(char)*(f_status.st_size+1));
+	FILE* f=fopen(targetPath,"rb");
+	fread(fcontent,f_status.st_size,1,f);
+	int fsize=f_status.st_size;
+	fcontent[fsize]=0;
+	fclose(f);
+	setMapInMaps(*main_conf,"lenv","message",fcontent);
+	free(fcontent);
+      }else
+	setMapInMaps(*main_conf,"lenv","message",_("No message provided"));
+    }else
+      setMapInMaps(*main_conf,"lenv","message",_("Unable to fetch the remote error log file"));
+    tmpPath=getMapFromMaps(m,"lenv","message");
+#ifdef HPC_DEBUG
+    fprintf(stderr,"************************* %s %d \n\n",__FILE__,__LINE__);
+    fflush(stderr);
+#endif
+#ifdef USE_CALLBACK
+    invokeCallback(*main_conf,NULL,NULL,7,0);
+#endif
+#ifdef HPC_DEBUG
+    fprintf(stderr,"************************* %s %d \n\n",__FILE__,__LINE__);
+    fflush(stderr);
+#endif
+    sprintf(tmpS, "Cannot execute the HPC ZOO-Service %s using %s: %s", s->name, configurationId, tmpPath->value);
+    errorException(*main_conf,tmpS,"NoApplicableCode",NULL);
+    free(command);
+    free(targetPath);
+    ssh_close(*main_conf);
+    removeReadLocks(main_conf);
+    return -1;
+  }
+  free(targetPath);
+#ifdef HPC_DEBUG
+  fprintf(stderr,"************************* %s %d \n\n",__FILE__,__LINE__);
+  fflush(stderr);
+#endif
+#ifdef USE_CALLBACK
+  invokeCallback(m,NULL,NULL,4,1);
+#endif
+#ifdef HPC_DEBUG
+  fprintf(stderr,"************************* %s %d \n\n",__FILE__,__LINE__);
+  fflush(stderr);
+#endif
+  free(command);
+#ifdef HPC_DEBUG
+  fprintf(stderr,"************************* %s %d \n\n",__FILE__,__LINE__);
+  fflush(stderr);
+#endif
+
+  struct sockaddr_un addr;
+  memset(&addr, 0, sizeof(addr));
+  addr.sun_family = AF_UNIX;
+  int rc, cl, fd = socket(AF_UNIX, SOCK_STREAM, 0);
+  char *sname=(char*)malloc((strlen(tmpPath->value)+strlen(uuid->value)+20));
+  sprintf(sname,"%s/.wait_socket_%s.sock",tmpPath->value,uuid->value);
+  strncpy(addr.sun_path, sname, sizeof(addr.sun_path)-1);
+  
+  if (bind(fd, (struct sockaddr*)&addr, sizeof(addr)) == -1) {
+    perror("bind error");
+    setMapInMaps(*main_conf,"lenv","message",_("Unable to bind socket!"));
+    errorException (*main_conf, _("Unable to bind socket!"),
+		    "InternalError", NULL);
+#ifdef HPC_DEBUG
+    fprintf(stderr,"************************* %s %d \n\n",__FILE__,__LINE__);
+    fflush(stderr);
+#endif
+#ifdef USE_CALLBACK
+    invokeCallback(*main_conf,NULL,NULL,7,0);
+#endif
+    removeReadLocks(main_conf);
+#ifdef HPC_DEBUG
+    fprintf(stderr,"************************* %s %d \n\n",__FILE__,__LINE__);
+    fflush(stderr);
+#endif
+    return -1;
+  }
+#ifdef HPC_DEBUG
+  fprintf(stderr,"************************* %s %d \n\n",__FILE__,__LINE__);
+  fflush(stderr);
+#endif
+  if (listen(fd, 5) == -1) {
+    setMapInMaps(*main_conf,"lenv","message",_("Listen error"));
+    errorException (*main_conf, _("Listen error"),
+		    "InternalError", NULL);
+#ifdef HPC_DEBUG
+    fprintf(stderr,"************************* %s %d \n\n",__FILE__,__LINE__);
+    fflush(stderr);
+#endif
+#ifdef USE_CALLBACK
+    invokeCallback(*main_conf,NULL,NULL,7,0);
+#endif
+    removeReadLocks(main_conf);
+#ifdef HPC_DEBUG
+    fprintf(stderr,"************************* %s %d \n\n",__FILE__,__LINE__);
+    fflush(stderr);
+#endif
+    return -1;
+  }
+  if ( (cl = accept(fd, NULL, NULL)) == -1) {
+    setMapInMaps(*main_conf,"lenv","message",_("Accept error"));
+    errorException (*main_conf, _("Accept error"),
+		    "InternalError", NULL);
+#ifdef HPC_DEBUG
+    fprintf(stderr,"************************* %s %d \n\n",__FILE__,__LINE__);
+    fflush(stderr);
+#endif
+#ifdef USE_CALLBACK
+    invokeCallback(*main_conf,NULL,NULL,7,0);
+#endif
+    removeReadLocks(main_conf);
+#ifdef HPC_DEBUG
+    fprintf(stderr,"************************* %s %d \n\n",__FILE__,__LINE__);
+    fflush(stderr);
+#endif
+    return -1;
+  }else{
+#ifdef HPC_DEBUG
+    fprintf(stderr,"************************* %s %d \n\n",__FILE__,__LINE__);
+    fflush(stderr);
+#endif
+    int hasPassed=-1;
+    char buf[11];
+    memset(&buf,0,11);
+    while ( (rc=read(cl,buf,10)) ) {	  
+      if(rc==0){
+	setMapInMaps(*main_conf,"lenv","message",_("Read closed"));
+	errorException (*main_conf, _("Read closed"),
+			"InternalError", NULL);
+#ifdef HPC_DEBUG
+	fprintf(stderr,"************************* %s %d \n\n",__FILE__,__LINE__);
+	fflush(stderr);
+#endif
+#ifdef USE_CALLBACK
+	invokeCallback(*main_conf,NULL,NULL,7,0);
+#endif
+	removeReadLocks(main_conf);
+#ifdef HPC_DEBUG
+	fprintf(stderr,"************************* %s %d \n\n",__FILE__,__LINE__);
+	fflush(stderr);
+#endif
+	return -1;
+      }else{
+	if(rc<0){
+	  setMapInMaps(*main_conf,"lenv","message",_("Read error"));
+	  errorException (*main_conf, _("Read error"),
+			  "InternalError", NULL);
+#ifdef HPC_DEBUG
+	  fprintf(stderr,"************************* %s %d \n\n",__FILE__,__LINE__);
+	  fflush(stderr);
+#endif
+#ifdef USE_CALLBACK
+	  invokeCallback(*main_conf,NULL,NULL,7,0);
+#endif
+	  removeReadLocks(main_conf);
+#ifdef HPC_DEBUG
+	  fprintf(stderr,"************************* %s %d \n\n",__FILE__,__LINE__);
+	  fflush(stderr);
+#endif
+	  return -1;
+	}
+      }
+      hasPassed=1;
+      res=atoi(buf);
+      unlink(sname);
+      free(sname);
+      removeReadLocks(main_conf);
+  
+      if(res==3){
+#ifdef HPC_DEBUG
+	fprintf(stderr,"************************* %s %d \n\n",__FILE__,__LINE__);
+	fflush(stderr);
+#endif
+#ifdef USE_CALLBACK
+	invokeCallback(m,NULL,outputs,5,0);
+#endif
+#ifdef HPC_DEBUG
+	fprintf(stderr,"************************* %s %d \n\n",__FILE__,__LINE__);
+	fflush(stderr);
+#endif
+
+	// Read informations provided by FinalizeHPC as a configuration file
+	// then, remove the file.
+	map* jobid=getMapFromMaps(*main_conf,"lenv","usid");
+	map* tmpPath=getMapFromMaps(*main_conf,"main","tmpPath");
+	char *filePath=(char*)malloc((strlen(tmpPath->value)+strlen(jobid->value)+15)*sizeof(char));
+	sprintf(filePath,"%s/exec_status_%s",tmpPath->value,jobid->value);
+	maps* lm = (maps *) malloc (MAPS_SIZE);
+	lm->child=NULL;
+	lm->next=NULL;
+	int saved_stdout = dup (fileno (stdout));
+	dup2 (fileno (stderr), fileno (stdout));
+	conf_read(filePath,lm);
+	//dumpMaps(m);
+	fflush(stdout);
+	dup2 (saved_stdout, fileno (stdout));
+	close(saved_stdout);
+	unlink(filePath);
+	free(filePath);
+	addMapsToMaps(main_conf,lm);
+	freeMaps(&lm);
+	free(lm);
+
+	input=*real_outputs;
+	while(input!=NULL){
+	  if(input->child==NULL){
+	    map* generatedFile=getMap(input->content,"generated_file");
+	    if(generatedFile!=NULL){
+	      char* filename=strrchr(generatedFile->value,'/');
+	      char* targetPath=(char*)malloc((strlen(tmpPath->value)+strlen(filename)+2)*sizeof(char));
+	      sprintf(targetPath,"%s/%s",tmpPath->value,filename);
+	      test=ssh_connect(*main_conf);
+	      if(ssh_fetch(*main_conf,targetPath,generatedFile->value,ssh_get_cnt(m))==0){
+		setMapInMaps(*real_outputs,input->name,"generated_file",targetPath);
+		free(targetPath);
+	      }else{
+		map* hpcStdErr=getMapFromMaps(*main_conf,"henv","StdErr");
+		// Added for using sacct in place of scontrol
+		char *sourcePath=NULL;
+		if(hpcStdErr!=NULL){
+		  sourcePath=(char*)malloc((strlen(targetPathMap->value)+strlen(hpcStdErr->value)+2)*sizeof(char));
+		  sprintf(sourcePath,"%s/%s",targetPathMap->value,hpcStdErr->value);
+		}
+                if(hpcStdErr!=NULL && sourcePath!=NULL && ssh_fetch(*main_conf,targetPath,sourcePath,ssh_get_cnt(m))==0){
+		  free(sourcePath);
+		  struct stat f_status;
+		  int ts=stat(targetPath, &f_status);
+		  if(ts==0) {
+		    char* fcontent = NULL;
+		    fcontent=(char*)malloc(sizeof(char)*(f_status.st_size+1));
+		    FILE* f=fopen(targetPath,"rb");
+		    fread(fcontent,f_status.st_size,1,f);
+		    int fsize=f_status.st_size;
+		    fcontent[fsize]=0;
+		    fclose(f);
+		    setMapInMaps(*main_conf,"lenv","message",fcontent);
+		    free(fcontent);
+		  }else{
+		    char *tmpStr=(char*)malloc((strlen(targetPath)+strlen(_("Unable to fetch the remote file for %s"))+1)*sizeof(char));
+		    sprintf(tmpStr,_("Unable to fetch the remote file for %s"),targetPath);
+		    setMapInMaps(*main_conf,"lenv","message",tmpStr);
+		    free(tmpStr);
+		  }
+                }else{
+                  char *tmpStr=(char*)malloc((strlen(filename)+strlen(_("Unable to fetch the remote file for %s"))+1)*sizeof(char));
+                  sprintf(tmpStr,_("Unable to fetch the remote file for %s"),filename);
+                  setMapInMaps(*main_conf,"lenv","message",tmpStr);
+                  free(tmpStr);
+                }
+#ifdef USE_CALLBACK
+		invokeCallback(*main_conf,NULL,NULL,7,0);
+#endif
+		return SERVICE_FAILED;
+	      }
+	    }
+	  }else{
+	    map* generatedFile=getMap(input->content,"generated_file");
+	    map* generatedUrl=getMap(input->content,"generated_url");
+	    if(generatedFile!=NULL){
+	      char* filename=strrchr(generatedFile->value,'/');
+	      char* targetPath=(char*)malloc((strlen(tmpPath->value)+strlen(filename)+2)*sizeof(char));
+	      sprintf(targetPath,"%s/%s",tmpPath->value,filename);
+	      test=ssh_connect(*main_conf);
+	      if(ssh_fetch(*main_conf,targetPath,generatedFile->value,ssh_get_cnt(m))==0){
+		maps* tmp=getMaps(*real_outputs,input->name);
+		char serviceName[9];
+		freeMap(&tmp->content);
+		free(tmp->content);
+		tmp->content=NULL;
+		maps* output=getMaps(*real_outputs,input->name);
+		setMapInMaps(output->child,"download_link","generated_file",targetPath);
+		setMapInMaps(output->child,"download_link","generated_url",generatedUrl->value);
+		setMapInMaps(output->child,"download_link","storage",targetPath);
+		setMapInMaps(output->child,"download_link","useMapserver","false");
+		setMapInMaps(output->child,"download_link","replicateStorageNext","true");
+		setMapInMaps(output->child,"download_link","asReference","true");
+		setMapInMaps(output->child,"download_link","inRequest","true");
+		setMapInMaps(output->child,"wms_link","generated_file",targetPath);
+		setMapInMaps(output->child,"wms_link","storage",targetPath);
+		setMapInMaps(output->child,"wms_link","useMapserver","true");
+		setMapInMaps(output->child,"wms_link","msOgc","WMS");
+		setMapInMaps(output->child,"wms_link","requestedMimeType","image/png");
+		setMapInMaps(output->child,"wms_link","asReference","true");
+		if(getMaps(output->child,"wcs_link")!=NULL){
+		  sprintf(serviceName,"wcs_link");
+		  setMapInMaps(output->child,"wcs_link","msOgc","WCS");
+		}else{
+		  sprintf(serviceName,"wfs_link");
+		  setMapInMaps(output->child,"wfs_link","msOgc","WFS");
+                }
+		setMapInMaps(output->child,serviceName,"storage",targetPath);
+		setMapInMaps(output->child,serviceName,"generated_file",targetPath);
+		setMapInMaps(output->child,serviceName,"useMapserver","true");
+		setMapInMaps(output->child,serviceName,"asReference","true");
+	      }else{
+		map* hpcStdErr=getMapFromMaps(*main_conf,"henv","StdErr");
+		char *sourcePath=NULL;
+		if(hpcStdErr!=NULL){
+		  dumpMap(hpcStdErr);
+		  sourcePath=(char*)malloc((strlen(targetPathMap->value)+strlen(hpcStdErr->value)+2)*sizeof(char));
+		  sprintf(sourcePath,"%s/%s",targetPathMap->value,hpcStdErr->value);
+		}
+                if(hpcStdErr!=NULL && sourcePath!=NULL && ssh_fetch(*main_conf,targetPath,sourcePath,ssh_get_cnt(m))==0){
+		  free(sourcePath);
+		  struct stat f_status;
+		  int ts=stat(targetPath, &f_status);
+		  if(ts==0) {
+		    char* fcontent = NULL;
+		    fcontent=(char*)malloc(sizeof(char)*(f_status.st_size+1));
+		    FILE* f=fopen(targetPath,"rb");
+		    fread(fcontent,f_status.st_size,1,f);
+		    int fsize=f_status.st_size;
+		    fcontent[fsize]=0;
+		    fclose(f);
+		    setMapInMaps(*main_conf,"lenv","message",fcontent);
+		    free(fcontent);
+		  }else{
+		    char *tmpStr=(char*)malloc((strlen(targetPath)+strlen(_("Unable to fetch the remote file for %s"))+1)*sizeof(char));
+		    sprintf(tmpStr,_("Unable to fetch the remote file for %s"),targetPath);
+		    setMapInMaps(*main_conf,"lenv","message",tmpStr);
+		    free(tmpStr);
+		  }
+		}else{
+		  char *tmpStr=(char*)malloc((strlen(sourcePath)+strlen(_("Unable to fetch the remote file for %s"))+1)*sizeof(char));
+		  sprintf(tmpStr,_("Unable to fetch the remote file for %s"),sourcePath);
+		  setMapInMaps(*main_conf,"lenv","message",tmpStr);
+		  free(tmpStr);
+		}
+#ifdef USE_CALLBACK
+                invokeCallback(*main_conf,NULL,NULL,7,0);
+#endif
+                return SERVICE_FAILED;
+	      }
+	      free(targetPath);
+	    }
+	  }
+	  input=input->next;
+	}
+
+      }else{
+	// Try to access remotely to the log file and return a more relevant error message
+	setMapInMaps(*main_conf,"lenv","message",_("HPC Execution failed!"));
+	errorException (*main_conf, _("HPC Execution failed!"),
+			"InternalError", NULL);
+#ifdef HPC_DEBUG
+	fprintf(stderr,"************************* %s %d \n\n",__FILE__,__LINE__);
+	fflush(stderr);
+#endif
+#ifdef USE_CALLBACK
+	invokeCallback(*main_conf,NULL,NULL,7,0);
+#endif
+#ifdef HPC_DEBUG
+	fprintf(stderr,"************************* %s %d \n\n",__FILE__,__LINE__);
+	fflush(stderr);
+#endif
+      }
+    }
+    if(hasPassed<0){
+      perror("Failed to read");
+      setMapInMaps(*main_conf,"lenv","message",_("Unable to parse the value returned by remote execution"));
+      errorException (*main_conf, _("Unable to parse the value returned by remote execution"),
+		      "InternalError", NULL);
+#ifdef HPC_DEBUG
+      fprintf(stderr,"************************* %s %d \n\n",__FILE__,__LINE__);
+      fflush(stderr);
+#endif
+#ifdef USE_CALLBACK
+      invokeCallback(*main_conf,NULL,NULL,7,0);
+#endif
+#ifdef HPC_DEBUG
+      fprintf(stderr,"************************* %s %d \n\n",__FILE__,__LINE__);
+      fflush(stderr);
+#endif
+      return SERVICE_FAILED;
+    }
+  }
+#ifdef HPC_DEBUG
+  fprintf(stderr,"************************* %s %d \n\n",__FILE__,__LINE__);
+  fflush(stderr);
+#endif
+  ssh_close(*main_conf);
+#ifdef HPC_DEBUG
+  fprintf(stderr,"************************* %s %d \n\n",__FILE__,__LINE__);
+  fflush(stderr);
+#endif
+  return res;
+}
Index: trunk/zoo-project/zoo-kernel/service_internal_hpc.h
===================================================================
--- trunk/zoo-project/zoo-kernel/service_internal_hpc.h	(revision 917)
+++ trunk/zoo-project/zoo-kernel/service_internal_hpc.h	(revision 917)
@@ -0,0 +1,45 @@
+/*
+ * Author : Gérald FENOY
+ *
+ * Copyright (c) 2017 GeoLabs SARL
+ *
+ * This work was supported by public funds received in the framework of GEOSUD,
+ * a project (ANR-10-EQPX-20) of the program "Investissements d'Avenir" managed 
+ * by the French National Research Agency
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef ZOO_SERVICE_INTERNAL_HPC_H
+#define ZOO_SERVICE_INTERNAL_HPC_H 1
+
+#pragma once 
+
+#include "service_internal.h"
+#include "service.h"
+#ifdef WIN32
+#include <windows.h>
+#include <direct.h>
+#endif
+#include "sshapi.h"
+
+void addNestedOutputs(service**);
+int zoo_hpc_support(maps**,map*,service*,maps**,maps**);
+
+#endif
Index: trunk/zoo-project/zoo-kernel/service_internal_java.c
===================================================================
--- trunk/zoo-project/zoo-kernel/service_internal_java.c	(revision 889)
+++ trunk/zoo-project/zoo-kernel/service_internal_java.c	(revision 917)
@@ -208,5 +208,5 @@
 #endif
 #ifdef JAVA7
-  cls_gr = (*env)NewGlobalRef(cls);
+  cls_gr = (*env).NewGlobalRef(cls);
 #else
   cls_gr = (*env)->NewGlobalRef(env, cls);
@@ -215,5 +215,5 @@
   if (cls != NULL) {
 #ifdef JAVA7
-@    (*env).ExceptionClear();
+    (*env).ExceptionClear();
     pmid=(*env).GetStaticMethodID(cls, s->name, "(Ljava/util/HashMap;Ljava/util/HashMap;Ljava/util/HashMap;)I");
 #else
@@ -284,5 +284,5 @@
   }
 #ifdef JAVA7
-      (*jvm).DestroyJavaVM();
+  (*jvm).DestroyJavaVM();
 #else
   (*jvm)->DestroyJavaVM(jvm);
@@ -427,4 +427,6 @@
 #endif
       map* sizeV=getMap(tmp1,"size");
+      map* useFile=getMap(tmp1,"use_file");
+      map* cacheFile=getMap(tmp1,"cache_file");
       map* isArray=getMap(tmp1,"isArray");
       map* alen=getMap(tmp1,"length");
@@ -432,9 +434,9 @@
 	if(strcmp(tmp1->name,"value")==0){
 	  if(isArray==NULL){
-	    if(sizeV!=NULL && strcmp(tmp1->name,"value")==0){
+	    if(sizeV!=NULL && strcmp(tmp1->name,"value")==0 && useFile==NULL){
 #ifdef JAVA7
 	      jbyteArray tmpData=(*env).NewByteArray(atoi(sizeV->value));
 	      (*env).SetByteArrayRegion(tmpData,0,atoi(sizeV->value),(const jbyte *)tmp1->value);
-	      (*env).CallObjectMethod(env,scObject1, put_mid, (*env).NewStringUTF(env,tmp1->name), tmpData);
+	      (*env).CallObjectMethod(scObject1, put_mid, (*env).NewStringUTF(tmp1->name), tmpData);
 #else
 	      jbyteArray tmpData=(*env)->NewByteArray(env,atoi(sizeV->value));
@@ -448,4 +450,11 @@
 	      (*env)->CallObjectMethod(env,scObject1, put_mid, (*env)->NewStringUTF(env,tmp1->name), (*env)->NewStringUTF(env,tmp1->value));
 #endif
+	      if(useFile!=NULL)
+#ifdef JAVA7
+		(*env).CallObjectMethod(scObject1, put_mid, (*env).NewStringUTF("cache_file"), (*env).NewStringUTF(cacheFile->value));
+#else
+	        (*env)->CallObjectMethod(env,scObject1, put_mid, (*env)->NewStringUTF(env,"cache_file"), (*env)->NewStringUTF(env,cacheFile->value));
+#endif
+	      
 	  }
 	  else{
@@ -455,5 +464,5 @@
 	    jclass scArrayListClass,scArrayList_class;
 	    jmethodID scArrayList_constructor;
-	    jobject scObject2;
+	    jobject scObject2,scObject3;
 #ifdef JAVA7
 	    scArrayListClass = (*env).FindClass("java/util/ArrayList");
@@ -462,4 +471,5 @@
 	    jmethodID add_mid = 0;
 	    scObject2 = (*env).NewObject(scArrayList_class, scArrayList_constructor);
+	    scObject3 = (*env).NewObject(scArrayList_class, scArrayList_constructor);
 
 	    add_mid = (*env).GetMethodID(scArrayListClass,
@@ -471,4 +481,5 @@
 	    jmethodID add_mid = 0;
 	    scObject2 = (*env)->NewObject(env, scArrayList_class, scArrayList_constructor);
+	    scObject3 = (*env)->NewObject(env, scArrayList_class, scArrayList_constructor);
 
 	    add_mid = (*env)->GetMethodID(env,scArrayListClass,
@@ -478,9 +489,11 @@
 	    
 	    for(i=0;i<alen1;i++){
+	      map* cMap=getMapArray(tmp->content,"cache_file",i);
+	      map* uMap=getMapArray(tmp->content,"use_file",i);
 	      map* vMap=getMapArray(tmp->content,"value",i);
 	      map* sMap=getMapArray(tmp->content,"size",i);
 	      map* mMap=getMapArray(tmp->content,tmap->value,i);
 	      
-	      if(sMap!=NULL && vMap!=NULL && strncmp(vMap->name,"value",5)==0){
+	      if(sMap!=NULL && vMap!=NULL && strncmp(vMap->name,"value",5)==0 && uMap==NULL){
 #ifdef JAVA7
 		jbyteArray tmpData=(*env).NewByteArray(atoi(sMap->value));
@@ -501,11 +514,23 @@
 #endif
 	      }
-	      
+
+	      if(cMap!=NULL){
+#ifdef JAVA7
+		jobject tmpData=(*env).NewStringUTF(cMap->value);
+		(*env).CallObjectMethod(scObject3, add_mid, tmpData);
+#else
+		jobject tmpData=(*env)->NewStringUTF(env,cMap->value);
+		(*env)->CallObjectMethod(env,scObject3, add_mid, tmpData);
+#endif
+
+	      }
 	    }
 
 #ifdef JAVA7
 	    (*env).CallObjectMethod(scObject1, put_mid, (*env).NewStringUTF(tmp1->name), scObject2);
+	    (*env).CallObjectMethod(scObject1, put_mid, (*env).NewStringUTF("cache_file"), scObject3);
 #else	    
 	    (*env)->CallObjectMethod(env,scObject1, put_mid, (*env)->NewStringUTF(env,tmp1->name), scObject2);
+	    (*env)->CallObjectMethod(env,scObject1, put_mid, (*env)->NewStringUTF(env,"cache_file"), scObject3);
 #endif
 
Index: trunk/zoo-project/zoo-kernel/service_internal_js.c
===================================================================
--- trunk/zoo-project/zoo-kernel/service_internal_js.c	(revision 889)
+++ trunk/zoo-project/zoo-kernel/service_internal_js.c	(revision 917)
@@ -157,4 +157,6 @@
     return 1;
   if (!JS_DefineFunction(cx, global, "alert", JSAlert, 2, 0))
+    return 1;  
+  if (!JS_DefineFunction(cx, global, "sleep", JSSleep, 1, 0))
     return 1;  
   if (!JS_DefineFunction(cx, global, "importScripts", JSLoadScripts, 1, 0))
@@ -901,4 +903,6 @@
   char* tmpValue;
   size_t dwRead;
+  maps *tmpConf=createMaps("main");
+  tmpConf->content=createMap("memory","load");
   JS_MaybeGC(cx);
   hInternet=InternetOpen("ZooWPSClient\0",
@@ -929,5 +933,5 @@
 #endif
     InternetOpenUrl(&hInternet,hInternet.waitingRequests[hInternet.nb],body,strlen(body),
-		    INTERNET_FLAG_NO_CACHE_WRITE,0);    
+		    INTERNET_FLAG_NO_CACHE_WRITE,0,tmpConf);    
     processDownloads(&hInternet);
     free(body);
@@ -940,10 +944,10 @@
 	}
 	InternetOpenUrl(&hInternet,hInternet.waitingRequests[hInternet.nb],NULL,0,
-			INTERNET_FLAG_NO_CACHE_WRITE,0);
+			INTERNET_FLAG_NO_CACHE_WRITE,0,tmpConf);
 	processDownloads(&hInternet);
       }else{
 	char *body=JSValToChar(cx,&argv[2]);
 	InternetOpenUrl(&hInternet,hInternet.waitingRequests[hInternet.nb],body,strlen(body),
-			INTERNET_FLAG_NO_CACHE_WRITE,0);
+			INTERNET_FLAG_NO_CACHE_WRITE,0,tmpConf);
 	processDownloads(&hInternet);
 	free(body);
@@ -951,5 +955,5 @@
     }else{
       InternetOpenUrl(&hInternet,hInternet.waitingRequests[hInternet.nb],NULL,0,
-		      INTERNET_FLAG_NO_CACHE_WRITE,0);
+		      INTERNET_FLAG_NO_CACHE_WRITE,0,tmpConf);
       processDownloads(&hInternet);
     }
@@ -972,4 +976,6 @@
   if(argc>=2)
     free(method);
+  freeMaps(&tmpConf);
+  free(tmpConf);
   InternetCloseHandle(&hInternet);
   JS_MaybeGC(cx);
@@ -1023,2 +1029,24 @@
 }
 
+/**
+ * The function used as sleep from the JavaScript environment
+ * (ZOO-API).
+ *
+ * @param cx the JavaScript context
+ * @param argc the number of parameters
+ * @param argv1 the parameter values
+ * @return true
+ */
+JSBool
+JSSleep(JSContext *cx, uintN argc, jsval *argv1)
+{
+  jsval *argv = JS_ARGV(cx,argv1);
+  JS_MaybeGC(cx);
+  int isleep=0;
+  if(JS_ValueToInt32(cx,argv[0],&isleep)==JS_TRUE){
+    zSleep(isleep);
+  }
+  JS_MaybeGC(cx);
+  return JS_TRUE;
+}
+
Index: trunk/zoo-project/zoo-kernel/service_internal_js.h
===================================================================
--- trunk/zoo-project/zoo-kernel/service_internal_js.h	(revision 889)
+++ trunk/zoo-project/zoo-kernel/service_internal_js.h	(revision 917)
@@ -49,4 +49,5 @@
   JSBool JSRequest(JSContext*, uintN, jsval*);
   JSBool JSUpdateStatus(JSContext*,uintN,jsval *);
+  JSBool JSSleep(JSContext*,uintN,jsval *);
 
   void reportError(JSContext *cx, const char *message, JSErrorReport *report);
Index: trunk/zoo-project/zoo-kernel/service_internal_mono.c
===================================================================
--- trunk/zoo-project/zoo-kernel/service_internal_mono.c	(revision 889)
+++ trunk/zoo-project/zoo-kernel/service_internal_mono.c	(revision 917)
@@ -30,4 +30,7 @@
 #include "response_print.h"
 
+MonoClass *iclasses[4];
+MonoMethod *imethods[10];
+
 /**
  * Load a Mono dll then run the static public method corresponding to the 
@@ -69,21 +72,52 @@
     mono_config_parse(NULL);
 
-  MonoDomain* monoDomain = mono_jit_init_version("ZOO_Embedded_Domain",
-                                                 "v4.0.30319");
-
-  map* cwdMap=getMapFromMaps(*main_conf,"main","servicePath");
-  if(cwdMap==NULL)
-    cwdMap=getMapFromMaps(*main_conf,"lenv","cwd");
-  
-  char *zooAssembly=(char*)malloc((strlen(cwdMap->value)+11)*sizeof(char));
-  sprintf(zooAssembly,"%s/ZMaps.dll",cwdMap->value);
-  assembly = mono_domain_assembly_open(monoDomain,zooAssembly);
-  if(assembly==NULL){
-    setMapInMaps(*main_conf,"lenv","message",_("The ZMaps.dll assembly cannot be found!"));
-    return 4;
-  }
-  mono_add_internal_call ("ZOO_API::Translate", MonoTranslate);
-  mono_add_internal_call ("ZOO_API::UpdateStatus", MonoUpdateStatus);
-
+  MonoDomain* monoDomain;
+  map* mono;
+  if (hasvalue(*main_conf, "mono", "version", &mono)) {	  
+	  monoDomain = mono_jit_init_version("ZOO_Embedded_Domain", mono->value);
+  }
+  else {	  
+	  monoDomain = mono_jit_init("ZOO_Embedded_Domain"); // use default framework version
+  }
+
+  //MonoDomain* monoDomain = mono_jit_init_version("ZOO_Embedded_Domain", "v4.0.30319"); 
+  //MonoDomain* monoDomain = mono_jit_init("ZOO_Embedded_Domain");  
+
+  char* ZMapsLib = "ZMaps.dll";
+  char *zooAssembly = NULL;
+  
+  map* config = NULL, *basedir = NULL;
+  if (hasvalue(*main_conf, "mono", "configdir", &basedir) && // knut: rename to e.g. "base_dir"?
+	  hasvalue(*main_conf, "mono", "configfile", &config)) {	  
+	  mono_domain_set_config(monoDomain, basedir->value, config->value); 
+	  zooAssembly = file_exists(basedir->value, ZMapsLib);
+  }
+  else {	  
+	  mono_domain_set_config(monoDomain, "./", "");
+  }    
+
+  map* cwdMap;
+  if (! hasvalue(*main_conf, "main", "servicePath", &cwdMap) &&
+	  ! hasvalue(*main_conf, "main", "libPath", &cwdMap) ) {
+	  cwdMap = getMapFromMaps(*main_conf, "lenv", "cwd");
+  }  
+
+  if (zooAssembly != NULL || (zooAssembly = file_exists(cwdMap->value, ZMapsLib)) != NULL) {
+	  assembly = mono_domain_assembly_open(monoDomain, zooAssembly);
+  }
+  else { 
+	  // try to load from default locations (GAC?)
+	  assembly = mono_domain_assembly_open(monoDomain, ZMapsLib);
+  }  
+  free(zooAssembly);
+
+  if (assembly == NULL) {
+	  setMapInMaps(*main_conf, "lenv", "message", _("The ZMaps.dll assembly cannot be found!"));
+	  return 4;
+  }
+
+  mono_add_internal_call ("ZOO_API::Translate", MonoTranslate);    
+  mono_add_internal_call("ZOO_API::UpdateStatus", MonoUpdateStatus);
+  
   monoImage = mono_assembly_get_image(assembly);
   MonoClass *KeysList = mono_class_from_name(monoImage, "ZooGenerics", "KeysList");
@@ -104,6 +138,7 @@
   MonoClass *classes[3]={_ZMapsClass,ZMapsClass,ZMapClass};
   MonoMethod *methods[5]={ZMapsAdd,_ZMapsSetContent,_ZMapsSetChild,ZMapAdd,ZMapDisplay};
-
+  
   MonoMethod *ZMapsGetKeys = mono_class_get_method_from_name(ZMapsClass, "getKeys", 0);
+  
   MonoMethod *ZMapsGetKeysCount = mono_class_get_method_from_name(ZMapsClass, "getKeysCount", 0);
   MonoMethod *ZMapsGetKey = mono_class_get_method_from_name(ZMapsClass, "getKey", 1);
@@ -116,5 +151,5 @@
   MonoClass *oclasses[4]={_ZMapsClass,ZMapsClass,ZMapClass,KeysList};
   MonoMethod *omethods[10]={ZMapsGetMaps,ZMapsGetKeysCount,ZMapsGetKey,ZMapGetMap,ZMapGetKeysCount,ZMapGetKey,_ZMapsGetContent,_ZMapsGetChild,ZMapGetSize,ZMapGetMapAsBytes};
-
+  
   for(int i=0;i<4;i++){
     iclasses[i]=oclasses[i];
@@ -131,13 +166,30 @@
 
   MonoObject * out=ZMapsFromMaps(monoDomain,classes,methods,&exc,outputs);
-
+  
   args [0] = main;
   args [1] = in;
   args [2] = out;
 
-  tmp=getMap(s->content,"serviceProvider");
-  char *sName=(char*)malloc((strlen(tmp->value)+strlen(cwdMap->value)+2)*sizeof(char));
-  sprintf(sName,"%s/%s",cwdMap->value,tmp->value);
-  MonoAssembly* serviceAssembly = mono_domain_assembly_open(monoDomain,sName);
+  char* sName = NULL;
+  MonoAssembly* serviceAssembly = NULL;
+  
+  tmp = getMap(s->content, "serviceProvider");  
+  char* test = file_exists(NULL, "log.txt");
+  if ( (sName = file_exists(cwdMap->value, tmp->value)) != NULL ||
+	   (sName = file_exists(".", tmp->value)) != NULL ||  // in case servicePath is defined but serviceProvider is in working directory
+	   (basedir != NULL && (sName = file_exists(basedir->value, tmp->value)) != NULL) ) {
+
+	   serviceAssembly = mono_domain_assembly_open(monoDomain, sName);
+  }
+  else {
+	  // try to open from default locations	  
+	  serviceAssembly = mono_domain_assembly_open(monoDomain, tmp->value);
+  }
+  free(sName);
+
+  //char *sName=(char*)malloc((strlen(tmp->value)+strlen(cwdMap->value)+2)*sizeof(char));
+  //sprintf(sName,"%s/%s",cwdMap->value,tmp->value);
+  //MonoAssembly* serviceAssembly = mono_domain_assembly_open(monoDomain,sName);
+  
   if(serviceAssembly==NULL){
     char *msg=(char*)malloc((strlen(_("Your service assembly: %s cannot be found!"))+strlen(tmp->value)+1)*sizeof(char));
@@ -147,8 +199,9 @@
     return 4;
   }
-
+  
   MonoImage* serviceImage = mono_assembly_get_image(serviceAssembly);
 
   map* tmp1=getMap(s->content,"serviceNameSpace");
+  
   tmp=getMap(s->content,"serviceClass");
   MonoClass *serviceClass = mono_class_from_name(serviceImage, tmp1->value, tmp->value);
@@ -160,4 +213,5 @@
     return 4;
   }
+  
   MonoMethod *serviceFunction = mono_class_get_method_from_name(serviceClass, s->name, 3);
   if(serviceFunction==NULL){
@@ -168,18 +222,28 @@
     return 4;
   }
+  
   MonoObject *exception=NULL;
   MonoObject *result = mono_runtime_invoke(serviceFunction,NULL,args,&exception);
+  
+  if (exception != NULL) { // knut: add exception handling
+	  MonoString* pMsg = mono_object_to_string(exception, NULL);	  
+	  setErrorMessage(*main_conf, s->name, NoApplicableCode, mono_string_to_utf8(pMsg));
+	  return 4;
+  }
+
   res=*(int*)mono_object_unbox (result);
+  
   if(res==3){
     freeMaps(&outputs);
     free(outputs);
-    outputs=mapsFromZMaps(monoDomain,oclasses,omethods,args[2]);
+    outputs=mapsFromZMaps(monoDomain,oclasses,omethods,(MonoObject*)args[2]);
     *real_outputs=outputs;
   }
+  
   freeMaps(&m);
   free(m);
-  m=mapsFromZMaps(monoDomain,oclasses,omethods,args[0]);
+  m=mapsFromZMaps(monoDomain,oclasses,omethods,(MonoObject*)args[0]);
   *main_conf=m;
-  mono_jit_cleanup (monoDomain);
+  mono_jit_cleanup (monoDomain);  
   return res;
 }
@@ -288,10 +352,10 @@
       values[0]=&i;
       exc=NULL;
-      MonoObject *okey = (MonoString*) mono_runtime_invoke(methods[2],m,values,&exc);
+      MonoString *okey = (MonoString*) mono_runtime_invoke(methods[2],m,values,&exc);
       char* key = mono_string_to_utf8(okey);
       maps* tmp=createMaps(key);
       values[0]=mono_string_new (domain, key);
-      MonoObject *content_ZMaps = (MonoString*) mono_runtime_invoke(methods[0],m,values,&exc);
-      MonoObject *content = mono_runtime_invoke(methods[6],content_ZMaps,NULL,&exc);
+      MonoString *content_ZMaps = (MonoString*) mono_runtime_invoke(methods[0],m,values,&exc);
+      MonoObject *content = mono_runtime_invoke(methods[6],(MonoObject*)content_ZMaps,NULL,&exc);
       tmp->content=mapFromZMap(domain,classes,methods,content);
       MonoObject *childs = mono_runtime_invoke(methods[7],content_ZMaps,NULL,&exc);
@@ -329,9 +393,9 @@
       values[0]=&i;
       exc=NULL;
-      MonoObject *okey = (MonoString*) mono_runtime_invoke(methods[5],m,values,&exc);
+      MonoString *okey = (MonoString*) mono_runtime_invoke(methods[5],m,values,&exc);
       char* key = mono_string_to_utf8(okey);
       values[0]=mono_string_new (domain, key);
       exc=NULL;
-      MonoObject *ovalue = (MonoString*) mono_runtime_invoke(methods[3],m,values,&exc);
+      MonoString *ovalue = (MonoString*) mono_runtime_invoke(methods[3],m,values,&exc);
       char* value = mono_string_to_utf8(ovalue);
       if(res==NULL)
@@ -350,5 +414,5 @@
  */
 static MonoString* MonoTranslate(MonoString *str){
-  return mono_string_new (mono_domain_get(), mono_string_to_utf8(_(str)));
+  return mono_string_new (mono_domain_get(), _(mono_string_to_utf8(str)));
 }
 
@@ -360,18 +424,15 @@
  * @return the translated string
  */
-static void MonoUpdateStatus(MonoObject* obj,MonoString *str,int* p){
-  MonoDomain* domain = mono_object_get_domain (obj);
-  maps *confMaps=mapsFromZMaps(domain,iclasses,imethods,obj);
-  setMapInMaps(confMaps,"lenv","message",mono_string_to_utf8(str));
-  int tmp=p;
-  if (p < 0 || p > 100){
-    tmp=-1;
-  }
-  char tmpStatus[5];
-  snprintf(tmpStatus, 4, "%d", tmp);
-  setMapInMaps(confMaps,"lenv","status",(char*)tmpStatus);
-  _updateStatus(confMaps);
-  freeMaps(&confMaps);
-  free(confMaps);
-  return;
-}
+static void MonoUpdateStatus(MonoObject* obj, MonoString *str, int p) {	
+	MonoDomain* domain = mono_object_get_domain(obj);	
+	maps *confMaps = mapsFromZMaps(domain, iclasses, imethods, obj);	
+	setMapInMaps(confMaps, "lenv", "message", mono_string_to_utf8(str));	
+	int tmp = p > 100 || p < 0 ? -1 : p;	
+	char tmpStatus[5];
+	snprintf(tmpStatus, 4, "%d", tmp);	
+	setMapInMaps(confMaps, "lenv", "status", (char*)tmpStatus);	
+	_updateStatus(confMaps);	
+	freeMaps(&confMaps);	
+	free(confMaps);
+	return;
+}
Index: trunk/zoo-project/zoo-kernel/service_internal_mono.h
===================================================================
--- trunk/zoo-project/zoo-kernel/service_internal_mono.h	(revision 889)
+++ trunk/zoo-project/zoo-kernel/service_internal_mono.h	(revision 917)
@@ -45,7 +45,8 @@
   map* mapFromZMap(MonoDomain*,MonoClass**,MonoMethod**,MonoObject*);
   static MonoString* MonoTranslate(MonoString*);
-  static void MonoUpdateStatus(MonoObject*,MonoString*,int*);
-  MonoClass *iclasses[4];
-  MonoMethod *imethods[10];
+  //static void MonoUpdateStatus(MonoObject*,MonoString*,int*);
+  static void MonoUpdateStatus(MonoObject*, MonoString*, int);
+  //MonoClass *iclasses[4]; // knut: move declarations to service_internal_mono.c
+  //MonoMethod *imethods[10];
 
 #ifdef __cplusplus
Index: trunk/zoo-project/zoo-kernel/service_internal_ms.c
===================================================================
--- trunk/zoo-project/zoo-kernel/service_internal_ms.c	(revision 889)
+++ trunk/zoo-project/zoo-kernel/service_internal_ms.c	(revision 917)
@@ -34,4 +34,5 @@
 #include "server_internal.h"
 #include "response_print.h"
+#include "caching.h"
 
 /**
@@ -76,4 +77,19 @@
 
 /**
+ * Return the current publish_id value
+ * @param elem and maps pointer on which the search occur
+ * @return the integer value of the publish_id field, if any, 0 otherwise
+ */ 
+int getPublishedId(maps* elem){
+  if(elem!=NULL && elem->content!=NULL){
+    map* myIndex=getMap(elem->content,"published_id");
+    if(myIndex!=NULL){
+      return atoi(myIndex->value);
+    }
+  }
+  return 0;
+}
+
+/**
  * Add width and height keys to an output maps containing the maximum width
  * and height for displaying the full data extent.
@@ -87,4 +103,5 @@
  */
 void setMapSize(maps* output,double minx,double miny,double maxx,double maxy){
+  int imyIndex=getPublishedId(output);
   double maxWidth=640;
   double maxHeight=480;
@@ -118,6 +135,6 @@
 #endif
   if(output!=NULL){
-    addToMap(output->content,"width",sWidth);
-    addToMap(output->content,"height",sHeight);
+    setMapArray(output->content,"width",imyIndex,sWidth);
+    setMapArray(output->content,"height",imyIndex,sHeight);
   }
 }
@@ -131,4 +148,7 @@
  */
 void setReferenceUrl(maps* m,maps* tmpI){
+  int imyIndex=getPublishedId(tmpI);
+  if(getMapArray(tmpI->content,"ref_wms_link",imyIndex)!=NULL)
+    return;
   outputMapfile(m,tmpI);
   map *msUrl=getMapFromMaps(m,"main","mapserverAddress");
@@ -138,34 +158,76 @@
     exit(-1);
   }
+  if(getMapArray(tmpI->content,"ref_wms_link",imyIndex)!=NULL)
+    return;
+  int finalProto=-1;
   map *msOgcVersion=getMapFromMaps(m,"main","msOgcVersion");
   map *dataPath=getMapFromMaps(m,"main","dataPath");
   map *sid=getMapFromMaps(m,"lenv","usid");
-  map* format=getMap(tmpI->content,"mimeType");
-  map* rformat=getMap(tmpI->content,"requestedMimeType");
-  map* width=getMap(tmpI->content,"width");
-  map* height=getMap(tmpI->content,"height");
-  map* protoMap=getMap(tmpI->content,"msOgc");
-  map* versionMap=getMap(tmpI->content,"msOgcVersion");
-  char options[3][5][25]={
+  map* format=getMapArray(tmpI->content,"mimeType",imyIndex);
+  map* rformat=getMapArray(tmpI->content,"requestedMimeType",imyIndex);
+  map* width=getMapArray(tmpI->content,"width",imyIndex);
+  map* height=getMapArray(tmpI->content,"height",imyIndex);
+  map* protoMap=getMapArray(tmpI->content,"msOgc",imyIndex);
+  map* versionMap=getMapArray(tmpI->content,"msOgcVersion",imyIndex);
+  map* datatype=getMapArray(tmpI->content,"geodatatype",imyIndex);
+  map* layerName=getMapArray(tmpI->content,"msLayer",imyIndex);
+  char options[4][5][25]={
     {"WMS","1.3.0","GetMap","layers=%s","wms_extent"},
-    {"WFS","1.1.0","GetFeature","typename=%s","wcs_extent"},
-    {"WCS","1.1.0","GetCoverage","coverage=%s","wcs_extent"}
+    {"WFS","1.0.0","GetFeature","typename=%s","wcs_extent"},
+    {"WCS","2.0.0","GetCoverage","coverageid=%s","wcs_extent"},
+    {"WCS","1.0.0","GetCoverage","coverage=%s","wcs_extent"}
   };
+  map *nbElements=getMapArray(tmpI->content,"nb_features",imyIndex);
+  if(nbElements==NULL)
+    nbElements=getMapArray(tmpI->content,"nb_pixels",imyIndex);
+  if(datatype==NULL || strncmp(datatype->value,"other",5)==0 || (nbElements!=NULL && atoi(nbElements->value)==0)){
+    map* minNb=getMap(tmpI->content,"minoccurs");
+    map* useMs=getMap(tmpI->content,"useMapserver");
+    if((minNb==NULL || atoi(minNb->value)>=1) && useMs!=NULL && strncasecmp(useMs->value,"true",4)==0){
+      int lIndex=0;
+      maps* lenv=getMaps(m,"lenv");
+      if(getMapFromMaps(m,"lenv","mapErrorNb")==NULL)
+	setMapInMaps(m,"lenv","mapErrorNb","0");
+      else{
+	map* tmpV=getMapFromMaps(m,"lenv","mapErrorNb");
+	lIndex=atoi(tmpV->value)+1;
+	addIntToMap(lenv->content,"mapErrorNb",lIndex);
+      }
+      setMapInMaps(m,"lenv","mapError","true");
+      setMapArray(lenv->content,"locator",lIndex,tmpI->name);
+      if(nbElements==NULL)
+	setMapArray(lenv->content,"message",lIndex,_("The ZOO-Kernel was able to retrieve the data but could not read it as geographic data."));
+      else
+	setMapArray(lenv->content,"message",lIndex,_("The ZOO-Kernel was able to retrieve the data but could not access any feature or pixel in te resulting file."));
+      if(getMapFromMaps(m,"lenv","state")==NULL)
+	errorException (m, _("Unable to find any geographic data"), "WrongInputData", tmpI->name);
+    }
+    return;
+  }
   int proto=0;
   if(rformat==NULL){
-    rformat=getMap(tmpI->content,"mimeType");
+    rformat=getMapArray(tmpI->content,"mimeType",imyIndex);
   }
   if(strncasecmp(rformat->value,"text/xml",8)==0)
     proto=1;
-  if(strncasecmp(rformat->value,"image/tiff",10)==0)
+  if(strncasecmp(rformat->value,"image/tiff",10)==0 ||
+     strncasecmp(rformat->value,"image/geotiff",10)==0)
     proto=2;
+  int hasFormat=-1;
   if(protoMap!=NULL){
-    if(strncasecmp(protoMap->value,"WMS",3)==0)
+    hasFormat=1;
+    if(strncasecmp(protoMap->value,"WMS",3)==0){
       proto=0;
+      rformat=createMap("value","image/png");
+    }
     else{
-      if(strncasecmp(protoMap->value,"WFS",3)==0)
+      if(strncasecmp(protoMap->value,"WFS",3)==0){
 	proto=1;
-      else 
+	rformat=createMap("value","text/xml");
+      }
+      else {
 	proto=2;
+	rformat=createMap("value","image/tiff");
+      }
     }
   }
@@ -178,6 +240,7 @@
   }
 
-  map* extent=getMap(tmpI->content,options[proto][4]);
-  map* crs=getMap(tmpI->content,"crs");
+
+  map* extent=getMapArray(tmpI->content,options[proto][4],imyIndex);
+  map* crs=getMapArray(tmpI->content,"crs",imyIndex);
   int hasCRS=1;
   if(crs==NULL){
@@ -189,14 +252,46 @@
   }
   char layers[128];
-  sprintf(layers,options[proto][3],tmpI->name);
-
-  char* webService_url=(char*)malloc((strlen(msUrl->value)+strlen(format->value)+strlen(tmpI->name)+strlen(width->value)+strlen(height->value)+strlen(extent->value)+256)*sizeof(char));
+  if(layerName==NULL)
+    sprintf(layers,options[proto][3],tmpI->name);
+  else
+    sprintf(layers,options[proto][3],layerName->value);
+
+  if(format==NULL || width==NULL || height==NULL || extent==NULL){
+    char tmpStr[1024];
+    sprintf(tmpStr,_("Unable to create the mapfile for %s because of missing values."),tmpI->name);
+    errorException (m, tmpStr,
+		    "InternalError", NULL);
+    exit(-1);
+    return;
+  }
+
+  if(proto==0){
+    hasFormat=1;
+    rformat=createMap("mimeType","image/png");
+  }else{
+    if(proto==1){
+      rformat=createMap("mimeType","text/xml");
+      hasFormat=1;
+    }
+    else
+      if(proto==2){
+        rformat=createMap("mimeType","image/tiff");
+	hasFormat=1;
+	finalProto=1;
+      }
+  }
+  
+  char* webService_url=(char*)malloc((strlen(msUrl->value)+strlen(rformat->value)+strlen(tmpI->name)+strlen(width->value)+strlen(height->value)+strlen(extent->value)+256)*sizeof(char));
+
 
   if(proto>0){
+    if(proto==2)
+      finalProto=1;
     sprintf(webService_url,
-	    "%s?map=%s/%s_%s.map&request=%s&service=%s&version=%s&%s&format=%s&bbox=%s&crs=%s",
+	    "%s?map=%s/%s_%d_%s.map&request=%s&service=%s&version=%s&%s&format=%s&bbox=%s&crs=%s",
 	    msUrl->value,
 	    dataPath->value,
 	    tmpI->name,
+	    imyIndex,
 	    sid->value,
 	    options[proto][2],
@@ -208,11 +303,22 @@
 	    crs->value
 	    );
+    if(datatype!=NULL && strncasecmp(datatype->value,"raster",6)==0){
+      setMapArray(tmpI->content,"ref_wcs_link",imyIndex,webService_url);
+    }
+    else{
+      setMapArray(tmpI->content,"ref_wfs_link",imyIndex,webService_url);
+    }
+    proto=0;
+    freeMap(&rformat);
+    free(rformat);
+    rformat=createMap("mimeType","image/png");
   }
   else{
     sprintf(webService_url,
-	    "%s?map=%s/%s_%s.map&request=%s&service=%s&version=%s&%s&width=%s&height=%s&format=%s&bbox=%s&crs=%s",
+	    "%s?map=%s/%s_%d_%s.map&request=%s&service=%s&version=%s&%s&width=%s&height=%s&format=%s&bbox=%s&crs=%s",
 	    msUrl->value,
 	    dataPath->value,
 	    tmpI->name,
+	    imyIndex,
 	    sid->value,
 	    options[proto][2],
@@ -226,4 +332,94 @@
 	    crs->value
 	    );
+    setMapArray(tmpI->content,"ref_wms_link",imyIndex,webService_url);
+    if(datatype!=NULL && strncasecmp(datatype->value,"raster",6)==0){
+      proto=2;
+      freeMap(&rformat);
+      free(rformat);
+      rformat=createMap("mimeType","image/tiff");
+    }
+    else{
+      proto=1;
+      freeMap(&rformat);
+      free(rformat);
+      rformat=createMap("mimeType","text/xml");
+    }
+  }
+  setMapArray(tmpI->content,"Reference",imyIndex,webService_url);
+  memset(layers,0,128);
+  sprintf(layers,options[proto][3],tmpI->name);
+  protoVersion=options[proto][1];
+  extent=getMapArray(tmpI->content,options[proto][4],imyIndex);
+  memset(webService_url,0,strlen(webService_url));
+  if(proto>0){
+    if(proto==2)
+      finalProto=1;
+    sprintf(webService_url,
+	    "%s?map=%s/%s_%d_%s.map&request=%s&service=%s&version=%s&%s&format=%s&bbox=%s&crs=%s",
+	    msUrl->value,
+	    dataPath->value,
+	    tmpI->name,
+	    imyIndex,
+	    sid->value,
+	    options[proto][2],
+	    options[proto][0],
+	    protoVersion,
+	    layers,
+	    rformat->value,
+	    extent->value,
+	    crs->value
+	    );
+    if(datatype!=NULL && strncasecmp(datatype->value,"raster",6)==0){
+      setMapArray(tmpI->content,"ref_wcs_link",imyIndex,webService_url);
+    }
+    else{
+      setMapArray(tmpI->content,"ref_wfs_link",imyIndex,webService_url);
+    }
+  }else{
+    sprintf(webService_url,
+	    "%s?map=%s/%s_%d_%s.map&request=%s&service=%s&version=%s&%s&width=%s&height=%s&format=%s&bbox=%s&crs=%s",
+	    msUrl->value,
+	    dataPath->value,
+	    tmpI->name,
+	    imyIndex,
+	    sid->value,
+	    options[proto][2],
+	    options[proto][0],
+	    protoVersion,
+	    layers,
+	    width->value,
+	    height->value,
+	    rformat->value,
+	    extent->value,
+	    crs->value
+	    );
+    setMapArray(tmpI->content,"ref_wms_link",imyIndex,webService_url);
+  }
+  if(finalProto>0){
+    proto=3;
+    memset(layers,0,128);
+    sprintf(layers,options[proto][3],tmpI->name);
+    protoVersion=options[proto][1];
+    extent=getMapArray(tmpI->content,options[proto][4],imyIndex);
+    memset(webService_url,0,strlen(webService_url));
+     freeMap(&rformat);
+    free(rformat);
+    rformat=createMap("value","image/tiff");
+    sprintf(webService_url,
+	    "%s?map=%s/%s_%d_%s.map&request=%s&service=%s&version=%s&%s&format=%s&bbox=%s&crs=%s",
+	    msUrl->value,
+	    dataPath->value,
+	    tmpI->name,
+	    imyIndex,
+	    sid->value,
+	    options[proto][2],
+	    options[proto][0],
+	    protoVersion,
+	    layers,
+	    rformat->value,
+	    extent->value,
+	    crs->value
+	    );
+    setMapArray(tmpI->content,"ref_wcs_preview_link",imyIndex,webService_url);
   }
   if(hasCRS==0){
@@ -231,5 +427,6 @@
     free(crs);
   }
-  addToMap(tmpI->content,"Reference",webService_url);
+  freeMap(&rformat);
+  free(rformat);
   free(webService_url);
 }
@@ -249,4 +446,5 @@
   OGRSpatialReferenceH  hSRS;
   map* msSrs=NULL;
+  int imyIndex=getPublishedId(output);
   hSRS = OSRNewSpatialReference(NULL);
   if( pszProjection!=NULL && strlen(pszProjection)>1){
@@ -272,8 +470,8 @@
 	if(output!=NULL){
 	  if(OSRIsGeographic(hSRS)==TRUE)
-	    addToMap(output->content,"crs_isGeographic","true");
+	    setMapArray(output->content,"crs_isGeographic",imyIndex,"true");
 	  else
-	    addToMap(output->content,"crs_isGeographic","false");
-	  addToMap(output->content,"crs",tmpSrs);
+	    setMapArray(output->content,"crs_isGeographic",imyIndex,"false");
+	  setMapArray(output->content,"crs",imyIndex,tmpSrs);
 	}
       }
@@ -288,7 +486,7 @@
 	  if(output!=NULL){ 
 	    if(OSRIsGeographic(hSRS)==TRUE)
-	      addToMap(output->content,"crs_isGeographic","true");
+	      setMapArray(output->content,"crs_isGeographic",imyIndex,"true");
 	    else
-	      addToMap(output->content,"crs_isGeographic","false");
+	      setMapArray(output->content,"crs_isGeographic",imyIndex,"false");
 	  }
 	  free(proj4Str);
@@ -298,10 +496,10 @@
 	  msLoadProjectionStringEPSG(&myLayer->projection,"EPSG:4326");
 	  if(output!=NULL){
-	    addToMap(output->content,"crs_isGeographic","true");
+	    setMapArray(output->content,"crs_isGeographic",imyIndex,"true");
 	  }
 	}
 	if(output!=NULL){
-	  addToMap(output->content,"crs","EPSG:4326");
-	  addToMap(output->content,"real_extent","true");
+	  setMapArray(output->content,"crs",imyIndex,"EPSG:4326");
+	  setMapArray(output->content,"real_extent",imyIndex,"true");
 	}
 	msInsertHashTable(&(m->web.metadata),"ows_srs", "EPSG:4326 EPSG:900913 EPSG:3857");
@@ -312,5 +510,5 @@
   else{
     if(output!=NULL){
-      msSrs=getMap(output->content,"msSrs");
+      msSrs=getMapArray(output->content,"msSrs",imyIndex);
     }
     if(msSrs!=NULL){
@@ -328,6 +526,6 @@
     }
     if(output!=NULL){
-      addToMap(output->content,"crs",msSrs->value);
-      addToMap(output->content,"crs_isGeographic","true");
+      setMapArray(output->content,"crs",imyIndex,msSrs->value);
+      setMapArray(output->content,"crs_isGeographic",imyIndex,"true");
     }
   }
@@ -351,5 +549,7 @@
 void setMsExtent(maps* output,mapObj* m,layerObj* myLayer,
 		 double minX,double minY,double maxX,double maxY){
+  int imyIndex=getPublishedId(output);
   msMapSetExtent(m,minX,minY,maxX,maxY);
+  //m->maxsize=4096;
 #ifdef DEBUGMS
   fprintf(stderr,"Extent %.15f %.15f %.15f %.15f\n",minX,minY,maxX,maxY);
@@ -363,32 +563,40 @@
   
   if(output!=NULL){
-    map* test=getMap(output->content,"real_extent");
+    map* test=getMapArray(output->content,"real_extent",imyIndex);
+    pointObj min, max;
+    projectionObj tempSrs;
+    min.x = m->extent.minx;
+    min.y = m->extent.miny;
+    max.x = m->extent.maxx;
+    max.y = m->extent.maxy;
+    char tmpSrsStr[1024];
+    msInitProjection(&tempSrs);
+    msLoadProjectionStringEPSG(&tempSrs,"EPSG:4326");
+
+    msProjectPoint(&(myLayer->projection),&tempSrs,&min);
+    msProjectPoint(&myLayer->projection,&tempSrs,&max);
+  
     if(test!=NULL){
-      pointObj min, max;
-      projectionObj tempSrs;
-      min.x = m->extent.minx;
-      min.y = m->extent.miny;
-      max.x = m->extent.maxx;
-      max.y = m->extent.maxy;
-      char tmpSrsStr[1024];
-      msInitProjection(&tempSrs);
-      msLoadProjectionStringEPSG(&tempSrs,"EPSG:4326");
-
-      msProjectPoint(&(m->projection),&tempSrs,&min);
-      msProjectPoint(&m->projection,&tempSrs,&max);
-      
-      sprintf(tmpExtent,"%.3f,%.3f,%.3f,%.3f",min.y,min.x,max.y,max.x);
-      map* isGeo=getMap(output->content,"crs_isGeographic");
+      sprintf(tmpExtent,"%.15f,%.15f,%.15f,%.15f",min.y,min.x,max.y,max.x);
+      map* isGeo=getMapArray(output->content,"crs_isGeographic",imyIndex);
 #ifdef DEBUGMS
       fprintf(stderr,"isGeo = %s\n",isGeo->value);
 #endif
-      if(isGeo!=NULL && strcasecmp("true",isGeo->value)==0)
-        sprintf(tmpExtent,"%f,%f,%f,%f", minY,minX, maxY, maxX);
-      addToMap(output->content,"wms_extent",tmpExtent);
-      sprintf(tmpSrsStr,"%.3f,%.3f,%.3f,%.3f",min.x,min.y,max.x,max.y);
-      addToMap(output->content,"wcs_extent",tmpExtent);
+      if(isGeo!=NULL && strcasecmp("true",isGeo->value)==0){
+	sprintf(tmpExtent,"%.15f,%.15f,%.15f,%.15f",min.y,min.x,max.y,max.x);
+	setMapArray(output->content,"wgs84_extent",imyIndex,tmpExtent);
+        sprintf(tmpExtent,"%.15f,%.15f,%.15f,%.15f", minY,minX, maxY, maxX);
+      }else{
+	sprintf(tmpExtent,"%.15f,%.15f,%.15f,%.15f",min.x,min.y,max.x,max.y);
+	setMapArray(output->content,"wgs84_extent",imyIndex,tmpExtent);
+      }
+      setMapArray(output->content,"wms_extent",imyIndex,tmpExtent);
+      sprintf(tmpSrsStr,"%.15f,%.15f,%.15f,%.15f",min.x,min.y,max.x,max.y);
+      setMapArray(output->content,"wcs_extent",imyIndex,tmpExtent);
     }else{
-      sprintf(tmpExtent,"%f,%f,%f,%f",minX, minY, maxX, maxY);
-      map* isGeo=getMap(output->content,"crs_isGeographic");
+      sprintf(tmpExtent,"%.15f,%.15f,%.15f,%.15f",min.x,min.y,max.x,max.y);
+      setMapArray(output->content,"wgs84_extent",imyIndex,tmpExtent);
+      sprintf(tmpExtent,"%.15f,%.15f,%.15f,%.15f",minX, minY, maxX, maxY);
+      map* isGeo=getMapArray(output->content,"crs_isGeographic",imyIndex);
       if(isGeo!=NULL){
 #ifdef DEBUGMS
@@ -396,9 +604,9 @@
 #endif
 	if(isGeo!=NULL && strcasecmp("true",isGeo->value)==0)
-	  sprintf(tmpExtent,"%f,%f,%f,%f", minY,minX, maxY, maxX);
-      }
-      addToMap(output->content,"wms_extent",tmpExtent); 
-      sprintf(tmpExtent,"%.3f,%.3f,%.3f,%.3f",minX,minY,maxX,maxY);
-      addToMap(output->content,"wcs_extent",tmpExtent);
+	  sprintf(tmpExtent,"%.15f,%.15f,%.15f,%.15f", minY,minX, maxY, maxX);
+      }
+      setMapArray(output->content,"wms_extent",imyIndex,tmpExtent); 
+      sprintf(tmpExtent,"%.15f,%.15f,%.15f,%.15f",minX,minY,maxX,maxY);
+      setMapArray(output->content,"wcs_extent",imyIndex,tmpExtent);
     }
   }
@@ -415,6 +623,6 @@
  */
 int tryOgr(maps* conf,maps* output,mapObj* m){
-
-  map* tmpMap=getMap(output->content,"storage");
+  int imyIndex=getPublishedId(output);
+  map* tmpMap=getMapArray(output->content,"storage",imyIndex);
   char *pszDataSource=tmpMap->value;
 
@@ -425,6 +633,5 @@
   /**
    * Try to load the file as ZIP
-   */
-
+   *
   OGRDataSourceH poDS1 = NULL;
   OGRSFDriverH *poDriver1 = NULL;
@@ -467,5 +674,7 @@
     fprintf(stderr,"Unable to access the DataSource as ZIP File\n");
     setMapInMaps(conf,"lenv","message","Unable to open datasource in read only mode");
-    OGR_DS_Destroy(poDS1);
+    fprintf(stderr,"Remove ZIP File!\n");
+    unlink(odsName);
+    //OGR_DS_Destroy(poDS1);
   }else{
 #ifdef DEBUGMS
@@ -526,8 +735,9 @@
       i++;
     }
-  }
+    OGR_DS_Destroy(poDS1);
+    }
   free(sdsName);
-  free(dsName);
-
+  free(dsName);*/
+  
   OGRDataSourceH poDS = NULL;
   OGRSFDriverH *poDriver = NULL;
@@ -538,6 +748,4 @@
 #endif
     setMapInMaps(conf,"lenv","message","Unable to open datasource in read only mode");
-    OGR_DS_Destroy(poDS);
-    OGRCleanupAll();
 #ifdef DEBUGMS
     fprintf(stderr,"Unable to access the DataSource, exit! \n"); 
@@ -546,4 +754,6 @@
   }
 
+  setMapArray(output->content,"gdalType",imyIndex,OGR_Dr_GetName(OGR_DS_GetDriver(poDS)));  
+  setMapArray(output->content,"geodatatype",imyIndex,"vector");
   int iLayer = 0;
   for( iLayer=0; iLayer < OGR_DS_GetLayerCount(poDS); iLayer++ ){
@@ -561,12 +771,17 @@
      * Add a new layer set name, data
      */
-    if(msGrowMapLayers(m)==NULL){
-      return -1;
-    }
-    if(initLayer((m->layers[m->numlayers]), m) == -1){
-      return -1;
-    }
-
-    layerObj* myLayer=m->layers[m->numlayers];
+    layerObj* myLayer=NULL;
+    if(getMapArray(output->content,"msInclude",imyIndex)==NULL){
+      if(msGrowMapLayers(m)==NULL){
+	return -1;
+      }
+      if(initLayer((m->layers[m->numlayers]), m) == -1){
+	return -1;
+      }
+      myLayer=m->layers[m->numlayers];
+    }else{
+      myLayer=m->layers[m->numlayers-1];
+    }
+    
 #ifdef DEBUGMS
     dumpMaps(output);
@@ -580,4 +795,6 @@
     myLayer->status = MS_ON;
     msConnectLayer(myLayer,MS_OGR,pszDataSource);
+
+    addIntToMapArray(output->content,"nb_features",imyIndex,OGR_L_GetFeatureCount(poLayer,1));
 
     /**
@@ -631,6 +848,6 @@
     }
     else{
-      addToMap(output->content,"crs","EPSG:4326");
-      addToMap(output->content,"crs_isGeographic","true");
+      setMapArray(output->content,"crs",imyIndex,"EPSG:4326");
+      setMapArray(output->content,"crs_isGeographic",imyIndex,"true");
       msLoadProjectionStringEPSG(&m->projection,"EPSG:4326");
       msInsertHashTable(&(m->web.metadata), "ows_srs", "EPSG:4326 EPSG:900913 EPSG:3857");
@@ -641,4 +858,8 @@
     if (OGR_L_GetExtent(poLayer,&oExt, TRUE) == OGRERR_NONE){
       setMsExtent(output,m,myLayer,oExt.MinX, oExt.MinY, oExt.MaxX, oExt.MaxY);
+      char extent[1024];
+      memset(&extent,0,1024);
+      sprintf(extent,"%d,%d,%d,%d",oExt.MinX, oExt.MinY, oExt.MaxX, oExt.MaxY);
+      setMapArray(output->content,"boundingbox",imyIndex,extent);
     }
   
@@ -659,60 +880,74 @@
     msInsertHashTable(&(myLayer->metadata), "gml_include_items", "all");
     msInsertHashTable(&(myLayer->metadata), "ows_name", output->name);
-    map* tmpMap=getMap(output->content,"title");
+    map* tmpMap=getMapArray(output->content,"title",imyIndex);
     if(tmpMap!=NULL)
       msInsertHashTable(&(myLayer->metadata), "ows_title", tmpMap->value);
     else
       msInsertHashTable(&(myLayer->metadata), "ows_title", "Default Title");
+
+    if(getMapArray(output->content,"msInclude",imyIndex)==NULL){
+      if(msGrowLayerClasses(myLayer) == NULL)
+	return -1;
+      if(initClass((myLayer->CLASS[myLayer->numclasses])) == -1)
+	return -1;
+      if(msGrowClassStyles(myLayer->CLASS[myLayer->numclasses]) == NULL)
+	return -1;
+      if(initStyle(myLayer->CLASS[myLayer->numclasses]->styles[myLayer->CLASS[myLayer->numclasses]->numstyles]) == -1)
+	return -1;
+      /**
+       * Apply msStyle else fallback to the default style
+       */
+      tmpMap=getMap(output->content,"msStyle");
+      if(tmpMap==NULL){
+        switch(myLayer->type){
+	case MS_LAYER_POLYGON:
+	  tmpMap=getMapFromMaps(conf,"main","msStylePoly");
+	  break;
+	case MS_LAYER_LINE:
+	  tmpMap=getMapFromMaps(conf,"main","msStyleLine");
+	  break;
+	default:
+	  tmpMap=getMapFromMaps(conf,"main","msStylePoint");
+	  break;
+        }
+      }
+      if(tmpMap!=NULL)
+	msUpdateStyleFromString(myLayer->CLASS[myLayer->numclasses]->styles[myLayer->CLASS[myLayer->numclasses]->numstyles],tmpMap->value,0);
+      else{
+	/**
+	 * Set style
+	 */
+	myLayer->CLASS[myLayer->numclasses]->styles[myLayer->CLASS[myLayer->numclasses]->numstyles]->color.red=125;
+	myLayer->CLASS[myLayer->numclasses]->styles[myLayer->CLASS[myLayer->numclasses]->numstyles]->color.green=125;
+	myLayer->CLASS[myLayer->numclasses]->styles[myLayer->CLASS[myLayer->numclasses]->numstyles]->color.blue=255;
+	myLayer->CLASS[myLayer->numclasses]->styles[myLayer->CLASS[myLayer->numclasses]->numstyles]->outlinecolor.red=80;
+	myLayer->CLASS[myLayer->numclasses]->styles[myLayer->CLASS[myLayer->numclasses]->numstyles]->outlinecolor.green=80;
+	myLayer->CLASS[myLayer->numclasses]->styles[myLayer->CLASS[myLayer->numclasses]->numstyles]->outlinecolor.blue=80;
+	
+	/**
+	 * Set specific style depending on type
+	 */
+	if(myLayer->type == MS_LAYER_POLYGON)
+	  myLayer->CLASS[myLayer->numclasses]->styles[myLayer->CLASS[myLayer->numclasses]->numstyles]->width=3;
+	if(myLayer->type == MS_LAYER_LINE){
+	  myLayer->CLASS[myLayer->numclasses]->styles[myLayer->CLASS[myLayer->numclasses]->numstyles]->width=3;
+	  myLayer->CLASS[myLayer->numclasses]->styles[myLayer->CLASS[myLayer->numclasses]->numstyles]->outlinewidth=1.5;
+	}
+	if(myLayer->type == MS_LAYER_POINT){
+	  myLayer->CLASS[myLayer->numclasses]->styles[myLayer->CLASS[myLayer->numclasses]->numstyles]->symbol=1;
+	  myLayer->CLASS[myLayer->numclasses]->styles[myLayer->CLASS[myLayer->numclasses]->numstyles]->size=15;
+	}
+	
+      }
+      myLayer->CLASS[myLayer->numclasses]->numstyles++;
+      myLayer->numclasses++;
     
-    if(msGrowLayerClasses(myLayer) == NULL)
-      return -1;
-    if(initClass((myLayer->CLASS[myLayer->numclasses])) == -1)
-      return -1;
-    if(msGrowClassStyles(myLayer->CLASS[myLayer->numclasses]) == NULL)
-      return -1;
-    if(initStyle(myLayer->CLASS[myLayer->numclasses]->styles[myLayer->CLASS[myLayer->numclasses]->numstyles]) == -1)
-      return -1;
-    /**
-     * Apply msStyle else fallback to the default style
-     */
-    tmpMap=getMap(output->content,"msStyle");
-    if(tmpMap!=NULL)
-      msUpdateStyleFromString(myLayer->CLASS[myLayer->numclasses]->styles[myLayer->CLASS[myLayer->numclasses]->numstyles],tmpMap->value,0);
-    else{
-      /**
-       * Set style
-       */
-      myLayer->CLASS[myLayer->numclasses]->styles[myLayer->CLASS[myLayer->numclasses]->numstyles]->color.red=125;
-      myLayer->CLASS[myLayer->numclasses]->styles[myLayer->CLASS[myLayer->numclasses]->numstyles]->color.green=125;
-      myLayer->CLASS[myLayer->numclasses]->styles[myLayer->CLASS[myLayer->numclasses]->numstyles]->color.blue=255;
-      myLayer->CLASS[myLayer->numclasses]->styles[myLayer->CLASS[myLayer->numclasses]->numstyles]->outlinecolor.red=80;
-      myLayer->CLASS[myLayer->numclasses]->styles[myLayer->CLASS[myLayer->numclasses]->numstyles]->outlinecolor.green=80;
-      myLayer->CLASS[myLayer->numclasses]->styles[myLayer->CLASS[myLayer->numclasses]->numstyles]->outlinecolor.blue=80;
-      
-      /**
-       * Set specific style depending on type
-       */
-      if(myLayer->type == MS_LAYER_POLYGON)
-	myLayer->CLASS[myLayer->numclasses]->styles[myLayer->CLASS[myLayer->numclasses]->numstyles]->width=3;
-      if(myLayer->type == MS_LAYER_LINE){
-	myLayer->CLASS[myLayer->numclasses]->styles[myLayer->CLASS[myLayer->numclasses]->numstyles]->width=3;
-	myLayer->CLASS[myLayer->numclasses]->styles[myLayer->CLASS[myLayer->numclasses]->numstyles]->outlinewidth=1.5;
-      }
-      if(myLayer->type == MS_LAYER_POINT){
-	myLayer->CLASS[myLayer->numclasses]->styles[myLayer->CLASS[myLayer->numclasses]->numstyles]->symbol=1;
-	myLayer->CLASS[myLayer->numclasses]->styles[myLayer->CLASS[myLayer->numclasses]->numstyles]->size=15;
-      }
-      
-    }
-    myLayer->CLASS[myLayer->numclasses]->numstyles++;
-    myLayer->numclasses++;
-    
-    m->layerorder[m->numlayers] = m->numlayers;
-    m->numlayers++;
-
-  }
-
+      m->layerorder[m->numlayers] = m->numlayers;
+      m->numlayers++;
+
+    }
+  }
   OGR_DS_Destroy(poDS);
-  OGRCleanupAll();
+  //OGRCleanupAll();
 
   return 1;
@@ -727,5 +962,7 @@
  */
 int tryGdal(maps* conf,maps* output,mapObj* m){
-  map* tmpMap=getMap(output->content,"storage");
+  int imyIndex=getPublishedId(output);
+  map* tmpMap=getMapArray(output->content,"storage",imyIndex);
+  map* styleMap=getMap(output->content,"msStyle");
   char *pszFilename=tmpMap->value;
   GDALDatasetH hDataset;
@@ -738,9 +975,10 @@
    */
   GDALAllRegister();
-  hDataset = GDALOpen( pszFilename, GA_ReadOnly );
+  hDataset = GDALOpen( pszFilename, GA_Update ); /*GA_ReadOnly*/
   if( hDataset == NULL ){
 #ifdef DEBUGMS
     fprintf(stderr,"Unable to access the DataSource %s \n",pszFilename);
 #endif
+    setMapArray(output->content,"geodatatype",imyIndex,"other");
     setMapInMaps(conf,"lenv","message","gdalinfo failed - unable to open");
     GDALDestroyDriverManager();
@@ -751,4 +989,5 @@
 #endif
 
+  setMapArray(output->content,"geodatatype",imyIndex,"raster");
   /**
    * Add a new layer set name, data
@@ -772,9 +1011,9 @@
 
   char *title=output->name;
-  tmpMap=getMap(output->content,"title");
+  tmpMap=getMapArray(output->content,"title",imyIndex);
   if(tmpMap!=NULL)
     title=tmpMap->value;
   char *abstract=output->name;
-  tmpMap=getMap(output->content,"abstract");
+  tmpMap=getMapArray(output->content,"abstract",imyIndex);
   if(tmpMap!=NULL)
     abstract=tmpMap->value;
@@ -791,5 +1030,24 @@
   m->width=GDALGetRasterXSize( hDataset );
   m->height=GDALGetRasterYSize( hDataset );
-  
+  if(m->width>4096 || m->height>4096){
+    if(m->width>m->height)
+      m->maxsize=m->width;
+    else  
+      m->maxsize=m->height;
+  }else
+    m->maxsize=4096;
+  addIntToMapArray(output->content,"nb_pixels",imyIndex,GDALGetRasterXSize( hDataset )*GDALGetRasterYSize( hDataset ));
+  int pixel_type=GDALGetRasterDataType( hDataset );
+  addIntToMapArray(output->content,"pixel_data_type",imyIndex,pixel_type);
+
+  int outputIndex=msGetOutputFormatIndex(m,"tiff");
+  if(outputIndex>=0){
+    m->outputformatlist[outputIndex]->imagemode=((pixel_type==GDT_Byte)?MS_IMAGEMODE_BYTE:((pixel_type==GDT_Int16 || pixel_type==GDT_UInt16)?MS_IMAGEMODE_INT16:((pixel_type!=GDT_Float32)?MS_IMAGEMODE_FLOAT32:MS_IMAGEMODE_BYTE)));
+    outputIndex=msGetOutputFormatIndex(m,"geotiff");
+    if(outputIndex>=0)
+      m->outputformatlist[outputIndex]->imagemode=((pixel_type==GDT_Byte)?MS_IMAGEMODE_BYTE:((pixel_type==GDT_Int16 || pixel_type==GDT_UInt16)?MS_IMAGEMODE_INT16:((pixel_type!=GDT_Float32)?MS_IMAGEMODE_FLOAT32:MS_IMAGEMODE_BYTE)));
+  }
+  //
+    
   /**
    * Set projection using Authority Code and Name if available or fallback to 
@@ -805,7 +1063,11 @@
     setSrsInformations(output,m,myLayer,pszProjection);
   }else{
-    fprintf(stderr,"NO SRS FOUND ! %s\n",GDALGetProjectionRef( hDataset ));    
-  }
-
+    fprintf(stderr,"NO SRS FOUND %s %d ! %s\n",__FILE__,__LINE__,GDALGetProjectionRef( hDataset ));
+    fflush(stderr);
+    CPLErr sp=GDALSetProjection( hDataset , "+init=epsg:4326" );
+    if(sp!=CE_None){
+      fprintf(stderr,"NO SRS SET ! %s\n",CPLGetLastErrorMsg());
+    }
+  }
 
   /**
@@ -825,7 +1087,18 @@
 	+ adfGeoTransform[4] * GDALGetRasterXSize(hDataset);
 
-       setMsExtent(output,m,myLayer,minX,minY,maxX,maxY);
-
-    }
+      setMsExtent(output,m,myLayer,minX,minY,maxX,maxY);
+      char extent[1024];
+      memset(&extent,0,1024);
+      sprintf(extent,"%d,%d,%d,%d",minX,minY,maxX,maxY);
+      setMapArray(output->content,"boundingbox",imyIndex,extent);
+    }
+  }else{
+    int scale=1;
+    if(m->width>2048){
+      addIntToMapArray(output->content,"width",imyIndex,2048);
+      scale=2048/m->width;
+    }else
+      addIntToMapArray(output->content,"width",imyIndex,m->width);
+    addIntToMapArray(output->content,"height",imyIndex,m->height*scale);
   }
 
@@ -835,13 +1108,21 @@
    */
   char nBands[3];
+  memset(&nBands,0,3);
   int nBandsI=GDALGetRasterCount( hDataset );
-  sprintf(nBands,"%d",GDALGetRasterCount( hDataset ));
-  msInsertHashTable(&(myLayer->metadata), "ows_bandcount", nBands);
-  if(nBandsI>=3)
-    msLayerAddProcessing(myLayer,"BANDS=1,2,3");
-  else if(nBandsI>=2)
-    msLayerAddProcessing(myLayer,"BANDS=1,2");
-  else
-    msLayerAddProcessing(myLayer,"BANDS=1");
+  if(nBandsI<100){
+    sprintf(nBands,"%d",GDALGetRasterCount( hDataset ));
+    msInsertHashTable(&(myLayer->metadata), "ows_bandcount", nBands);
+  }
+  if(styleMap==NULL || strstr(styleMap->value,"BANDS=")==NULL){
+    if(nBandsI>=3)
+      if(nBandsI==4)
+	msLayerAddProcessing(myLayer,"BANDS=1,2,3,4");
+      else
+	msLayerAddProcessing(myLayer,"BANDS=1,2,3");
+    else if(nBandsI>=2)
+      msLayerAddProcessing(myLayer,"BANDS=1,2");
+    else
+      msLayerAddProcessing(myLayer,"BANDS=1");
+  }
 
   /**
@@ -851,12 +1132,13 @@
   char *nameBands=NULL;
   for( iBand = 0; iBand < nBandsI; iBand++ ){
-    sprintf(lBands,"Band%d",iBand+1);
+    memset(&lBands,0,7);
+    sprintf(lBands,"Band%d",iBand+1);    
     if(nameBands==NULL){
       nameBands=(char*)malloc((strlen(lBands)+1)*sizeof(char));
       sprintf(nameBands,"%s",lBands);
     }else{
-      if(iBand<4){
+      /*if(iBand<4)*/{
 	char *tmpS=zStrdup(nameBands);
-	nameBands=(char*)realloc(nameBands,(strlen(nameBands)+strlen(lBands)+1)*sizeof(char));
+	nameBands=(char*)realloc(nameBands,(strlen(tmpS)+strlen(lBands)+2)*sizeof(char));
 	sprintf(nameBands,"%s %s",tmpS,lBands);
 	free(tmpS);
@@ -864,27 +1146,36 @@
     }
   }
-  msInsertHashTable(&(myLayer->metadata), "ows_bandnames", nameBands);
-  
+  if(nameBands!=NULL){
+    msInsertHashTable(&(myLayer->metadata), "ows_bandnames", nameBands);
+    free(nameBands);
+  }
+
   /**
    * Loops over metadata information to setup specific information
    */
   for( iBand = 0; iBand < nBandsI; iBand++ ){
-    //int         bGotNodata;//, bSuccess;
-    double      adfCMinMax[2]/*, dfNoData*/;
-    //int         nBlockXSize, nBlockYSize, nMaskFlags;
-    //double      /*dfMean, dfStdDev*/;
+    double      pdfMin, pdfMax, pdfMean, pdfStdDev;
     hBand = GDALGetRasterBand( hDataset, iBand+1 );
 
     CPLErrorReset();
-    GDALComputeRasterMinMax( hBand, FALSE, adfCMinMax );
+    GDALGetRasterStatistics( hBand, TRUE, TRUE, &pdfMin, &pdfMax, &pdfMean, &pdfStdDev);
     char tmpN[21];
     sprintf(tmpN,"Band%d",iBand+1);
     if (CPLGetLastErrorType() == CE_None){
-      char tmpMm[100];
-      sprintf(tmpMm,"%.3f %.3f",adfCMinMax[0],adfCMinMax[1]);
-      char tmpI[21];
+      char tmpMm[100],tmpMp[100],tmpNb[3];
+      sprintf(tmpMm,"%.3f %.3f",pdfMin,pdfMax);
+      if(pdfMin!=pdfMax && (styleMap==NULL || strstr(styleMap->value,"SCALE_")==NULL)){
+        sprintf(tmpNb,"%d",iBand+1);
+        if(styleMap==NULL || strstr(styleMap->value,"BANDS=")==NULL || strstr(strstr(styleMap->value,"BANDS="),tmpNb)!=NULL){ 
+	  if(pdfMean-(2*pdfStdDev)<0)
+	    sprintf(tmpMp,"SCALE_%d=%.3f,%.3f",iBand+1,0.0,pdfMean+(2*pdfStdDev));
+	  else
+	    sprintf(tmpMp,"SCALE_%d=%.3f,%.3f",iBand+1,pdfMean-(2*pdfStdDev),pdfMean+(2*pdfStdDev));
+	  msLayerAddProcessing(myLayer,tmpMp);
+        }
+      }
+      char tmpI[31];      
       sprintf(tmpI,"%s_interval",tmpN);
       msInsertHashTable(&(myLayer->metadata), tmpI, tmpMm);
-
       map* test=getMap(output->content,"msClassify");
       if(test!=NULL && strncasecmp(test->value,"true",4)==0){
@@ -906,7 +1197,7 @@
 	  
 	if(nBandsI==1){
-	  double delta=adfCMinMax[1]-adfCMinMax[0];
+	  double delta=pdfMax-pdfMin;
 	  double interval=delta/10;
-	  double cstep=adfCMinMax[0];
+	  double cstep=pdfMin;
 	  for(i=0;i<10;i++){
 	    /**
@@ -952,5 +1243,5 @@
 	  
 	  char tmpMm[100];
-	  sprintf(tmpMm,"%.3f %.3f",adfCMinMax[0],adfCMinMax[1]);
+	  sprintf(tmpMm,"%.3f %.3f",pdfMin,pdfMax);
 	  
 	}
@@ -962,9 +1253,8 @@
 	  myLayer->offsite.blue=0;
 	}
-	msLayerAddProcessing(myLayer,"RESAMPLE=BILINEAR");
       }
     }
     if( strlen(GDALGetRasterUnitType(hBand)) > 0 ){
-      char tmpU[21];
+      char tmpU[31];
       sprintf(tmpU,"%s_band_uom",tmpN);
       msInsertHashTable(&(myLayer->metadata), tmpU, GDALGetRasterUnitType(hBand));
@@ -972,5 +1262,11 @@
 
   }
-
+  if(styleMap==NULL || strstr(styleMap->value,"RESAMPLE")==NULL)
+    msLayerAddProcessing(myLayer,"RESAMPLE=BILINEAR");
+  
+  if(styleMap!=NULL && strlen(styleMap->value)>9){
+    msUpdateLayerFromString(myLayer,styleMap->value,MS_FALSE);
+  }
+  
   m->layerorder[m->numlayers] = m->numlayers;
   m->numlayers++;
@@ -978,4 +1274,5 @@
   GDALDestroyDriverManager();
   CPLCleanupTLS();
+  storeMd5(pszFilename);
   return 1;
 }
@@ -988,9 +1285,11 @@
  */
 void outputMapfile(maps* conf,maps* outputs){
-
   /**
    * First store the value on disk
    */
-  map* mime=getMap(outputs->content,"mimeType");
+  int imyIndex=getPublishedId(outputs);
+  map* mime=getMapArray(outputs->content,"mimeType",imyIndex);
+  map* msUrl=getMapFromMaps(conf,"main","mapserverAddress");
+  map* dataPath=getMapFromMaps(conf,"main","dataPath");
   char *ext="data";
   if(mime!=NULL)
@@ -998,29 +1297,47 @@
       ext="json";
 
-  map* tmpMap=getMapFromMaps(conf,"main","dataPath");
-  map* sidMap=getMapFromMaps(conf,"lenv","usid");
-  char *pszDataSource=(char*)malloc((strlen(tmpMap->value)+strlen(sidMap->value)+strlen(outputs->name)+17)*sizeof(char));
-  sprintf(pszDataSource,"%s/ZOO_DATA_%s_%s.%s",tmpMap->value,outputs->name,sidMap->value,ext); 
-  int f=zOpen(pszDataSource,O_WRONLY|O_CREAT,S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH);
-  map *gfile=getMap(outputs->content,"generated_file");
-  if(gfile!=NULL){
-    readGeneratedFile(conf,outputs->content,gfile->value);	    
-  }
-  map* sizeMap=getMap(outputs->content,"size");
-  map* vData=getMap(outputs->content,"value");
-  if(sizeMap!=NULL){
-    zWrite(f,vData->value,atoi(sizeMap->value)*sizeof(char));
-  }
-  else{
-    zWrite(f,vData->value,(strlen(vData->value)+1)*sizeof(char));
-  }
-  close(f);
-  addToMap(outputs->content,"storage",pszDataSource);
-  free(pszDataSource);
+  map* storage=getMapArray(outputs->content,"storage",imyIndex);
+  if(storage==NULL){
+    map* tmpMap=getMapFromMaps(conf,"main","dataPath");
+    map* sidMap=getMapFromMaps(conf,"lenv","usid");
+    char *pszDataSource=(char*)malloc((strlen(tmpMap->value)+strlen(sidMap->value)+strlen(outputs->name)+17)*sizeof(char));
+    sprintf(pszDataSource,"%s/ZOO_DATA_%d_%s_%s.%s",tmpMap->value,imyIndex,outputs->name,sidMap->value,ext);
+    int f=zOpen(pszDataSource,O_WRONLY|O_CREAT,S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH);
+    map *gfile=getMapArray(outputs->content,"generated_file",imyIndex);
+    if(gfile!=NULL){
+      readGeneratedFile(conf,outputs->content,gfile->value);	    
+    }
+    map* sizeMap=getMapArray(outputs->content,"size",imyIndex);
+    map* vData=getMapArray(outputs->content,"value",imyIndex);
+    if(sizeMap!=NULL){
+      zWrite(f,vData->value,atoi(sizeMap->value)*sizeof(char));
+    }
+    else{
+      zWrite(f,vData->value,(strlen(vData->value)+1)*sizeof(char));
+    }
+    close(f);
+    setMapArray(outputs->content,"storage",imyIndex,pszDataSource);
+    free(pszDataSource);
+  }
 
   /*
    * Create an empty map, set name, default size and extent
    */
-  mapObj *myMap=msNewMapObj();
+  map* mapfileTemplate=getMapArray(outputs->content,"msInclude",imyIndex);
+  mapObj *myMap=NULL;
+  if(mapfileTemplate==NULL){
+    myMap=msNewMapObj();
+  }
+  else{
+    map* dataPath=getMapFromMaps(conf,"main","dataPath");
+    map* sid=getMapFromMaps(conf,"lenv","sid");
+    char *mapfileTemplatePath=(char*)malloc(((strlen(dataPath->value)+strlen(sid->value)+strlen(outputs->name)+10)*sizeof(char)));
+    sprintf(mapfileTemplatePath,"%s/%s_%s.map",dataPath->value,outputs->name,sid->value);
+    myMap=msLoadMap(mapfileTemplate->value,mapfileTemplatePath);
+    if(myMap==NULL){
+      setMapInMaps(conf,"lenv","message",_("Unable to open your template mapfile!"));
+      return ;
+    }
+  }
   free(myMap->name);
   myMap->name=zStrdup("ZOO-Project_WXS_Server");
@@ -1048,7 +1365,12 @@
 #ifdef USE_KML
   outputFormatObj *o2=msCreateDefaultOutputFormat(NULL,"KML","kml");
-  o2->inmapfile=MS_TRUE;  
-  msAppendOutputFormat(myMap,msCloneOutputFormat(o2));
-  msFreeOutputFormat(o2);
+  if(!o2){
+    perror("Unable to initialize KML driver");
+    fprintf(stderr,"Unable to initialize KML driver !\n");
+  }else{
+    o2->inmapfile=MS_TRUE;  
+    msAppendOutputFormat(myMap,msCloneOutputFormat(o2));
+    msFreeOutputFormat(o2);
+  }
 #endif
 
@@ -1057,5 +1379,5 @@
     fprintf(stderr,"Unable to initialize GDAL driver !\n");
   else{
-    o3->imagemode=MS_IMAGEMODE_BYTE;
+    o3->imagemode=MS_IMAGEMODE_INT16;
     o3->inmapfile=MS_TRUE;  
     msAppendOutputFormat(myMap,msCloneOutputFormat(o3));
@@ -1067,5 +1389,5 @@
     fprintf(stderr,"Unable to initialize GDAL driver !\n");
   else{
-    o4->imagemode=MS_IMAGEMODE_INT16;
+    o4->imagemode=MS_IMAGEMODE_BYTE;
     o4->inmapfile=MS_TRUE;  
     msAppendOutputFormat(myMap,msCloneOutputFormat(o4));
@@ -1086,4 +1408,17 @@
 #endif
 
+  
+  outputFormatObj *o6=msCreateDefaultOutputFormat(NULL,"GDAL/GTiff","geotiff");
+  if(!o6)
+    fprintf(stderr,"Unable to initialize GDAL driver !\n");
+  else{
+    o6->imagemode=MS_IMAGEMODE_BYTE;
+    o6->mimetype=strdup("image/geotiff");
+    o6->inmapfile=MS_TRUE;
+    msAppendOutputFormat(myMap,msCloneOutputFormat(o6));
+    msFreeOutputFormat(o6);
+  }
+
+  
   /*
    * Set default projection to EPSG:4326
@@ -1091,28 +1426,4 @@
   msLoadProjectionStringEPSG(&myMap->projection,"EPSG:4326");
   myMap->transparent=1;
-
-  /**
-   * Set metadata extracted from main.cfg file maps
-   */
-  maps* cursor=conf;
-  map* correspondance=getCorrespondance();
-  while(cursor!=NULL){
-    map* _cursor=cursor->content;
-    map* vMap;
-    while(_cursor!=NULL){
-      if((vMap=getMap(correspondance,_cursor->name))!=NULL){
-	if (msInsertHashTable(&(myMap->web.metadata), vMap->value, _cursor->value) == NULL){
-#ifdef DEBUGMS
-	  fprintf(stderr,"Unable to add metadata");
-#endif
-	  return;
-	}
-      }
-      _cursor=_cursor->next;
-    }
-    cursor=cursor->next;
-  }
-  freeMap(&correspondance);
-  free(correspondance);
 
   /*
@@ -1157,23 +1468,85 @@
   msInsertHashTable(&(myMap->web.metadata), "ows_srs", "EPSG:4326");
 
+  /**
+   * Set metadata extracted from main.cfg file maps
+   */
+  maps* cursor=conf;
+  map* correspondance=getCorrespondance();
+  while(cursor!=NULL){
+    if(strstr(cursor->name,"_help")==NULL){
+      map* _cursor=cursor->content;
+      map* vMap;
+      while(_cursor!=NULL){
+	if((vMap=getMap(correspondance,_cursor->name))!=NULL){
+	  if (msInsertHashTable(&(myMap->web.metadata), vMap->value, _cursor->value) == NULL){
+#ifdef DEBUGMS
+	    fprintf(stderr,"Unable to add metadata");
+#endif
+	    freeMap(&correspondance);
+	    free(correspondance);
+	    return;
+	  }
+	}
+	_cursor=_cursor->next;
+      }
+    }
+    cursor=cursor->next;
+  }
+  freeMap(&correspondance);
+  free(correspondance);
+
+  map* sid=getMapFromMaps(conf,"lenv","usid");
+  char *mapPath=
+    (char*)malloc((14+strlen(sid->value)+strlen(outputs->name)+strlen(dataPath->value))*sizeof(char));
+  sprintf(mapPath,"%s/%s_%d_%s.map",dataPath->value,outputs->name,imyIndex,sid->value);
+  char *mapUrl=
+    (char*)malloc((6+strlen(mapPath)+strlen(msUrl->value))*sizeof(char));
+  sprintf(mapUrl,"%s?map=%s",msUrl->value,mapPath);
+
+  if (msInsertHashTable(&(myMap->web.metadata), "ows_onlineresource", mapUrl) == NULL){
+#ifdef DEBUGMS
+    fprintf(stderr,"Unable to add metadata");
+#endif
+    return;
+  }
+
   if(tryOgr(conf,outputs,myMap)<0)
     if(tryGdal(conf,outputs,myMap)<0)
       return ;
 
-  tmp1=getMapFromMaps(conf,"main","dataPath");
-  char *tmpPath=(char*)malloc((13+strlen(tmp1->value))*sizeof(char));
-  sprintf(tmpPath,"%s/symbols.sym",tmp1->value);
+  char *tmpPath=(char*)malloc((13+strlen(dataPath->value))*sizeof(char));
+  sprintf(tmpPath,"%s/symbols.sym",dataPath->value);
   msInitSymbolSet(&myMap->symbolset);
   myMap->symbolset.filename=zStrdup(tmpPath);
   free(tmpPath);
 
-  map* sid=getMapFromMaps(conf,"lenv","usid");
-  char *mapPath=
-    (char*)malloc((7+strlen(sid->value)+strlen(outputs->name)+strlen(tmp1->value))*sizeof(char));
-  sprintf(mapPath,"%s/%s_%s.map",tmp1->value,outputs->name,sid->value);
   msSaveMap(myMap,mapPath);
+  saveMapNames(conf,outputs,mapPath);
   free(mapPath);
+  //free(myMap->symbolset.filename);
+  //msFreeSymbolSet(&myMap->symbolset);
+  msFreeMap(myMap);
+  //msFree(myMap);
   msGDALCleanup();
-  msFreeMap(myMap);
 }
 
+/**
+ * Save the map fullpath in a text file (.maps)
+ * @param conf the main configuration map pointer
+ * @param output the current output for which a mapfile has been generated
+ * @param mapfile the mapfile saved to store in the text file
+ */
+void saveMapNames(maps* conf,maps* output,char* mapfile){
+  map* storage=getMap(output->content,"storage");
+  char *tmp=zStrdup(storage->value);
+  tmp[strlen(tmp)-strlen(strrchr(tmp,'.'))]=0;
+  char* mapName=(char*)malloc((strlen(tmp)+6)*sizeof(char*));
+  sprintf(mapName,"%s.maps",tmp);
+  FILE* myMaps=fopen(mapName,"a");
+  if(myMaps!=NULL){
+    fprintf(myMaps,"%s\n",mapfile);
+    fclose(myMaps);
+  }
+  free(mapName);
+  free(tmp);
+}
Index: trunk/zoo-project/zoo-kernel/service_internal_ms.h
===================================================================
--- trunk/zoo-project/zoo-kernel/service_internal_ms.h	(revision 889)
+++ trunk/zoo-project/zoo-kernel/service_internal_ms.h	(revision 917)
@@ -56,4 +56,6 @@
   int tryGdal(maps* conf,maps* output,mapObj* m);
   void outputMapfile(maps* conf,maps* outputs);
+  void saveMapNames(maps*,maps*,char*);
+
 #ifdef __cplusplus
 }
Index: trunk/zoo-project/zoo-kernel/service_internal_php7.c
===================================================================
--- trunk/zoo-project/zoo-kernel/service_internal_php7.c	(revision 889)
+++ trunk/zoo-project/zoo-kernel/service_internal_php7.c	(revision 917)
@@ -25,4 +25,5 @@
 #ifdef WIN32
   #define NO_FCGI_DEFINES
+  #define ZEND_WIN32_KEEP_INLINE
 #endif
 
Index: trunk/zoo-project/zoo-kernel/service_internal_python.c
===================================================================
--- trunk/zoo-project/zoo-kernel/service_internal_python.c	(revision 889)
+++ trunk/zoo-project/zoo-kernel/service_internal_python.c	(revision 917)
@@ -57,5 +57,5 @@
  * from the ZOO-Kernel Python environment:
  *  - "_" corresponding to the PythonTranslate function
- *  - "updte_status" corresponding to the PythonUpdateStatus function
+ *  - "update_status" corresponding to the PythonUpdateStatus function
  * @see PythonTranslate, PythonUpdateStatus
  */
@@ -146,14 +146,32 @@
  */
 int zoo_python_support(maps** main_conf,map* request,service* s,maps **real_inputs,maps **real_outputs){
+
   char *pythonpath;
   char *python_path;
+
+#ifdef WIN32
+  char* os_pathsep = ";";
+#else
+  char* os_pathsep = ":";
+#endif
+
   maps* m=*main_conf;
   maps* inputs=*real_inputs;
   maps* outputs=*real_outputs;
   map* tmp0=getMapFromMaps(*main_conf,"lenv","cwd");
-  char *ntmp=tmp0->value;
+  char *ntmp=tmp0->value;  
   map* tmp=NULL;
   int hasToClean=0;
-  tmp=getMapFromMaps(*main_conf,"env","PYTHONPATH");
+  tmp=getMapFromMaps(*main_conf,"env","PYTHONPATH"); 
+
+  map* kvp = NULL;
+  char* libPath = NULL;
+  if (hasvalue(*main_conf, "main", "libPath", &kvp)) {
+	  libPath = kvp->value;
+  }
+  else {
+	  libPath = "";
+  }
+
 #ifdef DEBUG
   fprintf(stderr,"PYTHON SUPPORT \n");
@@ -163,5 +181,5 @@
     fprintf(stderr,"PYTHON SUPPORT (%i)\n",strlen(tmp->value));
 #endif
-    python_path=(char*)malloc((strlen(tmp->value))*sizeof(char));
+    python_path=(char*)malloc((strlen(tmp->value)+1)*sizeof(char));
     sprintf(python_path,"%s",tmp->value);
     hasToClean=1;
@@ -172,36 +190,52 @@
       python_path=cwdMap->value;
     else
-      python_path=(char*)".";
+      python_path=(char*)".";	
   }
   tmp=NULL;
   tmp=getMap(request,"metapath");
   if(tmp!=NULL && strcmp(tmp->value,"")!=0){
-    pythonpath=(char*)malloc((4+strlen(python_path)+strlen(ntmp)+strlen(tmp->value))*sizeof(char));
+    //pythonpath=(char*)malloc((4+strlen(python_path)+strlen(ntmp)+strlen(tmp->value))*sizeof(char));
+	  pythonpath = (char*)malloc((5 + strlen(python_path) + strlen(ntmp) + strlen(tmp->value) + strlen(libPath)) * sizeof(char));
 #ifdef WIN32
-  sprintf(pythonpath,"%s/%s/;%s",ntmp,tmp->value,python_path);
+  //sprintf(pythonpath,"%s/%s/;%s",ntmp,tmp->value,python_path);
+	sprintf(pythonpath, "%s/%s/;%s;%s", ntmp, tmp->value, python_path, libPath);
 #else
-  sprintf(pythonpath,"%s/%s/:%s",ntmp,tmp->value,python_path);
+  //sprintf(pythonpath,"%s/%s/:%s",ntmp,tmp->value,python_path);
+  sprintf(pythonpath, "%s/%s/:%s:%s", ntmp, tmp->value, python_path, libPath);  
 #endif
   }
   else{
-    pythonpath=(char*)malloc((2+strlen(python_path)+strlen(ntmp))*sizeof(char));
+    //pythonpath=(char*)malloc((2+strlen(python_path)+strlen(ntmp))*sizeof(char));
+	  pythonpath = (char*)malloc((3 + strlen(python_path) + strlen(ntmp) + strlen(libPath)) * sizeof(char));
 #ifdef WIN32
-    sprintf(pythonpath,"%s;%s",ntmp,python_path);
+    //sprintf(pythonpath,"%s;%s",ntmp,python_path);
+	sprintf(pythonpath, "%s;%s;%s", ntmp, python_path, libPath);
 #else
-    sprintf(pythonpath,"%s:%s",ntmp,python_path);
-#endif
+    //sprintf(pythonpath,"%s:%s",ntmp,python_path);
+	sprintf(pythonpath, "%s:%s:%s", ntmp, python_path, libPath);
+#endif	
   }
 #ifdef DEBUG
     fprintf(stderr,"PYTHONPATH=%s\n",pythonpath);
 #endif
-#ifndef WIN32
-  setenv("PYTHONPATH",pythonpath,1);
-#else
+	map* home = NULL;
+// knut: also set PYTHONHOME environment variable so that Python can load standard modules
+#ifndef WIN32	
+  setenv("PYTHONPATH",pythonpath,1);  
+  //= getMapFromMaps(*main_conf, "env", "PYTHONHOME"); 
+  if (hasvalue(*main_conf, "env", "PYTHONHOME", &home)) {
+	  setenv("PYTHONHOME", home->value, 1); // overwrite
+  }
+#else	
   SetEnvironmentVariable("PYTHONPATH",pythonpath);
   char* toto=(char*)malloc((strlen(pythonpath)+12)*sizeof(char));
   sprintf(toto,"PYTHONPATH=%s",pythonpath);
-  putenv(toto);
+  _putenv(toto);
   free(toto);
-#endif
+  if (hasvalue(*main_conf, "env", "PYTHONHOME", &home)) { 
+	  SetEnvironmentVariable("PYTHONHOME", home->value);
+  }
+  char buffer[128];        
+#endif  
   if(hasToClean>0)
     free(python_path);
@@ -209,16 +243,16 @@
 
   PyThreadState *mainstate;
-#if PY_MAJOR_VERSION >= 3
-  PyImport_AppendInittab("zoo", init_zoo);
+#if PY_MAJOR_VERSION >= 3  
+  PyImport_AppendInittab("zoo", init_zoo);  
 #else
   PyEval_InitThreads();
-#endif
-  Py_Initialize();
-#if PY_MAJOR_VERSION >= 3
+#endif  
+  Py_Initialize();  
+#if PY_MAJOR_VERSION >= 3  
   PyEval_InitThreads();
-  PyImport_ImportModule("zoo");
+  PyImport_ImportModule("zoo");  
 #else
   init_zoo();
-#endif
+#endif  
   mainstate = PyThreadState_Swap(NULL);
   PyEval_ReleaseLock();
@@ -240,5 +274,5 @@
       char *mn=(char*)malloc((strlen(mps)+strlen(tmp->value)+2)*sizeof(char));
       sprintf(mn,"%s.%s",mps,tmp->value);
-      pName = PyString_FromString(mn);
+      pName = PyString_FromString(mn);	  
       free(mn);
       free(mps);
@@ -251,6 +285,6 @@
     errorException (m, "Unable to parse serviceProvider please check your zcfg file.", "NoApplicableCode", NULL);
     exit(-1);
-  }
-  pModule = PyImport_Import(pName);
+  }  
+  pModule = PyImport_Import(pName);    
   int res=SERVICE_FAILED;
   if (pModule != NULL) {
@@ -267,5 +301,5 @@
       PyTuple_SetItem(pArgs, 1, (PyObject *)arg2);
       PyTuple_SetItem(pArgs, 2, (PyObject *)arg3);
-      pValue = PyObject_CallObject(pFunc, pArgs);
+      pValue = PyObject_CallObject(pFunc, pArgs);	  
       if (pValue != NULL) {
 	res=PyInt_AsLong(pValue);
@@ -275,5 +309,5 @@
 	free(*main_conf);
 	*main_conf=mapsFromPyDict(arg1);
-	*real_outputs=mapsFromPyDict(arg3);
+	*real_outputs=mapsFromPyDict(arg3);	
 #ifdef DEBUG
 	fprintf(stderr,"Result of call: %i\n", PyInt_AsLong(pValue));
@@ -281,5 +315,5 @@
 	dumpMaps(*real_outputs);
 #endif
-      }else{	  
+      }else{
 	PythonZooReport(m,tmp->value,0);
 	res=-1;
@@ -301,5 +335,5 @@
 #endif
   PyThreadState_Swap(mainstate);
-  Py_Finalize();
+  Py_Finalize();  
   return res;
 }
@@ -323,10 +357,10 @@
   char *pbt=NULL;
   if(PyString_Check(trace)){
-    pbt=(char*)malloc((7+strlen(PyString_AsString(trace))+1)*sizeof(char));
+    pbt=(char*)malloc((8+strlen(PyString_AsString(trace)))*sizeof(char));
     sprintf(pbt,"TRACE: %s",PyString_AsString(trace));
   }
   else
     fprintf(stderr,"EMPTY TRACE ?");
-  
+
   trace=NULL;
   
@@ -425,4 +459,6 @@
   map* isArray=getMap(tmp,"isArray");
   map* size=getMap(tmp,"size");
+  map* useFile=getMap(tmp,"use_file");
+  map* cacheFile=getMap(tmp,"cache_file");
   map* tmap=getMapType(tmp);
   while(tmp!=NULL){
@@ -435,9 +471,12 @@
 	PyObject* mvalue=PyList_New(cnt);
 	PyObject* svalue=PyList_New(cnt);
+	PyObject* cvalue=PyList_New(cnt);
 
 	for(int i=0;i<cnt;i++){
 	  
-	  map* vMap=getMapArray(tmp,"value",i);	    
-	  map* sMap=getMapArray(tmp,"size",i);
+	  map* vMap=getMapArray(t,"value",i);
+	  map* uMap=getMapArray(t,"use_file",i);
+	  map* sMap=getMapArray(t,"size",i);
+	  map* cMap=getMapArray(t,"cache_file",i);
 
 	  if(vMap!=NULL){
@@ -445,13 +484,21 @@
 	    PyObject* lvalue;
 	    PyObject* lsvalue;
-	    if(sMap==NULL){
+	    PyObject* lcvalue;
+	    if(sMap==NULL || uMap!=NULL){
 	      lvalue=PyString_FromString(vMap->value);
-	      lsvalue=Py_None;
 	    }
 	    else{    
 	      lvalue=PyString_FromStringAndSize(vMap->value,atoi(sMap->value));
+	    }
+	    if(sMap!=NULL){
 	      lsvalue=PyString_FromString(sMap->value);
 	      hasSize=1;
 	    }
+	    else
+	      lsvalue=Py_None;
+	    if(uMap!=NULL){
+	      lcvalue=PyString_FromString(cMap->value);;
+	    }else
+	      lcvalue=Py_None;
 
 	    if(PyList_SetItem(value,i,lvalue)<0){
@@ -463,8 +510,12 @@
 	      return NULL;
 	    } 
+	    if(PyList_SetItem(cvalue,i,lcvalue)<0){
+	      fprintf(stderr,"Unable to set key value pair...");
+	      return NULL;
+	    }
 	  }
 	  
+	  PyObject* lmvalue;
 	  map* mMap=getMapArray(tmp,tmap->name,i);
-	  PyObject* lmvalue;
 	  if(mMap!=NULL){
 	    lmvalue=PyString_FromString(mMap->value);
@@ -487,4 +538,8 @@
 	  return NULL;
 	}
+	if(PyDict_SetItem(res,PyString_FromString("cache_file"),cvalue)<0){
+	  fprintf(stderr,"Unable to set key value pair...");
+	  return NULL;
+	}
 	if(hasSize>0)
 	  if(PyDict_SetItem(res,PyString_FromString("size"),svalue)<0){
@@ -493,5 +548,5 @@
 	  }
       }
-      else if(size!=NULL){
+      else if(size!=NULL && useFile==NULL){
 	PyObject* value=PyString_FromStringAndSize(tmp->value,atoi(size->value));
 	if(PyDict_SetItem(res,name,value)<0){
Index: trunk/zoo-project/zoo-kernel/service_internal_python.h
===================================================================
--- trunk/zoo-project/zoo-kernel/service_internal_python.h	(revision 889)
+++ trunk/zoo-project/zoo-kernel/service_internal_python.h	(revision 917)
@@ -2,5 +2,5 @@
  * Author : Gérald FENOY
  *
- * Copyright (c) 2009-2010 GeoLabs SARL
+ * Copyright (c) 2009-2019 GeoLabs SARL
  *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -28,8 +28,7 @@
 #pragma once 
 
+#include <Python.h>
 #include "service_internal.h"
 #include "response_print.h"
-#include <Python.h>
-#include "cgic.h"
 #ifdef WIN32
 #include <windows.h>
Index: trunk/zoo-project/zoo-kernel/service_internal_r.c
===================================================================
--- trunk/zoo-project/zoo-kernel/service_internal_r.c	(revision 917)
+++ trunk/zoo-project/zoo-kernel/service_internal_r.c	(revision 917)
@@ -0,0 +1,394 @@
+/*
+ * Author : Gérald FENOY
+ *
+ * Copyright (c) 2018 GeoLabs SARL
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "service_internal_r.h"
+
+void jump_to_toplevel(void){
+  fprintf(stderr,"Error occured\n");
+  fprintf(stderr,"%s %d \n",__FILE__,__LINE__);
+  fflush(stderr);
+  //resetStack(1);
+  fprintf(stderr,"%s %d \n",__FILE__,__LINE__);
+  fflush(stderr);
+}
+
+void init_zoo(SEXP conf,SEXP outputs){
+  const char* names[]={
+    "SERVICE_SUCCEEDEED",
+    "SERVICE_FAILED",
+    "conf",
+    "outputs",
+    ""
+  };
+  SEXP res = PROTECT(mkNamed(VECSXP, names));
+  SET_VECTOR_ELT(res, 0, Rf_ScalarInteger(3));
+  SET_VECTOR_ELT(res, 1, Rf_ScalarInteger(4));
+  SET_VECTOR_ELT(res, 2, conf);
+  SET_VECTOR_ELT(res, 3, outputs);
+  defineVar(install("zoo"),res, R_GlobalEnv);
+
+  static const R_CallMethodDef callMethods[]  = {
+    {"ZOOTranslate", (DL_FUNC) &RTranslate, 1},
+    {"ZOOUpdateStatus", (DL_FUNC) &RUpdateStatus, 2},
+    {NULL, NULL, 0}
+  };
+  
+  static R_NativePrimitiveArgType RTranslate_t[] = {
+    STRSXP
+  };
+  static R_NativePrimitiveArgType RUpdateStatus_t[] = {
+    VECSXP,STRSXP
+  };
+  
+  static const R_CMethodDef cMethods[] = {
+   {"ZOOTranslate", (DL_FUNC) &RTranslate, 1, RTranslate_t},
+   {"ZOOUpdateStatus", (DL_FUNC) &RUpdateStatus, 2, RUpdateStatus_t},
+   {NULL, NULL, 0, NULL}
+  };
+  
+  DllInfo *info = R_getEmbeddingDllInfo();
+  R_registerRoutines(info, cMethods, callMethods, NULL, NULL);
+}
+
+/**
+ * Load a R script then run the function corresponding to the service
+ * by passing the conf, inputs and outputs parameters by reference. 
+ *
+ * @param main_conf the conf maps containing the main.cfg settings
+ * @param request the map containing the HTTP request
+ * @param s the service structure
+ * @param real_inputs the maps containing the inputs
+ * @param real_outputs the maps containing the outputs
+ */
+int zoo_r_support(maps** main_conf,map* request,service* s,maps **real_inputs,maps **real_outputs){
+  SEXP pName;
+  int result=0;
+  maps* m=*main_conf;
+  maps* inputs=*real_inputs;
+  maps* outputs=*real_outputs;
+  map* tmp0=getMapFromMaps(*main_conf,"lenv","cwd");
+  char *ntmp=tmp0->value;
+  map* tmp=NULL;
+  int hasToClean=0;
+  char *r_path, *rpath;
+  map* cwdMap=getMapFromMaps(*main_conf,"main","servicePath");
+  int r_argc = 3;
+  char *r_argv[] = { "R", "--no-save", "--silent" };
+  Rf_initEmbeddedR(r_argc, r_argv);
+  if(cwdMap!=NULL)
+    r_path=cwdMap->value;
+  else{
+    if(tmp0!=NULL)
+      r_path=tmp0->value;
+    else
+      r_path=(char*)".";
+  }
+
+  tmp=getMap(s->content,"serviceProvider");
+  map* mp=getMap(request,"metapath");
+  if(tmp!=NULL){
+    if(mp!=NULL && strlen(mp->value)>0){
+      char *mn=(char*)malloc((strlen(mp->value)+strlen(tmp->value)+2)*sizeof(char));
+      sprintf(mn,"%s/%s",mp->value,tmp->value);
+      pName = mkString(mn);
+      free(mn);
+    }
+    else{
+      char *tmpStr=(char*)malloc((strlen(r_path)+strlen(tmp->value)+2)*sizeof(char));
+      sprintf(tmpStr,"%s/%s",r_path,tmp->value);
+      pName = mkString(tmpStr);
+      free(tmpStr);
+    }
+  }
+  else{
+    errorException (m, "Unable to parse serviceProvider please check your zcfg file.", "NoApplicableCode", NULL);
+    return -1;
+  }
+  SEXP e;
+  int errorOccurred;
+  PROTECT(e = lang2(install("source"), pName));
+  R_tryEval(e, R_GlobalEnv, &errorOccurred);
+  UNPROTECT(1);
+  if (errorOccurred){
+    setMapInMaps(*main_conf,"lenv","message",_("Unable to load your R file"));
+    return SERVICE_FAILED;
+  }else{
+    result=SERVICE_FAILED;
+    {
+      SEXP pValue;
+      SEXP  arg1=RList_FromMaps(m);
+      SEXP  arg2=RList_FromMaps(*real_inputs);
+      SEXP  arg3=RList_FromMaps(*real_outputs);
+      SEXP r_call;
+      init_zoo(arg1,arg3);
+      PROTECT(r_call = lang4(install(s->name), arg1,arg2,arg3));
+      int errorOccurred;
+      
+      SEXP ret = R_tryEval(r_call, R_GlobalEnv, &errorOccurred);
+      if (!errorOccurred) {
+	int *val = INTEGER(ret);
+        for (int i = 0; i < LENGTH(ret); i++)
+	  if(i==0){
+	      result=val[i];
+	      SEXP zooEnv = findVar(install("zoo"), R_GlobalEnv);
+	      if(zooEnv!=NULL){
+		SEXP names = Rf_getAttrib(zooEnv, R_NamesSymbol);
+		int nbKeys=nrows(names);
+		int i;
+		for(i=0;i<nbKeys;i++){
+		  if(i==2){
+		    freeMaps(main_conf);
+		    free(*main_conf);
+		    SEXP confList=VECTOR_ELT(zooEnv,i);
+		    *main_conf=mapsFromRList(confList);
+		  }
+		  if(i==3){
+		    freeMaps(real_outputs);
+		    free(*real_outputs);
+		    SEXP outList=VECTOR_ELT(zooEnv,i);
+		    *real_outputs=mapsFromRList(outList);
+		  }
+		}
+	      }
+	      return result;
+	    }
+      }else{
+	const char* tmpStr=R_curErrorBuf();
+	setMapInMaps(*main_conf,"lenv","message",tmpStr);
+	char* finalStr=(char*)malloc((strlen(tmpStr)+strlen(_("Unable to run your R service: "))+2)*sizeof(char));
+	sprintf(finalStr,"%s %s",_("Unable to run your R service: "),tmpStr);
+	errorException(*main_conf,finalStr,"NoApplicableCode",NULL);
+	free(finalStr);
+	result=-1;
+      }
+    }
+  }
+  Rf_endEmbeddedR(0);
+  return result;
+}
+
+char** listMapsKeys(maps* m){
+  char** res=NULL;
+  maps* tmp=m;
+  int i=0;
+  while(tmp!=NULL){
+    if(i==0)
+      res=(char**)malloc(2*sizeof(char*));
+    else
+      res=(char**)realloc(res,(i+2)*sizeof(char*));
+    res[i]=zStrdup(tmp->name);
+    res[i+1]="";
+    i++;
+    tmp=tmp->next;
+  }
+  return res;
+}
+
+char** listMapKeys(map* m){
+  char** res=NULL;
+  map* tmp=m;
+  int i=0;
+  while(tmp!=NULL){
+    if(i==0)
+      res=(char**)malloc(2*sizeof(char*));
+    else
+      res=(char**)realloc(res,(i+2)*sizeof(char*));
+    res[i]=zStrdup(tmp->name);
+    res[i+1]="";
+    i++;
+    tmp=tmp->next;
+  }
+  return res;
+}
+
+/**
+ * Convert a maps to a R List
+ *
+ * @param t the maps to convert
+ * @return a new SEXP containing the converted maps
+ * @see RList_FromMap
+ * @warning make sure to free resources returned by this function
+ */
+SEXP RList_FromMaps(maps* t){
+  maps* tmp=t;
+  char** keys=listMapsKeys(t);
+  SEXP res = PROTECT(mkNamed(VECSXP,(const char**) keys));
+  free(keys);
+  int cnt=0;
+  while(tmp!=NULL){
+    SEXP input = RList_FromMap(tmp->content);
+    SET_VECTOR_ELT(res,cnt,input);
+    cnt++;
+    tmp=tmp->next;
+  } 
+  UNPROTECT(1);
+  return res;
+}
+
+/**
+ * Convert a map to a R List
+ *
+ * @param t the map to convert
+ * @return a new SEXP containing the converted maps
+ * @warning make sure to free resources returned by this function
+ */
+SEXP RList_FromMap(map* t){
+  map* tmp=t;
+  int hasSize=0;
+  char** keys=listMapKeys(t);
+  SEXP res = PROTECT(mkNamed(VECSXP, (const char**)keys));
+  free(keys);
+  int cnt=0;
+  while(tmp!=NULL){
+    SEXP value=mkString(tmp->value);
+    SET_VECTOR_ELT(res,cnt,value);
+    cnt++;
+    tmp=tmp->next;
+  }
+  UNPROTECT(1);
+  return res;
+}
+
+/**
+ * Convert a R List to a maps 
+ *
+ * @param t the PyDictObject to convert
+ * @return a new maps containing the converted PyDictObject
+ * @warning make sure to free resources returned by this function
+ */
+maps* mapsFromRList(SEXP t){
+  maps* res=NULL;
+  maps* cursor=NULL;
+  SEXP names = Rf_getAttrib(t, R_NamesSymbol);
+  int nbKeys=nrows(names);
+  int i;
+  for(i=0;i<nbKeys;i++){
+    SEXP key=STRING_ELT(names,i);
+    SEXP value=VECTOR_ELT(t,i);
+    cursor=createMaps(R_CHAR(key));
+    cursor->content=mapFromRList(value);
+    cursor->next=NULL;
+    if(res==NULL)
+      res=dupMaps(&cursor);
+    else
+      addMapsToMaps(&res,cursor);
+    freeMap(&cursor->content);
+    free(cursor->content);
+    free(cursor);
+  }
+  return res;
+}
+
+/**
+ * Convert a R List to a map 
+ *
+ * @param t the PyDictObject to convert
+ * @return a new map containing the converted PyDictObject
+ * @warning make sure to free resources returned by this function
+ */
+map* mapFromRList(SEXP t){
+  map* res=NULL;
+  SEXP names = Rf_getAttrib(t, R_NamesSymbol);
+  int nbKeys=nrows(names);
+  int i;
+  for(i=0;i<nbKeys;i++){
+    SEXP key=STRING_ELT(names,i);
+    SEXP value=VECTOR_ELT(t,i);
+    if(strncmp(R_CHAR(key),"child",5)!=0){
+      {
+	const char* lkey=R_CHAR(key);
+	const char* lvalue=CHAR(STRING_ELT(value,0));
+	if(res!=NULL){
+	  addToMap(res,lkey,lvalue);
+	}
+	else{
+	  res=createMap(lkey,lvalue);
+	}
+      }
+    }
+  }
+  return res;
+}
+
+/**
+ * Use the ZOO-Services messages translation function from the R
+ * environment
+ *
+ * @param str the R string passed from the R environment
+ * @return a new R string containing the translated value
+ * @see _ss
+ */
+SEXP
+RTranslate(SEXP str)
+{
+  if (!isString(str) || !TYPEOF(STRING_ELT( str, 0 )) == CHARSXP){
+#ifdef DEBUG
+    fprintf(stderr,"Incorrect arguments to update status function");
+#endif
+    return R_NilValue;
+  }
+  const char* tmpStr=CHAR(STRING_ELT(str,0));
+  return mkString(_ss(tmpStr));
+}
+
+/**
+ * Update the ongoing status of a running service from the R environment
+ *
+ * @param confdict the R arguments passed from the R environment
+ * @param status the R arguments passed from the R environment
+ * @return Nil to the Python environment
+ * @see _updateStatus
+ */
+SEXP
+RUpdateStatus(SEXP confdict,SEXP status)
+{
+  maps* conf;
+  int istatus;
+  char* cstatus=NULL;
+  if (!isInteger(status) && !isReal(status)){
+#ifdef DEBUG
+    fprintf(stderr,"Incorrect arguments to update status function");
+#endif
+    return R_NilValue;
+  }
+  if(isInteger(status))
+    istatus=asInteger(status);
+  else
+    istatus=asReal(status);
+  if (istatus < 0 || istatus > 100){
+    return R_NilValue;
+  }
+  // create a local copy and update the lenv map
+  conf = mapsFromRList(confdict);
+  if(status!=NULL){
+    maps* tmpMaps=getMaps(conf,"lenv");
+    addIntToMap(tmpMaps->content,"status",istatus);
+  }
+  else
+    setMapInMaps(conf,"lenv","status","15");
+  _updateStatus(conf);
+  freeMaps(&conf);
+  free(conf);
+  return R_NilValue;
+}
Index: trunk/zoo-project/zoo-kernel/service_internal_r.h
===================================================================
--- trunk/zoo-project/zoo-kernel/service_internal_r.h	(revision 917)
+++ trunk/zoo-project/zoo-kernel/service_internal_r.h	(revision 917)
@@ -0,0 +1,47 @@
+/*
+ * Author : Gérald FENOY
+ *
+ * Copyright (c) 2009-2010 GeoLabs SARL
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef ZOO_SERVICE_INTERNAL_R_H
+#define ZOO_SERVICE_INTERNAL_R_H 1
+
+#pragma once 
+
+#include <Rinternals.h>
+#include <Rembedded.h>
+#include "service_internal.h"
+#include "response_print.h"
+#include "cgic.h"
+
+SEXP RList_FromMaps(maps* t);
+SEXP RList_FromMap(map* t);
+
+maps* mapsFromRList(SEXP t);
+map* mapFromRList(SEXP t);
+
+int zoo_r_support(maps**,map*,service*,maps**,maps**);
+
+SEXP RTranslate(SEXP);
+SEXP RUpdateStatus(SEXP,SEXP);
+
+#endif
Index: trunk/zoo-project/zoo-kernel/service_internal_ruby.c
===================================================================
--- trunk/zoo-project/zoo-kernel/service_internal_ruby.c	(revision 889)
+++ trunk/zoo-project/zoo-kernel/service_internal_ruby.c	(revision 917)
@@ -260,4 +260,5 @@
   int hasSize=0;
   map* isArray=getMap(tmp,"isArray");
+  map* useFile=getMap(tmp,"use_file");
   map* size=getMap(tmp,"size");
   map* tmap=getMapType(tmp);
@@ -271,4 +272,5 @@
 	VALUE mvalue=rb_ary_new2(cnt);
 	VALUE svalue=rb_ary_new2(cnt);
+	VALUE cvalue=rb_ary_new2(cnt);
 
 	for(int i=0;i<cnt;i++){
@@ -276,4 +278,6 @@
 	  map* vMap=getMapArray(tmp,"value",i);	    
 	  map* sMap=getMapArray(tmp,"size",i);
+	  map* uMap=getMapArray(tmp,"use_file",i);
+	  map* cMap=getMapArray(tmp,"cache_file",i);
 
 	  if(vMap!=NULL){
@@ -281,7 +285,11 @@
 	    VALUE lvalue;
 	    VALUE lsvalue;
-	    if(sMap==NULL){
+	    VALUE lcvalue;
+	    if(sMap==NULL || uMap==NULL){
 	      lvalue=rb_str_new2(vMap->value);
-	      lsvalue=Qnil;
+	      if(sMap==NULL)
+		lsvalue=Qnil;
+	      else
+		lsvalue=rb_str_new2(sMap->value);
 	    }
 	    else{
@@ -290,7 +298,12 @@
 	      hasSize=1;
 	    }
+	    if(uMap!=NULL)
+	      lcvalue=rb_str_new2(cMap->value);
+	    else
+	      lcvalue=Qnil;
 
 	    rb_ary_push(value,lvalue);
 	    rb_ary_push(svalue,lsvalue);
+	    rb_ary_push(cvalue,lcvalue);
 	  }
 	  
@@ -308,4 +321,6 @@
 	rb_hash_aset(res, name, mvalue);
 	rb_hash_aset(res, rb_str_new2(tmap->name), mvalue);
+	VALUE lname0=rb_str_new2("cache_size");
+	rb_hash_aset(res, lname0, value);
       
 	if(hasSize>0){
Index: trunk/zoo-project/zoo-kernel/service_internal_saga.c
===================================================================
--- trunk/zoo-project/zoo-kernel/service_internal_saga.c	(revision 889)
+++ trunk/zoo-project/zoo-kernel/service_internal_saga.c	(revision 917)
@@ -30,5 +30,5 @@
 #include <api_core.h>
 #include <data_manager.h>
-#include <module_library.h>
+#include <saga_api.h>
 #define _ZOO_SAGA
 #include "service_internal_saga.h"
@@ -237,5 +237,7 @@
 	return false;
       }
-      return( param->Set_Value(SG_Get_Data_Manager().Find(&fileName)) );
+      fprintf(stderr,"%s %s\n",carg->name,carg->value);
+      fflush(stderr);
+      return( param->Set_Value(SG_Get_Data_Manager().Find(&fileName,false)) );
     }
     else
@@ -250,5 +252,5 @@
 	    SG_Get_Data_Manager().Add(&fileName);
 	  }
-	  param->asList()->Add_Item(SG_Get_Data_Manager().Find(&fileName));
+	  param->asList()->Add_Item(SG_Get_Data_Manager().Find(&fileName,false));
 	}
       }
@@ -327,8 +329,16 @@
 	    inmap=getMap(argument,(CSG_String(param->Get_Identifier())+"_MIN").b_str());
 	    if(inmap!=NULL)
+#if SAGA_MAJOR_VERSION == 2	      
 	      param->asRange()->Set_LoVal(strtod(inmap->value,NULL));
+#else
+	      param->asRange()->Set_Min(strtod(inmap->value,NULL));
+#endif	    
 	    inmap=getMap(argument,(CSG_String(param->Get_Identifier())+"_MAX").b_str());
 	    if(inmap!=NULL)
+#if SAGA_MAJOR_VERSION == 2	      
 	      param->asRange()->Set_HiVal(strtod(inmap->value,NULL));	    
+#else
+	      param->asRange()->Set_Max(strtod(inmap->value,NULL));
+#endif	    
 	  }
 	  if(inmap==NULL){
@@ -386,7 +396,19 @@
 	    else if( param->is_DataObject_List() )
 	      {
-		for(int i=0; i<param->asList()->Get_Count(); i++)
+		for(int i=0; i<
+#if SAGA_MAJOR_VERSION == 2
+		      param->asList()->Get_Count()
+#else
+		      param->asList()->Get_Data_Count()
+#endif		      
+		      ; i++)
 		  {
-		    CSG_Data_Object *pObject = param->asList()->asDataObject(i);
+		    CSG_Data_Object *pObject =
+#if SAGA_MAJOR_VERSION == 2		      
+		      param->asList()->asDataObject(i)
+#else
+		      param->asList()->Get_Data(i)
+#endif		      
+		      ;
 		    
 		    if( pObject->is_Modified() && SG_File_Exists(pObject->Get_File_Name()) )
@@ -439,5 +461,5 @@
 			}
 		    }
-		  
+#if SAGA_MAJOR_VERSION == 2		  
 		  int nFileNames = param->asList()->Get_Count() <= fileNames.Get_Count() ? fileNames.Get_Count() : fileNames.Get_Count() - 1;
 		  for(int i=0; i<param->asList()->Get_Count(); i++)
@@ -458,4 +480,25 @@
 				  CSG_String(param->asList()->asDataObject(i)->Get_File_Name()).b_str());
 		    }
+#else
+		  int nFileNames = param->asList()->Get_Data_Count() <= fileNames.Get_Count() ? fileNames.Get_Count() : fileNames.Get_Count() - 1;
+		  for(int i=0; i<param->asList()->Get_Data_Count(); i++)
+		    {
+		      if( i < nFileNames )
+			{
+			  param->asList()->Get_Data(i)->Save(fileNames[i]);
+			}
+		      else
+			{
+			  param->asList()->Get_Data(i)->Save(CSG_String::Format(SG_T("%s_%0*d"),
+										    fileNames[fileNames.Get_Count() - 1].c_str(),
+										    SG_Get_Digit_Count(param->asList()->Get_Data_Count()),
+										    1 + i - nFileNames
+										    ));
+			}
+		      setMapArray(cMaps->content,"generated_file",i,
+				  CSG_String(param->asList()->Get_Data(i)->Get_File_Name()).b_str());
+		    }
+		  
+#endif		  
 		}
 	    }
@@ -477,5 +520,9 @@
   int res=SERVICE_FAILED;
 
+#if SAGA_MAJOR_VERSION == 2  
   CSG_Module_Library * library=SG_Get_Module_Library_Manager().Get_Library(CSG_String(lib_name),true);
+#else
+  CSG_Tool_Library * library=SG_Get_Tool_Library_Manager().Get_Library(CSG_String(lib_name),true);
+#endif  
   if( library == NULL){
     char tmp[255];
@@ -486,5 +533,9 @@
   }
 
+#if SAGA_MAJOR_VERSION == 2  
   CSG_Module * module=library->Get_Module(atoi(module_name));
+#else
+  CSG_Tool * module=library->Get_Tool(atoi(module_name));
+#endif  
   if(module == NULL){
     char tmp[255];
@@ -985,6 +1036,12 @@
   SG_Set_UI_Callback(Get_Callback(watcher));
 
+#if SAGA_MAJOR_VERSION == 2  
   int n = SG_Get_Module_Library_Manager().Add_Directory(wxT(MODULE_LIBRARY_PATH),false);
-  if( SG_Get_Module_Library_Manager().Get_Count() <= 0 ){
+  if( SG_Get_Module_Library_Manager().Get_Count() <= 0 )
+#else
+  int n = SG_Get_Tool_Library_Manager().Add_Directory(wxT(MODULE_LIBRARY_PATH),false);
+  if( SG_Get_Tool_Library_Manager().Get_Count() <= 0 )
+#endif
+  {
     setMapInMaps(*main_conf,"lenv","message","Could not load any SAGA tool library");
     res=SERVICE_FAILED;
@@ -995,5 +1052,9 @@
 
   // Load the SAGA-GIS library corresponding to the serviceProvider
+#if SAGA_MAJOR_VERSION == 2  
   CSG_Module_Library * library=SG_Get_Module_Library_Manager().Get_Library(CSG_String(serviceProvider->value),true);
+#else
+  CSG_Tool_Library * library=SG_Get_Tool_Library_Manager().Get_Library(CSG_String(serviceProvider->value),true);
+#endif
   if( library == NULL){
     char tmp[255];
@@ -1005,5 +1066,9 @@
   
   // Load the SAGA-GIS module corresponding to the service name from the library
+#if SAGA_MAJOR_VERSION == 2  
   CSG_Module * module=library->Get_Module(atoi(s->name));
+#else
+  CSG_Tool * module=library->Get_Tool(atoi(s->name));
+#endif
   if(module == NULL){
     char tmp[255];
@@ -1017,5 +1082,4 @@
   // Load all the parameters defined for the module
   CSG_Parameters * params=module->Get_Parameters();
-  int pc=params->Get_Count();
   if(!params){
     char tmp[255];
@@ -1026,4 +1090,5 @@
     return res;
   }
+  int pc=params->Get_Count();
 
   // Loop over each inputs to transform raster files to grid when needed, 
Index: trunk/zoo-project/zoo-kernel/service_json.c
===================================================================
--- trunk/zoo-project/zoo-kernel/service_json.c	(revision 917)
+++ trunk/zoo-project/zoo-kernel/service_json.c	(revision 917)
@@ -0,0 +1,143 @@
+/*
+ * Author : Gérald FENOY
+ *
+ *  Copyright 2017 GeoLabs SARL. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "service_json.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+  json_object* mapToJson(map* myMap){
+    json_object *res=json_object_new_object();
+    map* cursor=myMap;
+    map* sizeMap=getMap(myMap,"size");
+    map* length=getMap(myMap,"length");
+    while(cursor!=NULL){
+      json_object *val=NULL;
+      if(length==NULL && sizeMap==NULL)
+	val=json_object_new_string(cursor->value);
+      else{
+	if(length==NULL && sizeMap!=NULL){
+	  if(strncasecmp(cursor->name,"value",5)==0)
+	    val=json_object_new_string_len(cursor->value,atoi(sizeMap->value));
+	  else
+	    val=json_object_new_string(cursor->value);
+	}
+	else{
+	  // In other case we should consider array with potential sizes
+	  int limit=atoi(length->value);
+	  int i=0;
+	  val=json_object_new_array();
+	  for(i=0;i<limit;i++){
+	    map* lsizeMap=getMapArray(myMap,"size",i);
+	    if(lsizeMap!=NULL && strncasecmp(cursor->name,"value",5)==0){
+	      json_object_array_add(val,json_object_new_string_len(cursor->value,atoi(sizeMap->value)));
+	    }else{
+	      json_object_array_add(val,json_object_new_string(cursor->value));
+	    }
+	  }
+	}
+      }
+      if(val!=NULL)
+	json_object_object_add(res,cursor->name,val);
+      cursor=cursor->next;
+    }
+    return res;
+  }
+
+  json_object* mapsToJson(maps* myMap){
+    json_object *res=json_object_new_object();
+    maps* cursor=myMap;
+    while(cursor!=NULL){
+      json_object *obj=NULL;
+      if(cursor->content!=NULL){
+	//json_object *content=NULL;
+	obj=mapToJson(cursor->content);
+	//json_object_object_add(obj,"content",content);
+      }else
+	obj=json_object_new_object();
+      if(cursor->child!=NULL){
+	json_object *child=NULL;
+	child=mapsToJson(cursor->child);
+	json_object_object_add(obj,"child",child);
+      }
+      json_object_object_add(res,cursor->name,obj);
+      cursor=cursor->next;
+    }
+    return res;
+  }
+
+  json_object* elementsToJson(elements* myElements){
+    json_object *res=json_object_new_object();
+    elements* cur=myElements;
+    while(cur!=NULL){
+      json_object *cres=json_object_new_object();
+      json_object_object_add(cres,"content",mapToJson(cur->content));
+      json_object_object_add(cres,"metadata",mapToJson(cur->metadata));
+      json_object_object_add(cres,"additional_parameters",mapToJson(cur->additional_parameters));
+      if(cur->format!=NULL){
+	json_object_object_add(cres,"format",json_object_new_string(cur->format));
+      }
+      if(cur->child==NULL){
+	if(cur->defaults!=NULL)
+	  json_object_object_add(cres,"defaults",mapToJson(cur->defaults->content));
+	else
+	  json_object_object_add(cres,"defaults",mapToJson(NULL));
+	iotype* scur=cur->supported;
+	json_object *resi=json_object_new_array();
+	while(scur!=NULL){
+	  json_object_array_add(resi,mapToJson(scur->content));
+	  scur=scur->next;
+	}
+	json_object_object_add(cres,"supported",resi);
+	fprintf(stderr,"%s %d\n",__FILE__,__LINE__);
+	fflush(stderr);
+      }
+      
+      dumpElements(cur->child);
+      json_object_object_add(cres,"child",elementsToJson(cur->child));
+      fprintf(stderr,"%s %d\n",__FILE__,__LINE__);
+      fflush(stderr);
+
+      json_object_object_add(res,cur->name,cres);
+      cur=cur->next;
+    }
+    return res;
+  }
+  
+  json_object* serviceToJson(service* myService){
+    json_object *res=json_object_new_object();
+    json_object_object_add(res,"name",json_object_new_string(myService->name));
+    json_object_object_add(res,"content",mapToJson(myService->content));
+    json_object_object_add(res,"metadata",mapToJson(myService->metadata));
+    json_object_object_add(res,"additional_parameters",mapToJson(myService->additional_parameters));
+    json_object_object_add(res,"inputs",elementsToJson(myService->inputs));
+    json_object_object_add(res,"outputs",elementsToJson(myService->outputs));
+    return res;
+  }
+  
+  
+#ifdef __cplusplus
+}
+#endif
Index: trunk/zoo-project/zoo-kernel/service_json.h
===================================================================
--- trunk/zoo-project/zoo-kernel/service_json.h	(revision 917)
+++ trunk/zoo-project/zoo-kernel/service_json.h	(revision 917)
@@ -0,0 +1,44 @@
+/*
+ * Author : Gérald FENOY
+ *
+ *  Copyright 2014 GeoLabs SARL. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef ZOO_JSON_H
+#define ZOO_JSON_H 1
+
+#pragma once
+
+#include <stdio.h>
+#include <ctype.h>
+#include <service.h>
+#include <json_object.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+  json_object* mapToJson(map*);
+  json_object* mapsToJson(maps*);
+  json_object* serviceToJson(service*);
+#ifdef __cplusplus
+}
+#endif
+#endif
Index: trunk/zoo-project/zoo-kernel/service_yaml.c
===================================================================
--- trunk/zoo-project/zoo-kernel/service_yaml.c	(revision 889)
+++ trunk/zoo-project/zoo-kernel/service_yaml.c	(revision 917)
@@ -487,5 +487,5 @@
 	      addMapToIoType(&current_element->supported,current_content);
 	  }
-	  freeMaps(&current_content);
+	  freeMap(&current_content);
 	  free(current_content);
 	  current_content=NULL;
Index: trunk/zoo-project/zoo-kernel/sql/schema.sql
===================================================================
--- trunk/zoo-project/zoo-kernel/sql/schema.sql	(revision 889)
+++ trunk/zoo-project/zoo-kernel/sql/schema.sql	(revision 917)
@@ -31,6 +31,6 @@
 -- Create a dedicated schema to store all tables
 -- Uncomment the following 2 lines to activate the schema use
--- CREATE SCHEMA zoo;
--- SET search_path TO zoo;
+-- CREATE SCHEMA processdb;
+-- SET search_path TO processdb;
 --------------------------------------------------------------------------------
 -- Services table
Index: trunk/zoo-project/zoo-kernel/sql/zoo_collectiondb.sql
===================================================================
--- trunk/zoo-project/zoo-kernel/sql/zoo_collectiondb.sql	(revision 917)
+++ trunk/zoo-project/zoo-kernel/sql/zoo_collectiondb.sql	(revision 917)
@@ -0,0 +1,321 @@
+create schema CollectionDB;
+
+set search_path = CollectionDB, pg_catalog;
+
+CREATE OR REPLACE FUNCTION update_Description() RETURNS trigger AS 
+$$
+DECLARE
+	i integer;
+BEGIN
+	INSERT INTO CollectionDB.Descriptions (id) VALUES (NEW.id);
+	RETURN NEW;
+END;
+$$ LANGUAGE plpgsql;
+
+CREATE FUNCTION is_in_ows_DataDescription(i integer) RETURNS boolean
+    LANGUAGE plpgsql
+    AS $$
+DECLARE
+        res int;
+        mymax int;
+BEGIN
+	SELECT id from CollectionDB.ows_DataDescription where id=i INTO res ;
+	if res is NULL then
+	   return false;
+	else
+	   return true;
+	end if;
+END;
+$$;
+
+create table CollectionDB.Descriptions (
+       id serial primary key
+);
+
+create table CollectionDB.ows_Metadata (
+       id serial primary key,
+       title text,
+       role text,
+       href text
+);
+
+create table CollectionDB.DescriptionsMetadataAssignment(
+       descriptions_id int references CollectionDB.Descriptions(id),
+       metadata_id int references CollectionDB.ows_Metadata(id)
+);
+
+create table CollectionDB.ows_Keywords (
+    id serial primary key,
+    keyword varchar
+);
+
+create table CollectionDB.DescriptionsKeywordsAssignment(
+       descriptions_id int references CollectionDB.Descriptions(id),
+       keywords_id int references CollectionDB.ows_Keywords(id)
+);
+
+create table CollectionDB.ows_AdditionalParameters (
+    id serial primary key,
+    title varchar,
+    role varchar,
+    href varchar
+);
+
+create table CollectionDB.DescriptionsAdditionalParametersAssignment (
+       descriptions_id int references CollectionDB.Descriptions(id),
+       additional_parameters_id int references CollectionDB.ows_AdditionalParameters(id)
+);
+
+--
+-- See reference for primitive datatypes
+-- https://www.w3.org/TR/xmlschema-2/#built-in-primitive-datatypes
+-- 
+create table CollectionDB.PrimitiveDataTypes (
+       id serial primary key,
+       name varchar(255)
+);
+INSERT INTO CollectionDB.PrimitiveDataTypes (name) VALUES ('string');
+INSERT INTO CollectionDB.PrimitiveDataTypes (name) VALUES ('boolean');
+INSERT INTO CollectionDB.PrimitiveDataTypes (name) VALUES ('integer');
+INSERT INTO CollectionDB.PrimitiveDataTypes (name) VALUES ('float');
+INSERT INTO CollectionDB.PrimitiveDataTypes (name) VALUES ('double');
+INSERT INTO CollectionDB.PrimitiveDataTypes (name) VALUES ('duration');
+INSERT INTO CollectionDB.PrimitiveDataTypes (name) VALUES ('dateTime');
+INSERT INTO CollectionDB.PrimitiveDataTypes (name) VALUES ('time');
+INSERT INTO CollectionDB.PrimitiveDataTypes (name) VALUES ('date');
+INSERT INTO CollectionDB.PrimitiveDataTypes (name) VALUES ('gYearMonth');
+INSERT INTO CollectionDB.PrimitiveDataTypes (name) VALUES ('gYear');
+INSERT INTO CollectionDB.PrimitiveDataTypes (name) VALUES ('gMonthDay');
+INSERT INTO CollectionDB.PrimitiveDataTypes (name) VALUES ('gDay');
+INSERT INTO CollectionDB.PrimitiveDataTypes (name) VALUES ('gMonth');
+INSERT INTO CollectionDB.PrimitiveDataTypes (name) VALUES ('hexBinary');
+INSERT INTO CollectionDB.PrimitiveDataTypes (name) VALUES ('base64Binary');
+INSERT INTO CollectionDB.PrimitiveDataTypes (name) VALUES ('anyURI');
+INSERT INTO CollectionDB.PrimitiveDataTypes (name) VALUES ('QName');
+INSERT INTO CollectionDB.PrimitiveDataTypes (name) VALUES ('NOTATION');
+
+--
+-- List all primitive formats
+--
+create table CollectionDB.PrimitiveFormats (
+       id serial primary key,
+       mime_type varchar(255),
+       encoding varchar(15),
+       schema varchar(255)
+);
+
+-- https://tools.ietf.org/html/rfc4180
+INSERT INTO CollectionDB.PrimitiveFormats (mime_type,encoding) VALUES ('text/csv','utf-8');
+INSERT INTO CollectionDB.PrimitiveFormats (mime_type,encoding) VALUES ('text/css','utf-8');
+INSERT INTO CollectionDB.PrimitiveFormats (mime_type,encoding) VALUES ('text/html','utf-8');
+INSERT INTO CollectionDB.PrimitiveFormats (mime_type,encoding) VALUES ('text/javascript','utf-8');
+INSERT INTO CollectionDB.PrimitiveFormats (mime_type,encoding) VALUES ('text/plain','utf-8');
+INSERT INTO CollectionDB.PrimitiveFormats (mime_type,encoding,schema)
+       VALUES ('text/xml','utf-8','http://schema.opengis.net/gml/3.2.1/gml.xsd');
+INSERT INTO CollectionDB.PrimitiveFormats (mime_type,encoding,schema)
+       VALUES ('text/xml','utf-8','http://schema.opengis.net/gml/3.1.0/gml.xsd');
+INSERT INTO CollectionDB.PrimitiveFormats (mime_type,encoding) VALUES ('application/gml+xml','utf-8');
+INSERT INTO CollectionDB.PrimitiveFormats (mime_type,encoding) VALUES ('application/json','utf-8');
+-- https://tools.ietf.org/html/rfc3302
+INSERT INTO CollectionDB.PrimitiveFormats (mime_type) VALUES ('image/tiff');
+-- https://www.ietf.org/rfc/rfc4047.txt
+INSERT INTO CollectionDB.PrimitiveFormats (mime_type) VALUES ('image/fits');
+-- https://tools.ietf.org/html/rfc3745
+INSERT INTO CollectionDB.PrimitiveFormats (mime_type) VALUES ('image/jp2');
+INSERT INTO CollectionDB.PrimitiveFormats (mime_type) VALUES ('image/png');
+INSERT INTO CollectionDB.PrimitiveFormats (mime_type) VALUES ('image/jpeg');
+INSERT INTO CollectionDB.PrimitiveFormats (mime_type) VALUES ('image/gif');
+INSERT INTO CollectionDB.PrimitiveFormats (mime_type) VALUES ('application/octet-stream');
+INSERT INTO CollectionDB.PrimitiveFormats (mime_type) VALUES ('application/vnd.google-earth.kml+xml');
+-- https://www.iana.org/assignments/media-types/application/zip
+INSERT INTO CollectionDB.PrimitiveFormats (mime_type) VALUES ('application/zip');
+-- https://www.iana.org/assignments/media-types/application/xml
+INSERT INTO CollectionDB.PrimitiveFormats (mime_type,encoding) VALUES ('application/xml','utf-8');
+
+create table CollectionDB.ows_Format (
+    id serial primary key,
+    primitive_format_id int references CollectionDB.PrimitiveFormats(id),
+    maximum_megabytes int,
+    def boolean,
+	use_mapserver bool,
+	ms_styles text
+);
+
+create table CollectionDB.ows_DataDescription (
+    id serial primary key,
+    format_id int references CollectionDB.ows_Format(id)
+);
+
+create table CollectionDB.PrimitiveUom (
+	id serial primary key,
+	uom varchar
+);
+-- source : Open Geospatial Consortium - URNs of definitions in ogc namespace
+insert into CollectionDB.PrimitiveUom (uom) values ('degree');
+insert into CollectionDB.PrimitiveUom (uom) values ('radian');
+insert into CollectionDB.PrimitiveUom (uom) values ('metre');
+insert into CollectionDB.PrimitiveUom (uom) values ('unity');
+
+create table CollectionDB.LiteralDataDomain (
+    possible_literal_values varchar,
+    default_value varchar,
+    data_type_id int references CollectionDB.PrimitiveDataTypes(id),
+    uom int references CollectionDB.PrimitiveUom(id),
+    def boolean
+) inherits (CollectionDB.ows_DataDescription);
+alter table CollectionDB.LiteralDataDomain add constraint literal_data_domain_id unique (id);
+
+create table CollectionDB.BoundingBoxData (
+    epsg int
+) inherits (CollectionDB.ows_DataDescription);
+alter table CollectionDB.BoundingBoxData add constraint bounding_box_data_id unique (id);
+
+create table CollectionDB.ComplexData (
+) inherits (CollectionDB.ows_DataDescription);
+alter table CollectionDB.ComplexData add constraint complex_data_id unique (id);
+
+create table CollectionDB.AllowedValues (
+    id serial primary key,
+    allowed_value varchar(255)
+);
+
+create table CollectionDB.AllowedValuesAssignment (
+    id serial primary key,
+    literal_data_domain_id int references CollectionDB.LiteralDataDomain (id),
+    allowed_value_id int references CollectionDB.AllowedValues (id)
+);
+
+create table CollectionDB.ows_AdditionalParameter (
+    id serial primary key,
+    key varchar,
+    value varchar,
+    additional_parameters_id int references CollectionDB.ows_AdditionalParameters(id)
+);
+
+create table CollectionDB.ows_Input (
+    id int primary key default nextval('collectiondb.descriptions_id_seq'::regclass),
+    title text,
+    abstract text,
+    identifier varchar(255),
+    min_occurs int,
+    max_occurs int
+); -- inherits (CollectionDB.Descriptions);
+alter table CollectionDB.ows_Input add constraint codb_input_id unique (id);
+CREATE TRIGGER ows_Input_proc AFTER INSERT ON CollectionDB.ows_Input FOR EACH ROW EXECUTE PROCEDURE update_Description();
+
+create table CollectionDB.ows_Output (
+    id int primary key default nextval('collectiondb.descriptions_id_seq'::regclass),
+    title text,
+    abstract text,
+    identifier varchar(255)
+); --inherits (CollectionDB.Descriptions);
+alter table CollectionDB.ows_Output add constraint codb_output_id unique (id);
+CREATE TRIGGER ows_Output_proc AFTER INSERT ON CollectionDB.ows_Output FOR EACH ROW EXECUTE PROCEDURE update_Description();
+
+create table CollectionDB.zoo_PrivateMetadata (
+    id serial primary key,
+    identifier varchar,
+    metadata_date timestamp
+);
+
+create table CollectionDB.ows_Process (
+    id int primary key default nextval('collectiondb.descriptions_id_seq'::regclass),
+    title text,
+    abstract text,
+    identifier varchar(255),
+    availability boolean,
+    process_description_xml text,
+    private_metadata_id int references CollectionDB.zoo_PrivateMetadata(id)
+); -- inherits (CollectionDB.Descriptions);
+alter table CollectionDB.ows_Process add constraint codb_process_id unique (id);
+alter table CollectionDB.ows_Process add constraint codb_process_identifier unique (identifier);
+CREATE TRIGGER ows_Process_proc AFTER INSERT ON CollectionDB.ows_Process FOR EACH ROW EXECUTE PROCEDURE update_Description();
+
+create table CollectionDB.InputInputAssignment (
+    id serial primary key,
+    parent_input int references CollectionDB.ows_Input(id),
+    child_input int references CollectionDB.ows_Input(id)
+);
+
+create table CollectionDB.InputDataDescriptionAssignment (
+    id serial primary key,
+    input_id int references CollectionDB.ows_Input(id),
+    data_description_id int check (CollectionDB.is_in_ows_DataDescription(data_description_id))
+);
+
+create table CollectionDB.OutputOutputAssignment (
+    id serial primary key,
+    parent_output int references CollectionDB.ows_Output(id),
+    child_output int references CollectionDB.ows_Output(id)
+);
+
+create table CollectionDB.OutputDataDescriptionAssignment (
+    id serial primary key,
+    output_id int references CollectionDB.ows_Output(id),
+    data_description_id int check (CollectionDB.is_in_ows_DataDescription(data_description_id))
+);
+
+create table CollectionDB.zoo_ServiceTypes (
+	id serial primary key,
+	service_type varchar
+);
+insert into CollectionDB.zoo_ServiceTypes (service_type) VALUES ('HPC');
+insert into CollectionDB.zoo_ServiceTypes (service_type) VALUES ('C');
+insert into CollectionDB.zoo_ServiceTypes (service_type) VALUES ('Java');
+insert into CollectionDB.zoo_ServiceTypes (service_type) VALUES ('Mono');
+insert into CollectionDB.zoo_ServiceTypes (service_type) VALUES ('JS');
+insert into CollectionDB.zoo_ServiceTypes (service_type) VALUES ('PHP');
+insert into CollectionDB.zoo_ServiceTypes (service_type) VALUES ('Python');
+
+insert into CollectionDB.zoo_ServiceTypes (service_type) VALUES ('OTB');
+
+create table CollectionDB.zoo_DeploymentMetadata (
+    id serial primary key,
+    executable_name varchar,
+    configuration_identifier varchar,
+	service_type_id int references CollectionDB.zoo_ServiceTypes(id)
+);
+
+create table CollectionDB.zoo_PrivateProcessInfo (
+    id serial primary key
+);
+
+create table CollectionDB.PrivateMetadataDeploymentMetadataAssignment (
+    id serial primary key,
+    private_metadata_id int references CollectionDB.zoo_PrivateMetadata(id),
+    deployment_metadata_id int references CollectionDB.zoo_DeploymentMetadata(id)
+);
+
+create table CollectionDB.PrivateMetadataPrivateProcessInfoAssignment (
+    id serial primary key,
+    private_metadata_id int references CollectionDB.zoo_PrivateMetadata(id),
+    private_process_info_id int references CollectionDB.zoo_PrivateProcessInfo(id)
+);
+
+create table CollectionDB.ProcessInputAssignment (
+    id serial primary key,
+    process_id int references CollectionDB.ows_Process(id),
+    input_id int references CollectionDB.ows_Input(id),
+    index int
+);
+
+create table CollectionDB.ProcessOutputAssignment (
+    id serial primary key,
+    process_id int references CollectionDB.ows_Process(id),
+    output_id int references CollectionDB.ows_Output(id),
+    index int
+);
+
+CREATE OR REPLACE VIEW public.ows_process AS
+       (SELECT
+	id,
+	identifier,
+	title,
+	abstract,
+	(SELECT service_type FROM CollectionDB.zoo_ServiceTypes WHERE id = (SELECT service_type_id FROM CollectionDB.zoo_DeploymentMetadata WHERE id = (SELECT deployment_metadata_id FROM CollectionDB.PrivateMetadataDeploymentmetadataAssignment WHERE private_metadata_id=(SELECT id FROM CollectionDB.zoo_PrivateMetadata WHERE id = CollectionDB.ows_Process.private_metadata_id)))) as service_type,
+	(SELECT executable_name  as service_provider FROM CollectionDB.zoo_DeploymentMetadata WHERE id = (SELECT deployment_metadata_id FROM CollectionDB.PrivateMetadataDeploymentmetadataAssignment WHERE private_metadata_id=(SELECT id FROM CollectionDB.zoo_PrivateMetadata WHERE id = CollectionDB.ows_Process.private_metadata_id))) as service_provider,
+	availability
+	FROM CollectionDB.ows_Process
+	WHERE
+	 availability
+	);
Index: trunk/zoo-project/zoo-kernel/sqlapi.c
===================================================================
--- trunk/zoo-project/zoo-kernel/sqlapi.c	(revision 889)
+++ trunk/zoo-project/zoo-kernel/sqlapi.c	(revision 917)
@@ -1,5 +1,5 @@
 /*
- * Author : David Saggiorato
- *          Gérald Fenoy
+ * Authors : David Saggiorato
+ *           Gérald Fenoy
  *  Copyright 2015 GeoLabs SARL. All rights reserved.
  *
@@ -23,5 +23,4 @@
  */
 
-#ifdef RELY_ON_DB
 #include "ogr_api.h"
 #include "ogrsf_frmts.h"
@@ -44,5 +43,5 @@
 OGRDataSource 
 #endif
- *zoo_DS = NULL;
+ **zoo_DS = NULL;
 
 /**
@@ -52,22 +51,29 @@
 
 /**
- * Create a GDAL / OGR string for connecting to the db backend
- * (do not support active_schema)
- * 
- * @param conf the maps containing the setting of the main.cfg file
- */
-char* createInitString(maps* conf){
+ * Create a GDAL / OGR string for connecting to a db backend defined in the
+ * key section.
+ * 
+ * @param conf the maps containing the setting of the main.cfg file
+ * @param key the name of the section containing the connection setting
+ * @return the OGR connection string
+ */
+char* _createInitString(maps* conf,const char* key){
   char* res=NULL;
-  char keywords[5][9]={
+  char keywords[6][14]={
     "dbname",
     "host",
     "port",
     "user",
-    "password"
+    "password",
+    "active_schema"    
   };
   int i=0;
-  maps* cconf=getMaps(conf,"database");
+  maps* cconf=getMaps(conf,key);
+  if(cconf==NULL){
+    fprintf(stderr,"%s %d\n",__FILE__,__LINE__);
+    return "-1";
+  }
   int len=0;
-  for(i=0;i<5;i++){
+  for(i=0;i<6;i++){
     map* tmp=getMap(cconf->content,keywords[i]);
     if(tmp!=NULL){
@@ -98,35 +104,91 @@
 
 /**
- * Connect to the db backend.
+ * Create a GDAL / OGR string for connecting to the db backend
+ * 
+ * @param conf the maps containing the setting of the main.cfg file
+ * @return the OGR connection string
+ */
+char* createInitString(maps* conf){
+  return _createInitString(conf,"database");
+}
+
+/**
+ * Connect to a db backend.
  * 
  * @param conf the maps containing the setting of the main.cfg file
  * @see createInitString
  */
-void init_sql(maps* conf){
-  char* sqlInitString=createInitString(conf);
+int _init_sql(maps* conf,const char* key){
+  char* sqlInitString=_createInitString(conf,key);
+#ifdef SQL_DEBUG
+  fprintf(stderr,"Try to connect to: %s %s !\n",key,sqlInitString);
+  fflush(stderr);  
+#endif
+  if(strncmp(sqlInitString,"-1",2)==0)
+    return -1;
   OGRSFDriver *poDriver = NULL;
   OGRRegisterAll();
-
+  int zoo_ds_nb=0;
+  map* dsNb=getMapFromMaps(conf,"lenv","ds_nb");
+  if(dsNb==NULL){
+    setMapInMaps(conf,"lenv","ds_nb","1");
+  }else{
+    zoo_ds_nb=atoi(dsNb->value);
+    char* tmp=(char*)malloc(11*sizeof(char));
+    sprintf(tmp,"%d",zoo_ds_nb+1);
+    setMapInMaps(conf,"lenv","ds_nb",(const char*)tmp);
+    free(tmp);
+  }
+  if(zoo_DS==NULL)
+    zoo_DS=
 #if GDAL_VERSION_MAJOR >= 2
-  zoo_DS = (GDALDataset*) GDALOpenEx( sqlInitString,
+      (GDALDataset**) malloc(sizeof(GDALDataset*))
+#else
+      (OGRDataSource**) malloc(sizeof(OGRDataSource*))
+#endif
+      ;
+  else
+    zoo_DS=      
+#if GDAL_VERSION_MAJOR >= 2
+      (GDALDataset**)realloc(zoo_DS,(zoo_ds_nb+1)*sizeof(GDALDataset*))
+#else
+      (OGRDataSource**)realloc(zoo_DS,(zoo_ds_nb+1)*sizeof(OGRDataSource*))
+#endif
+      ;
+  
+#if GDAL_VERSION_MAJOR >= 2
+  zoo_DS[zoo_ds_nb] = (GDALDataset*) GDALOpenEx( sqlInitString,
 				      GDAL_OF_UPDATE | GDAL_OF_VECTOR,
 				      NULL, NULL, NULL );
 #else
-  zoo_DS = OGRSFDriverRegistrar::Open(sqlInitString,false,&poDriver);
-#endif
-  if( zoo_DS == NULL ){
-#ifdef DEBUG
+  zoo_DS[zoo_ds_nb] = OGRSFDriverRegistrar::Open(sqlInitString,false,&poDriver);
+#endif
+  if( zoo_DS[zoo_ds_nb] == NULL ){
+#ifdef SQL_DEBUG
     fprintf(stderr,"sqlInitString: %s FAILED !\n",sqlInitString);
     fflush(stderr);
 #endif
     free(sqlInitString);
-    setMapInMaps(conf,"lenv","message","Failed to connect to the database backend");
-    return;
-  }
-#ifdef DEBUG
+    setMapInMaps(conf,"lenv","dbIssue","1");
+    setMapInMaps(conf,"lenv","message",_("Failed to connect to the database backend"));
+    return -2;
+  }
+#ifdef SQL_DEBUG
   fprintf(stderr,"sqlInitString: %s SUCEED !\n",sqlInitString);
   fflush(stderr);
 #endif
   free(sqlInitString);
+  zoo_ds_nb++;
+  return zoo_ds_nb;
+}
+
+/**
+ * Connect to the db backend.
+ * 
+ * @param conf the maps containing the setting of the main.cfg file
+ * @see createInitString
+ */
+int init_sql(maps* conf){
+  return _init_sql(conf,"database");
 }
 
@@ -136,14 +198,16 @@
  * @param conf the maps containing the setting of the main.cfg file
  */
-void close_sql(maps* conf){
-  if( zoo_ResultSet != NULL )
-    zoo_DS->ReleaseResultSet( zoo_ResultSet );
-  if(zoo_DS!=NULL){
+void close_sql(maps* conf,int cid){
+  if( zoo_ResultSet != NULL ){
+    zoo_DS[cid]->ReleaseResultSet( zoo_ResultSet );
+    zoo_ResultSet=NULL;
+  }
+  if(zoo_DS!=NULL && zoo_DS[cid]!=NULL){
 #if GDAL_VERSION_MAJOR >= 2
-    GDALClose(zoo_DS);
-#else
-    OGRDataSource::DestroyDataSource( zoo_DS );
-#endif
-    zoo_DS=NULL;
+    GDALClose(zoo_DS[cid]);
+#else
+    OGRDataSource::DestroyDataSource( zoo_DS[cid] );
+#endif
+    zoo_DS[cid]=NULL;
   }
 }
@@ -158,4 +222,30 @@
 
 /**
+ * Fetch a tuple set by executing a SQL query to the Database Backend.
+ * 
+ * @param conf the maps containing the setting of the main.cfg file
+ * @param sqlQuery the SQL query to run
+ * @return NULL in case of failure or an OGRLayer pointer if the query succeed.
+ */
+OGRLayer *fetchSql(maps* conf,int cid,const char* sqlQuery){
+  if(zoo_DS==NULL || zoo_DS[cid]==NULL)
+    return NULL;
+  OGRLayer *res=NULL;
+#ifdef SQL_DEBUG
+  fprintf(stderr,"************************* %s %s %d\n\n",sqlQuery,__FILE__,__LINE__);
+  fflush(stderr);
+#endif
+  res = zoo_DS[cid]->ExecuteSQL( sqlQuery, NULL, NULL);
+  return res;
+}
+
+void cleanFetchSql(maps* conf,int cid,OGRLayer *objects){
+  if( objects != NULL ){
+    zoo_DS[cid]->ReleaseResultSet( objects );
+    objects=NULL;
+  }
+}
+
+/**
  * Execute a SQL query to the SQL Database Backend.
  * 
@@ -164,10 +254,13 @@
  * @return -1 in case of failure and 1 if the query succeed.
  */
-int execSql(maps* conf,const char* sqlQuery){
-  zoo_ResultSet = zoo_DS->ExecuteSQL( sqlQuery, NULL, NULL);
+int execSql(maps* conf,int cid,const char* sqlQuery){
+  int res=-1;
+  if(zoo_DS == NULL || zoo_DS[cid]==NULL)
+    return -1;
+  zoo_ResultSet = zoo_DS[cid]->ExecuteSQL( sqlQuery, NULL, NULL);
   if( zoo_ResultSet != NULL ){
-    return 1;
-  }
-  return -1;
+    res=1;
+  }
+  return res;
 }
 
@@ -179,9 +272,18 @@
  * @return -1 in case of failure and 1 if the query succeed.
  */
-void cleanUpResultSet(const maps* conf){
+void cleanUpResultSet(const maps* conf,int cid){
   if( zoo_ResultSet != NULL ){
-    zoo_DS->ReleaseResultSet( zoo_ResultSet );
+    zoo_DS[cid]->ReleaseResultSet( zoo_ResultSet );
     zoo_ResultSet=NULL;
   }
+}
+
+#ifdef RELY_ON_DB
+int getCurrentId(maps* conf){
+  int res=0;
+  map* dsNb=getMapFromMaps(conf,"lenv","ds_nb");
+  if(dsNb!=NULL)
+    res=atoi(dsNb->value);
+  return res;
 }
 
@@ -195,4 +297,5 @@
  */
 void recordStoredFile(maps* conf,const char* filename,const char* type,const char* name){
+  int zoo_ds_nb=getCurrentId(conf);
   map *uusid=getMapFromMaps(conf,"lenv","usid");
   map *schema=getMapFromMaps(conf,"database","schema");
@@ -202,7 +305,7 @@
   else
     sprintf(sqlQuery,"INSERT INTO %s.files (uuid,filename,nature,name) VALUES ('%s','%s','%s',NULL);",schema->value,uusid->value,filename,type);
-  execSql(conf,sqlQuery);
-  free(sqlQuery);
-  cleanUpResultSet(conf);
+  execSql(conf,zoo_ds_nb-1,sqlQuery);
+  free(sqlQuery);
+  cleanUpResultSet(conf,zoo_ds_nb-1);
 }
 
@@ -213,4 +316,5 @@
  */
 void recordServiceStatus(maps* conf){
+  int zoo_ds_nb=getCurrentId(conf);
   map *sid=getMapFromMaps(conf,"lenv","sid");
   map *osid=getMapFromMaps(conf,"lenv","osid");
@@ -230,7 +334,7 @@
 	  osid->value,
 	  wpsStatus[2]);
-  execSql(conf,sqlQuery);
-  free(sqlQuery);
-  cleanUpResultSet(conf);
+  execSql(conf,zoo_ds_nb-1,sqlQuery);
+  free(sqlQuery);
+  cleanUpResultSet(conf,zoo_ds_nb-1);
 }
 
@@ -242,4 +346,5 @@
  */
 void recordResponse(maps* conf,char* filename){
+  int zoo_ds_nb=getCurrentId(conf);
   FILE *file = fopen (filename, "rb");
   fseek (file, 0, SEEK_END);
@@ -254,8 +359,8 @@
   char *sqlQuery=(char*)malloc((strlen(schema->value)+flen+strlen(sid->value)+57+1)*sizeof(char));
   sprintf(sqlQuery,"INSERT INTO %s.responses (content,uuid) VALUES ($$%s$$,$$%s$$);",schema->value,tmps,sid->value);
-  execSql(conf,sqlQuery);
+  execSql(conf,zoo_ds_nb-1,sqlQuery);
   free(sqlQuery);
   free(tmps);
-  cleanUpResultSet(conf);
+  cleanUpResultSet(conf,zoo_ds_nb-1);
 }
 
@@ -267,4 +372,5 @@
  */
 int _updateStatus(maps* conf){
+  int zoo_ds_nb=getCurrentId(conf);
   map *sid=getMapFromMaps(conf,"lenv","usid");
   map *p=getMapFromMaps(conf,"lenv","status");
@@ -273,9 +379,10 @@
   char *sqlQuery=(char*)malloc((strlen(schema->value)+strlen(msg->value)+strlen(p->value)+strlen(sid->value)+64+1)*sizeof(char));
   sprintf(sqlQuery,"UPDATE %s.services set status=$$%s$$,message=$$%s$$ where uuid=$$%s$$;",schema->value,p->value,msg->value,sid->value);
-  fflush(stderr);
-  if( zoo_DS == NULL )
+  if( zoo_DS == NULL || zoo_DS[zoo_ds_nb-1]==NULL ){
     init_sql(conf);
-  execSql(conf,sqlQuery);
-  cleanUpResultSet(conf);
+    zoo_ds_nb++;
+  }
+  execSql(conf,zoo_ds_nb-1,sqlQuery);
+  cleanUpResultSet(conf,zoo_ds_nb-1);
   free(sqlQuery);
   return 0;
@@ -290,10 +397,21 @@
  */
 char* _getStatus(maps* conf,char* pid){
+  int zoo_ds_nb=getCurrentId(conf);
+  int created=-1;
   map *schema=getMapFromMaps(conf,"database","schema");
   char *sqlQuery=(char*)malloc((strlen(schema->value)+strlen(pid)+58+1)*sizeof(char));
   sprintf(sqlQuery,"select status||'|'||message from %s.services where uuid=$$%s$$;",schema->value,pid);
-  if( zoo_DS == NULL )
+  if( zoo_ds_nb==
+#ifdef META_DB
+      1
+#else
+      0
+#endif
+      ){
     init_sql(conf);
-  execSql(conf,sqlQuery);
+    zoo_ds_nb++;
+    created=1;
+  }
+  execSql(conf,zoo_ds_nb-1,sqlQuery);
   OGRFeature  *poFeature = NULL;
   const char *tmp1;
@@ -301,5 +419,5 @@
     for( int iField = 0; iField < poFeature->GetFieldCount(); iField++ ){
       if( poFeature->IsFieldSet( iField ) ){
-	tmp1=strdup(poFeature->GetFieldAsString( iField ));
+	tmp1=zStrdup(poFeature->GetFieldAsString( iField ));
       }
       else
@@ -308,5 +426,5 @@
     OGRFeature::DestroyFeature( poFeature );
   }
-  cleanUpResultSet(conf);
+  cleanUpResultSet(conf,zoo_ds_nb-1);
   free(sqlQuery);
   return (char*)tmp1;
@@ -321,29 +439,40 @@
  */
 char* _getStatusFile(maps* conf,char* pid){
-  map *schema=getMapFromMaps(conf,"database","schema");
+  int zoo_ds_nb=getCurrentId(conf);
+  map *schema=getMapFromMaps(conf,"database","schema");
+  OGRFeature  *poFeature = NULL;
+  const char *tmp1=NULL;
+  int hasRes=-1;
   char *sqlQuery=(char*)malloc((strlen(schema->value)+strlen(pid)+82+1)*sizeof(char));
   sprintf(sqlQuery,
 	  "select content from %s.responses where uuid=$$%s$$"
 	  " order by creation_time desc limit 1",schema->value,pid);
-  if( zoo_DS == NULL )
+  if( zoo_ds_nb==
+#ifdef META_DB
+      1
+#else
+      0
+#endif
+      ){
     init_sql(conf);
-  execSql(conf,sqlQuery);
-  OGRFeature  *poFeature = NULL;
-  const char *tmp1;
-  int hasRes=-1;
-  while( (poFeature = zoo_ResultSet->GetNextFeature()) != NULL ){
-    for( int iField = 0; iField < poFeature->GetFieldCount(); iField++ ){
-      if( poFeature->IsFieldSet( iField ) ){
-	tmp1=strdup(poFeature->GetFieldAsString( iField ));
-	hasRes=1;
+    zoo_ds_nb++;
+  }
+  execSql(conf,zoo_ds_nb-1,sqlQuery);
+  if(zoo_ResultSet!=NULL){
+      while( (poFeature = zoo_ResultSet->GetNextFeature()) != NULL ){
+	for( int iField = 0; iField < poFeature->GetFieldCount(); iField++ ){
+	  if( poFeature->IsFieldSet( iField ) ){
+	    tmp1=zStrdup(poFeature->GetFieldAsString( iField ));
+	    hasRes=1;
+	  }
+	  else
+	    tmp1=NULL;
+	}
+	OGRFeature::DestroyFeature( poFeature );
       }
-      else
-	tmp1=NULL;
-    }
-    OGRFeature::DestroyFeature( poFeature );
   }
   if(hasRes<0)
     tmp1=NULL;
-  cleanUpResultSet(conf);
+  cleanUpResultSet(conf,zoo_ds_nb-1);
   free(sqlQuery);
   return (char*)tmp1;
@@ -357,16 +486,25 @@
  */
 void removeService(maps* conf,char* pid){
+  int zoo_ds_nb=getCurrentId(conf);
   map *schema=getMapFromMaps(conf,"database","schema");
   char *sqlQuery=(char*)
     malloc((strlen(pid)+strlen(schema->value)+38+1)
 	   *sizeof(char));
-  if( zoo_DS == NULL )
+  if( zoo_ds_nb==
+#ifdef META_DB
+      1
+#else
+      0
+#endif
+      ){
     init_sql(conf);
+    zoo_ds_nb++;
+  }
   sprintf(sqlQuery,
 	  "DELETE FROM %s.services where uuid=$$%s$$;",
 	  schema->value,pid);
-  execSql(conf,sqlQuery);
-  cleanUpResultSet(conf);
-  close_sql(conf);
+  execSql(conf,zoo_ds_nb-1,sqlQuery);
+  cleanUpResultSet(conf,zoo_ds_nb-1);
+  close_sql(conf,zoo_ds_nb-1);
   free(sqlQuery);
   end_sql();
@@ -379,4 +517,5 @@
  */
 void unhandleStatus(maps* conf){
+  int zoo_ds_nb=getCurrentId(conf);
   map *schema=getMapFromMaps(conf,"database","schema");
   map *sid=getMapFromMaps(conf,"lenv","usid");
@@ -392,9 +531,9 @@
 	  " where uuid=$$%s$$;",
 	  schema->value,(fstate!=NULL?fstate->value:"Failed"),sid->value);
-  execSql(conf,sqlQuery);
-  cleanUpResultSet(conf);
-  close_sql(conf);
-  free(sqlQuery);
-  end_sql();
+  execSql(conf,zoo_ds_nb-1,sqlQuery);
+  cleanUpResultSet(conf,zoo_ds_nb-1);
+  //close_sql(conf,zoo_ds_nb-1);
+  free(sqlQuery);
+  //end_sql();
 }
 
@@ -407,4 +546,5 @@
  */
 char* getStatusId(maps* conf,char* pid){
+  int zoo_ds_nb=getCurrentId(conf);
   map *schema=getMapFromMaps(conf,"database","schema");
   char *sqlQuery=(char*)malloc((strlen(schema->value)+strlen(pid)+58+1)*sizeof(char));
@@ -412,7 +552,10 @@
 	  "select osid from %s.services where uuid=$$%s$$",
 	  schema->value,pid);
-  if( zoo_DS == NULL )
+  if( zoo_ds_nb==0 ){
     init_sql(conf);
-  execSql(conf,sqlQuery);
+    zoo_ds_nb++;
+  }
+  if(execSql(conf,zoo_ds_nb-1,sqlQuery)<0)
+    return NULL;
   OGRFeature  *poFeature = NULL;
   const char *tmp1;
@@ -431,4 +574,5 @@
     tmp1=NULL;
   free(sqlQuery);
+  cleanUpResultSet(conf,zoo_ds_nb-1);
   return (char*)tmp1;
 }
@@ -441,4 +585,5 @@
  */
 void readFinalRes(maps* conf,char* pid,map* statusInfo){
+  int zoo_ds_nb=getCurrentId(conf);
   map *schema=getMapFromMaps(conf,"database","schema");
   char *sqlQuery=(char*)malloc((strlen(schema->value)+strlen(pid)+58+1)*sizeof(char));
@@ -448,5 +593,5 @@
   if( zoo_DS == NULL )
     init_sql(conf);
-  execSql(conf,sqlQuery);
+  execSql(conf,zoo_ds_nb-1,sqlQuery);
   OGRFeature  *poFeature = NULL;
   int hasRes=-1;
@@ -461,4 +606,5 @@
     OGRFeature::DestroyFeature( poFeature );
   }
+  cleanUpResultSet(conf,zoo_ds_nb-1);
   if(hasRes<0)
     addToMap(statusInfo,"Status","Failed");
@@ -476,10 +622,13 @@
 int isRunning(maps* conf,char* pid){
   int res=0;
+  int zoo_ds_nb=getCurrentId(conf);
   map *schema=getMapFromMaps(conf,"database","schema");
   char *sqlQuery=(char*)malloc((strlen(schema->value)+strlen(pid)+73+1)*sizeof(char));
   sprintf(sqlQuery,"select count(*) as t from %s.services where uuid=$$%s$$ and end_time is null;",schema->value,pid);
-  if( zoo_DS == NULL )
+  if( zoo_ds_nb == 0 ){
     init_sql(conf);
-  execSql(conf,sqlQuery);
+    zoo_ds_nb++;
+  }
+  execSql(conf,zoo_ds_nb-1,sqlQuery);
   OGRFeature  *poFeature = NULL;
   const char *tmp1;
@@ -494,5 +643,5 @@
     OGRFeature::DestroyFeature( poFeature );
   }
-  cleanUpResultSet(conf);
+  cleanUpResultSet(conf,zoo_ds_nb-1);
   free(sqlQuery);
   return res;
Index: trunk/zoo-project/zoo-kernel/sqlapi.h
===================================================================
--- trunk/zoo-project/zoo-kernel/sqlapi.h	(revision 889)
+++ trunk/zoo-project/zoo-kernel/sqlapi.h	(revision 917)
@@ -25,14 +25,41 @@
 #ifndef ZOO_SQLAPI_H
 #define ZOO_SQLAPI_H 1
-#ifdef RELY_ON_DB
+
+#ifdef META_DB
+#include "ogrsf_frmts.h"
+#include "ogr_p.h"
+#if GDAL_VERSION_MAJOR >= 2
+#include <gdal_priv.h>
+#endif
+#endif
+
 #include "service.h"
 #include "service_internal.h"
+
+#ifdef META_DB
+extern "C" 
+#if GDAL_VERSION_MAJOR >=2
+  GDALDataset
+#else
+  OGRDataSource 
+#endif
+  **zoo_DS;
+#endif
 
 #ifdef __cplusplus
 extern "C" {
 #endif
-  ZOO_DLL_EXPORT void init_sql(maps*);
-  ZOO_DLL_EXPORT void close_sql(maps*);
-  ZOO_DLL_EXPORT int execSql(maps*,const char*);
+
+  
+#ifdef META_DB
+  ZOO_DLL_EXPORT char* _createInitString(maps*,const char*);
+  ZOO_DLL_EXPORT int _init_sql(maps*,const char*);
+  ZOO_DLL_EXPORT OGRLayer *fetchSql(maps*,int,const char*);
+  ZOO_DLL_EXPORT void cleanFetchSql(maps*,int,OGRLayer*);
+#endif
+#ifdef RELY_ON_DB
+  ZOO_DLL_EXPORT int init_sql(maps*);
+  ZOO_DLL_EXPORT void close_sql(maps*,int);
+  ZOO_DLL_EXPORT int execSql(maps*,int,const char*);
   ZOO_DLL_EXPORT void recordStoredFile(maps*,const char*,const char*,const char*);
   ZOO_DLL_EXPORT void recordServiceStatus(maps*);
@@ -42,4 +69,6 @@
   ZOO_DLL_EXPORT char* getStatusId(maps*,char*);
   ZOO_DLL_EXPORT void removeService(maps*,char*);
+  ZOO_DLL_EXPORT void end_sql();
+#endif
 
 #ifdef __cplusplus
@@ -48,3 +77,2 @@
 
 #endif
-#endif
Index: trunk/zoo-project/zoo-kernel/sshapi.c
===================================================================
--- trunk/zoo-project/zoo-kernel/sshapi.c	(revision 917)
+++ trunk/zoo-project/zoo-kernel/sshapi.c	(revision 917)
@@ -0,0 +1,763 @@
+/*
+ *
+ * Author : Gérald FENOY
+ *
+ * Copyright 2017-2019 GeoLabs SARL. All rights reserved.
+ *
+ * This work was supported by public funds received in the framework of GEOSUD,
+ * a project (ANR-10-EQPX-20) of the program "Investissements d'Avenir" managed 
+ * by the French National Research Agency
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "sshapi.h"
+#include "service_internal.h"
+
+SSHCON *sessions[MAX_PARALLEL_SSH_CON];
+
+/**
+ * Wait until one or more file descriptor has been changed for the socket for a
+ * time defined by timeout
+ * @param socket_fd int defining the sockket file descriptor
+ * @param session an exeisting LIBSSH2_SESSION
+ */ 
+int waitsocket(int socket_fd, LIBSSH2_SESSION *session)
+{
+    struct timeval timeout;
+    int rc;
+    fd_set fd;
+    fd_set *writefd = NULL;
+    fd_set *readfd = NULL;
+    int dir;
+ 
+    timeout.tv_sec = 10;
+    timeout.tv_usec = 0;
+ 
+    FD_ZERO(&fd);
+ 
+    FD_SET(socket_fd, &fd);
+ 
+    /* now make sure we wait in the correct direction */ 
+    dir = libssh2_session_block_directions(session);
+
+ 
+    if(dir & LIBSSH2_SESSION_BLOCK_INBOUND)
+        readfd = &fd;
+ 
+    if(dir & LIBSSH2_SESSION_BLOCK_OUTBOUND)
+        writefd = &fd;
+ 
+    rc = select(socket_fd + 1, readfd, writefd, NULL, &timeout);
+ 
+    return rc;
+}
+
+/**
+ * Connect to a remote host using SSH protocol
+ * @param conf maps The main configuration maps
+ * @return the libssh2 sessions pointer or NULL in case any failure occured. 
+ */
+SSHCON *ssh_connect(maps* conf){
+  unsigned long hostaddr;
+  int i, use_pw = 1;
+  struct sockaddr_in sin;
+  const char *fingerprint;
+  SSHCON *result=(SSHCON*)malloc((2*sizeof(int))+sizeof(LIBSSH2_SESSION*)+sizeof(LIBSSH2_SFTP*));
+  result->sock_id=NULL;
+  result->index=NULL;
+  result->session=NULL;
+  result->sftp_session=NULL;
+  const char *user;
+  const char *password=NULL;
+  const char *public_key;
+  char *private_key;
+  int rc;
+  FILE *local;
+  char mem[1024 * 1000];
+  char error[1024];
+  int port=22;
+
+  map* hpc_config=getMapFromMaps(conf,"lenv","configId");
+  map* hpc_host=getMapFromMaps(conf,hpc_config->value,"ssh_host");
+  map* hpc_port=getMapFromMaps(conf,hpc_config->value,"ssh_port");
+  map* hpc_user=getMapFromMaps(conf,hpc_config->value,"ssh_user");
+  map* hpc_password=getMapFromMaps(conf,hpc_config->value,"ssh_password");
+  map* hpc_public_key=getMapFromMaps(conf,hpc_config->value,"ssh_key");
+  
+  char ip[100];
+  struct hostent *my_hostent;
+  struct in_addr **addrs;
+  
+  if (hpc_host != NULL) {
+    // Fetch ip address for the hostname
+    if ( (my_hostent = gethostbyname( hpc_host->value ) ) == NULL){
+      herror("gethostbyname");
+      setMapInMaps(conf,"lenv","message",_("Issue when invoking gethostbyname!"));
+      return NULL;
+    }
+ 
+    addrs = (struct in_addr **) my_hostent->h_addr_list;
+  
+    for(i = 0; addrs[i] != NULL; i++) {
+      strcpy(ip , inet_ntoa(*addrs[i]) );
+      break;
+    }
+  }
+
+#ifdef WIN32
+  WSADATA wsadata;
+  int err;
+  err = WSAStartup(MAKEWORD(2,0), &wsadata);
+  if (err != 0) {
+    sprintf(error, "WSAStartup failed with error: %d\n", err);
+    setMapInMaps(conf,"lenv","message",error);
+    return NULL;
+  }
+#endif
+
+  if (hpc_host != NULL) {
+    hostaddr = inet_addr(ip);
+  } else {
+    setMapInMaps(conf,"lenv","message","No host parameter found in your main.cfg file!\n");
+    return NULL;
+  }
+
+  // Default port is 22
+  if(hpc_port!=NULL){
+    port=atoi(hpc_port->value);
+  }
+
+  // In case there is no HPC > user the it must failed
+  if (hpc_user != NULL) {
+    user = hpc_user->value;
+  }else{
+    setMapInMaps(conf,"lenv","message","No user parameter found in your main.cfg file!");
+    return NULL;
+  }
+
+  // TODO: in case password is available but there is also the public key
+  // defined, then we can consider this password as the pass phrase.
+  if (hpc_password != NULL) {
+    password = hpc_password->value;
+  }else{
+    use_pw=-1;
+    if (hpc_public_key != NULL) {
+      public_key = hpc_public_key->value;
+      private_key = zStrdup(hpc_public_key->value);
+      private_key[strlen(public_key)-4]=0;
+    }else{
+      setMapInMaps(conf,"lenv","message","No method found to authenticate!");
+      return NULL;
+    }
+  }
+
+  rc = libssh2_init (0);
+  if (rc != 0) {
+    sprintf (error, "libssh2 initialization failed (%d)\n", rc);
+    setMapInMaps(conf,"lenv","message",error);
+    return NULL;
+  }
+
+  result->sock_id = socket(AF_INET, SOCK_STREAM, 0);
+  sin.sin_family = AF_INET;
+  sin.sin_port = htons(port);
+  sin.sin_addr.s_addr = hostaddr;
+  if (connect(result->sock_id, (struct sockaddr*)(&sin),sizeof(struct sockaddr_in)) != 0) {
+    setMapInMaps(conf,"lenv","message","Failed to connect to remote host!");
+    return NULL;
+  }
+
+  result->session = libssh2_session_init();
+  result->sftp_session = NULL;
+  map* tmp=getMapFromMaps(conf,"lenv","nb_sessions");
+  if(tmp!=NULL){
+    char nb_sessions[10];
+    int nb_sess=atoi(tmp->value);
+    sprintf(nb_sessions,"%d",nb_sess+1);
+    setMapInMaps(conf,"lenv","nb_sessions",nb_sessions);
+    result->index=nb_sess+1;
+    sessions[nb_sess+1]=result;
+  }else{
+    setMapInMaps(conf,"lenv","nb_sessions","0");
+    sessions[0]=result;
+    result->index=0;
+  }
+
+  if (!result->session)
+    return NULL;
+
+  libssh2_session_set_blocking(result->session, 1);
+
+  while ((rc = libssh2_session_handshake(result->session, result->sock_id))
+	 == LIBSSH2_ERROR_EAGAIN);
+
+  if (rc) {
+    sprintf(error, "Failure establishing SSH session: %d\n", rc);
+    setMapInMaps(conf,"lenv","message",error);
+    return NULL;
+  }
+
+  fingerprint = libssh2_hostkey_hash(result->session, LIBSSH2_HOSTKEY_HASH_SHA1);
+  
+  if (use_pw>0) {
+    while ((rc = libssh2_userauth_password(result->session, user, password)) ==
+	   LIBSSH2_ERROR_EAGAIN);
+    if (rc) {
+      setMapInMaps(conf,"lenv","message","Authentication by password failed.");
+      ssh_close(conf);
+      return NULL;
+    }
+  } else {
+    while ((rc = libssh2_userauth_publickey_fromfile(result->session, user,
+						     public_key,
+						     private_key,
+						     password)) ==
+	   LIBSSH2_ERROR_EAGAIN);
+    if (rc) {
+      setMapInMaps(conf,"lenv","message","Authentication by public key failed");
+      ssh_close(conf);
+      return NULL;
+    }
+    free(private_key);
+  }
+
+  return result;
+
+}
+
+/** 
+ * Get the number of opened SSH connections
+ * @param conf maps pointer to the main configuration maps
+ * @return the number of opened SSH connections
+ */
+int ssh_get_cnt(maps* conf){
+  int result=0;
+  map* myMap=getMapFromMaps(conf,"lenv","nb_sessions");
+  if(myMap!=NULL){
+    result=atoi(myMap->value);
+  }
+  return result;
+}
+
+/** 
+ * Verify if a file exists on the remote host
+ * @param conf maps pointer to the main configuration maps
+ * @param targetPath const char* defining the path for storing the file on the
+ * remote host
+ * @return true in case of success, false if failure occured
+ */
+size_t ssh_file_exists(maps* conf,const char* targetPath,int cnt){
+  size_t result=-1;
+  if(cnt>0)
+    cnt-=1;
+  int rc;
+  LIBSSH2_SFTP_ATTRIBUTES attrs;
+  LIBSSH2_SFTP_HANDLE *sftp_handle;
+  do{
+    sftp_handle =
+      libssh2_sftp_open(sessions[cnt]->sftp_session, targetPath, LIBSSH2_FXF_READ,
+			LIBSSH2_SFTP_S_IRUSR|LIBSSH2_SFTP_S_IWUSR|
+			LIBSSH2_SFTP_S_IRGRP|LIBSSH2_SFTP_S_IROTH);
+    if (!sftp_handle) {
+      fprintf(stderr, "Unable to open file with SFTP: %d %ld\n",__LINE__,
+	      libssh2_sftp_last_error(sessions[cnt]->sftp_session));
+      return 0;
+    }
+  }while(!sftp_handle);
+#ifdef SSH_DEBUG
+  fprintf(stderr, "libssh2_sftp_open() is done, get file information\n");
+#endif
+  do {
+  rc = libssh2_sftp_stat_ex(sessions[cnt]->sftp_session, targetPath, strlen(targetPath),
+			    LIBSSH2_SFTP_LSTAT, &attrs );
+  if (rc<0 &&
+      (libssh2_session_last_errno(sessions[cnt]->session) != LIBSSH2_ERROR_EAGAIN))
+    {
+      fprintf(stderr, "error trying to fstat_ex, returned %d\n", rc);
+      break;
+    }
+  else
+    {
+#ifdef SSH_DEBUG
+      fprintf(stderr, "Stat Data: RetCode=%d\n", rc);
+      fprintf(stderr, "Stat Data: Size=%llu\n", attrs.filesize);
+      fprintf(stderr, "Stat Data: Perm=%lx\n",  attrs.permissions);
+      fprintf(stderr, "Stat Data: mtime=%lu\n",  attrs.mtime);
+#endif
+      if(rc==0)
+	break;
+      result=attrs.filesize;
+    }
+  } while (true);
+  libssh2_sftp_close(sftp_handle);
+  //libssh2_sftp_shutdown(sessions[cnt]->sftp_session);
+
+  return result;
+}
+
+/** 
+ * Upload a file over an opened SSH connection
+ * @param conf maps pointer to the main configuration maps
+ * @param localPath const char* defining the local path for accessing the file
+ * @param targetPath const char* defining the path for storing the file on the
+ * remote host
+ * @return true in case of success, false if failure occured
+ */
+bool ssh_copy(maps* conf,const char* localPath,const char* targetPath,int cnt){
+  char mem[1024 * 16];
+  size_t nread;
+  size_t memuse=0;
+  time_t start;
+  long total = 0;
+  int counter=0;
+  int duration;
+  int rc;
+  LIBSSH2_SFTP_HANDLE *sftp_handle;
+  //map* myMap=getMapFromMaps(conf,"lenv","cnt_session");
+  if(getMapFromMaps(conf,"lenv","cnt_session")!=NULL){
+    char tmp[10];
+    sprintf(tmp,"%d",cnt+1);
+    setMapInMaps(conf,"lenv","cnt_session",tmp);
+  }else
+    setMapInMaps(conf,"lenv","cnt_session","0");
+  FILE *local = fopen(localPath, "rb");
+  if (!local) {
+    fprintf(stderr, "Can't open local file %s\n", localPath);
+    return false;
+  }
+  
+  do {
+    sessions[cnt]->sftp_session = libssh2_sftp_init(sessions[cnt]->session);
+    if (!sessions[cnt]->sftp_session &&
+	(libssh2_session_last_errno(sessions[cnt]->session) != LIBSSH2_ERROR_EAGAIN)) {
+      
+      fprintf(stderr, "Unable to init SFTP session\n");
+      return false;
+    }
+    if(!sessions[cnt]->sftp_session)
+      zSleep(10);
+  } while (!sessions[cnt]->sftp_session);
+
+  do {
+    sftp_handle =
+      libssh2_sftp_open(sessions[cnt]->sftp_session, targetPath,
+			LIBSSH2_FXF_WRITE|LIBSSH2_FXF_CREAT|LIBSSH2_FXF_TRUNC,
+			LIBSSH2_SFTP_S_IRUSR|LIBSSH2_SFTP_S_IWUSR|
+			LIBSSH2_SFTP_S_IRGRP|LIBSSH2_SFTP_S_IROTH);
+
+    if (!sftp_handle &&
+	(libssh2_session_last_errno(sessions[cnt]->session) != LIBSSH2_ERROR_EAGAIN)) {
+      
+      fprintf(stderr, "Unable to open file with SFTP\n");
+      return false;
+    }
+    if(!sftp_handle)
+      zSleep(10);
+  } while (!sftp_handle);
+  start = time(NULL);
+  
+  do {
+    nread = fread(&mem[memuse], 1, sizeof(mem)-memuse, local);
+    if (nread <= 0) {
+      if (memuse > 0)
+	nread = 0;
+      else
+	break;
+    }
+    memuse += nread;
+    total += nread;
+    
+    while ((rc = libssh2_sftp_write(sftp_handle, mem, memuse)) ==
+	   LIBSSH2_ERROR_EAGAIN) {
+      waitsocket(sessions[cnt]->sock_id, sessions[cnt]->session);
+    }
+    if(rc < 0)
+      break;
+    
+    memuse = 0;
+    
+  } while (rc > 0);
+  
+  duration = (int)(time(NULL)-start);
+  fclose(local);
+  libssh2_sftp_close_handle(sftp_handle);
+
+  libssh2_sftp_shutdown(sessions[cnt]->sftp_session);
+  return true;
+}
+
+/** 
+ * Download a file over an opened SSH connection
+ * @param conf maps pointer to the main configuration maps
+ * @param localPath const char* defining the local path for storing the file
+ * @param targetPath const char* defining the path for accessing the file on the
+ * remote host
+ * @return 0 in case of success, -1 if failure occured
+ */
+int ssh_fetch(maps* conf,const char* localPath,const char* targetPath,int cnt){
+  size_t nread;
+  size_t memuse=0;
+  time_t start;
+  long total = 0;
+  int duration;
+  int rc;
+  LIBSSH2_SFTP_HANDLE *sftp_handle;
+  FILE *local = fopen(localPath, "wb");
+  if (!local) {
+    fprintf(stderr, "Can't open local file %s\n", localPath);
+    return -1;
+  }
+
+  do {
+    sessions[cnt]->sftp_session = libssh2_sftp_init(sessions[cnt]->session);
+    if (!sessions[cnt]->sftp_session &&
+	(libssh2_session_last_errno(sessions[cnt]->session) != LIBSSH2_ERROR_EAGAIN)) {
+      fprintf(stderr, "Unable to init SFTP session\n");
+      return -1;
+    }
+    if(!sessions[cnt]->sftp_session)
+      zSleep(10);
+  } while (!sessions[cnt]->sftp_session);
+  do {
+    sftp_handle = libssh2_sftp_open(sessions[cnt]->sftp_session, targetPath,   
+				    LIBSSH2_FXF_READ, 0);
+    if (!sftp_handle) {
+      if (libssh2_session_last_errno(sessions[cnt]->session) != LIBSSH2_ERROR_EAGAIN) {
+	fprintf(stderr, " ** Unable to open file with SFTP\n");
+	return -1;
+      }
+      else {
+	waitsocket(sessions[cnt]->sock_id, sessions[cnt]->session); 
+      }
+    }
+    if(!sftp_handle)
+      zSleep(10);
+  } while (!sftp_handle);
+
+  int result=0;
+  int counter=0;
+  do {
+    do {
+      char* mem=(char*)malloc(16*1024);
+      rc = libssh2_sftp_read(sftp_handle, mem,16*1024);
+      if(rc > 0) {
+	fwrite(mem, rc, 1, local);
+      }
+      free(mem);
+      if(counter%25==0)
+	zSleep(10);
+    } while (rc > 0);
+
+    if(rc != LIBSSH2_ERROR_EAGAIN) {
+      result=-1;
+      break;
+    }
+
+    struct timeval timeout;
+    fd_set fd;
+    timeout.tv_sec = 10;
+    timeout.tv_usec = 0;
+
+    FD_ZERO(&fd);
+
+    FD_SET(sessions[cnt]->sock_id, &fd);
+
+    rc = select(sessions[cnt]->sock_id+1, &fd, &fd, NULL, &timeout);
+    if(rc <= 0) {
+      if(rc==0)
+	fprintf(stderr, "SFTP download timed out: %d\n", rc);
+      else
+	fprintf(stderr, "SFTP download error: %d\n", rc);
+      return -1;
+    }
+
+    if(counter%50==0)
+       zSleep(10);
+    counter++;
+
+  } while (1);
+  duration = (int)(time(NULL)-start);
+  fclose(local);
+  libssh2_sftp_close_handle(sftp_handle);
+  libssh2_sftp_shutdown(sessions[cnt]->sftp_session);
+  return 0;
+}
+
+/** 
+ * Execute a command over an opened SSH connection
+ * @param conf maps pointer to the main configuration maps
+ * @param command const char pointer to the command to be executed
+ * @return bytecount resulting from the execution of the command
+ */
+int ssh_exec(maps* conf,const char* command,int cnt){
+  LIBSSH2_CHANNEL *channel;
+  int rc;
+  int bytecount = 0;
+  int exitcode;
+  char *exitsignal=(char *)"none";
+  while( (channel = libssh2_channel_open_session(sessions[cnt]->session)) == NULL &&
+	 libssh2_session_last_error(sessions[cnt]->session,NULL,NULL,0) == LIBSSH2_ERROR_EAGAIN ) {
+    waitsocket(sessions[cnt]->sock_id, sessions[cnt]->session);
+  }
+  if( channel == NULL ){
+    fprintf(stderr,"Error\n");
+    return -1;
+  }
+  while( (rc = libssh2_channel_exec(channel, command)) == LIBSSH2_ERROR_EAGAIN ) {
+    waitsocket(sessions[cnt]->sock_id, sessions[cnt]->session);
+  }
+  if( rc != 0 ) {
+    fprintf(stderr,"Error\n");
+    return -1;
+  }
+
+  map* tmpPath=getMapFromMaps(conf,"main","tmpPath");
+  map* uuid=getMapFromMaps(conf,"lenv","usid");
+  char *logPath=(char*)malloc((strlen(tmpPath->value)+strlen(uuid->value)+11)*sizeof(char));
+  sprintf(logPath,"%s/exec_out_%s",tmpPath->value,uuid->value);
+  
+  FILE* logFile=fopen(logPath,"wb");
+  free(logPath);
+  while(true){
+    int rc;
+    do {
+      char buffer[0x4000];
+      rc = libssh2_channel_read( channel, buffer, sizeof(buffer) );
+      
+      if( rc > 0 ){
+	int i;
+	bytecount += rc;
+	buffer[rc]=0;
+	
+	fprintf(logFile,"%s",buffer);
+	fflush(logFile);
+      }
+    }
+    while( rc > 0 );
+    
+    if( rc == LIBSSH2_ERROR_EAGAIN ) {
+      waitsocket(sessions[cnt]->sock_id, sessions[cnt]->session);
+    }
+    else
+      break;
+  }
+  fclose(logFile);
+  exitcode = 127;
+  while( (rc = libssh2_channel_close(channel)) == LIBSSH2_ERROR_EAGAIN )
+    waitsocket(sessions[cnt]->sock_id, sessions[cnt]->session);
+  
+  if( rc == 0 ) {
+    exitcode = libssh2_channel_get_exit_status( channel );
+    libssh2_channel_get_exit_signal(channel, &exitsignal,
+				    NULL, NULL, NULL, NULL, NULL);
+  }
+  
+  if (exitsignal)
+    fprintf(stderr, "\nGot signal: %s\n", exitsignal);
+  else
+    fprintf(stderr, "\nEXIT: %d bytecount: %d\n", exitcode, bytecount);
+  
+  libssh2_channel_free(channel);
+
+  return bytecount;
+}
+
+/** 
+ * Close an opened SSH connection
+ * @param conf maps pointer to the main configuration maps
+ * @param con SSHCON pointer to the SSH connection
+ * @return true in case of success, false if failure occured
+ */
+bool ssh_close_session(maps* conf,SSHCON* con){
+  if(con==NULL)
+    return true;
+  while (libssh2_session_disconnect(con->session, "Normal Shutdown, Thank you for using the ZOO-Project sshapi")
+	 == LIBSSH2_ERROR_EAGAIN);
+#ifdef WIN32
+  closesocket(con->sock_id);
+#else
+  close(con->sock_id);
+#endif
+  libssh2_session_free(con->session);
+  con=NULL;
+  return true;
+}
+
+/** 
+ * Close all the opened SSH connections
+ * @param conf maps pointer to the main configuration maps
+ * @return true in case of success, false if failure occured
+ */
+bool ssh_close(maps* conf){
+  int i,nb_sessions;
+  map* tmp=getMapFromMaps(conf,"lenv","nb_sessions");
+  if(tmp!=NULL){
+    nb_sessions=atoi(tmp->value);
+    for(i=0;i<nb_sessions;i++)
+      ssh_close_session(conf,sessions[i]);
+  }
+  libssh2_exit();
+  return true;
+}
+
+bool addToUploadQueue(maps** conf,maps* input){
+  map* queueMap=getMapFromMaps(*conf,"uploadQueue","length");
+  if(queueMap==NULL){
+    maps* queueMaps=createMaps("uploadQueue");
+    queueMaps->content=createMap("length","0");
+    addMapsToMaps(conf,queueMaps);
+    freeMaps(&queueMaps);
+    free(queueMaps);
+    queueMap=getMapFromMaps(*conf,"uploadQueue","length");
+  }
+  maps* queueMaps=getMaps(*conf,"uploadQueue");
+  int queueIndex=atoi(queueMap->value);
+  if(input!=NULL){
+    if(getMap(input->content,"cache_file")!=NULL){
+      map* length=getMap(input->content,"length");
+      if(length==NULL){
+	addToMap(input->content,"length","1");
+	length=getMap(input->content,"length");
+      }
+      int len=atoi(length->value);
+      int i=0;
+      for(i=0;i<len;i++){
+	
+	map* tmp[2]={getMapArray(input->content,"localPath",i),
+		     getMapArray(input->content,"targetPath",i)};
+
+	setMapArray(queueMaps->content,"input",queueIndex+i,input->name);
+	setMapArray(queueMaps->content,"localPath",queueIndex+i,tmp[0]->value);
+	setMapArray(queueMaps->content,"targetPath",queueIndex+i,tmp[1]->value);
+
+      }
+    }
+  }
+  return true;
+}
+
+int fileMd5Check(maps** conf,const char* localPath,const char* targetPath){
+  if(strstr(localPath,".zca")!=NULL){
+    char *logPath=NULL;    
+    char *command=(char*)malloc(((2*strlen(targetPath))+42)*sizeof(char));
+    sprintf(command,"(md5sum %s | awk {'print $1'}) && touch %s",targetPath,targetPath);
+    if(ssh_exec(*conf,command,ssh_get_cnt(*conf))<=0){
+      return -1;
+    }else{
+      struct stat f_status={};
+      map* usid=getMapFromMaps(*conf,"lenv","usid");
+      map* tmpMap=getMapFromMaps(*conf,"main","tmpPath");
+      char* tmpPath=zStrdup(localPath);
+      tmpPath[strlen(tmpPath)-2]='m';
+      tmpPath[strlen(tmpPath)-1]='d';
+      free(command);
+      logPath=(char*)malloc((strlen(tmpMap->value)+strlen(usid->value)+11)*sizeof(char));
+      sprintf(logPath,"%s/exec_out_%s",tmpMap->value,usid->value);
+      int ts=stat(logPath, &f_status);
+      if(ts==0) {
+	char* fcontent=(char*)malloc(sizeof(char)*(f_status.st_size+1));
+	FILE* f=fopen(logPath,"rb");
+	fread(fcontent,f_status.st_size,1,f);
+	fcontent[f_status.st_size-1]=0;
+	fclose(f);
+	free(logPath);
+	struct stat f_status1={};
+	int ts1=stat(tmpPath, &f_status1);
+	if(ts1==0) {
+	  char* fcontent1=(char*)malloc(sizeof(char)*(f_status.st_size+1));
+	  FILE* f1=fopen(tmpPath,"rb");
+	  fread(fcontent1,f_status1.st_size,1,f1);
+	  fcontent1[f_status1.st_size]=0;
+	  fclose(f1);
+	  free(tmpPath);
+	  if(strcmp(fcontent,fcontent1)==0){
+	    free(fcontent);
+	    free(fcontent1);
+	    return 0;
+	  }else{
+	    free(fcontent);
+	    free(fcontent1);
+	    return -1;
+	  }
+	}else{
+	  free(tmpPath);
+	  free(fcontent);
+	  return -1;
+	}	
+      }
+      free(logPath);
+      free(tmpPath);
+    }
+  }
+  return -1;
+}
+
+bool runUpload(maps** conf){
+  SSHCON *test=ssh_connect(*conf);
+  if(test==NULL){
+    return false;
+  }
+  map* queueLengthMap=getMapFromMaps(*conf,"uploadQueue","length");
+  maps* queueMaps=getMaps(*conf,"uploadQueue");
+  if(queueLengthMap!=NULL){
+    int cnt=atoi(queueLengthMap->value);
+    int i=0;
+    for(i=0;i<cnt;i++){
+      map* argv[3]={
+	getMapArray(queueMaps->content,"input",i),
+	getMapArray(queueMaps->content,"localPath",i),
+	getMapArray(queueMaps->content,"targetPath",i)
+      };
+      if(fileMd5Check(conf,argv[1]->value,argv[2]->value)<0){
+	/**/zooLock* lck;
+	if((lck=lockFile(*conf,argv[1]->value,'w'))!=NULL){/**/
+	  if(ssh_copy(*conf,argv[1]->value,argv[2]->value,ssh_get_cnt(*conf))!=true){
+	    char* templateStr=_("Unable to copy over SSH the file requested for setting the value of %s.");
+	    char *tmpMessage=(char*)malloc((strlen(templateStr)+strlen(argv[0]->value)+1)*sizeof(char));
+	    sprintf(tmpMessage,templateStr,argv[0]->value);
+	    setMapInMaps(*conf,"lenv","message",tmpMessage);
+	    free(tmpMessage);
+	    unlockFile(*conf,lck);
+	    return false;
+	  }
+	  /**/unlockFile(*conf,lck);
+	}else{
+	  setMapInMaps(*conf,"lenv","message",_("Unable to lock the file for upload!"));
+	  return false;
+	}/**/
+      }
+    }    
+  }
+  while (libssh2_session_disconnect(test->session, "Normal Shutdown, Thank you for using the ZOO-Project sshapi")
+         == LIBSSH2_ERROR_EAGAIN);
+#ifdef WIN32
+  closesocket(test->sock_id);
+#else
+  close(test->sock_id);
+#endif
+  libssh2_session_free(test->session);
+  free(test);
+  test=NULL;
+  sessions[ssh_get_cnt(*conf)-1]=NULL;
+  maps* tmp=getMaps(*conf,"lenv");
+  addIntToMap(tmp->content,"nb_sessions",ssh_get_cnt(*conf)-1);  
+
+  return true; 
+}
Index: trunk/zoo-project/zoo-kernel/sshapi.h
===================================================================
--- trunk/zoo-project/zoo-kernel/sshapi.h	(revision 917)
+++ trunk/zoo-project/zoo-kernel/sshapi.h	(revision 917)
@@ -0,0 +1,101 @@
+/*
+ *
+ * Author : Gérald FENOY
+ *
+ *  Copyright 2017 GeoLabs SARL. All rights reserved.
+ *
+ * This work was supported by public funds received in the framework of GEOSUD,
+ * a project (ANR-10-EQPX-20) of the program "Investissements d'Avenir" managed 
+ * by the French National Research Agency
+ *
+ * permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef SSHAPI_H
+#define SSHAPI_H 1
+
+#pragma once 
+
+#include <libssh2.h>
+#include <libssh2_sftp.h>
+ 
+#ifdef HAVE_WINSOCK2_H
+#include <winsock2.h>
+#endif
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+#ifdef HAVE_SYS_SELECT_H
+#include <sys/select.h>
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+
+#include <netdb.h>
+#include <arpa/inet.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <time.h>
+
+#include "service.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define MAX_PARALLEL_SSH_CON 128  
+
+  static int nb_sessions;
+
+  typedef struct {
+    int sock_id;
+    int index;
+    LIBSSH2_SESSION *session;
+    LIBSSH2_SFTP *sftp_session;
+  } SSHCON;
+
+  
+  ZOO_DLL_EXPORT SSHCON *ssh_connect(maps*);
+  ZOO_DLL_EXPORT bool ssh_copy(maps*,const char*,const char*,int);
+  ZOO_DLL_EXPORT int ssh_get_cnt(maps*);
+  ZOO_DLL_EXPORT int ssh_fetch(maps*,const char*,const char*,int);
+  ZOO_DLL_EXPORT int ssh_exec(maps*,const char*,int);
+  ZOO_DLL_EXPORT bool ssh_close_session(maps*,SSHCON*);
+  ZOO_DLL_EXPORT bool ssh_close(maps*);
+  ZOO_DLL_EXPORT bool addToUploadQueue(maps**,maps*);
+  ZOO_DLL_EXPORT bool runUpload(maps**);
+  
+#ifdef __cplusplus
+}
+#endif
+
+#endif
Index: trunk/zoo-project/zoo-kernel/ulinet.c
===================================================================
--- trunk/zoo-project/zoo-kernel/ulinet.c	(revision 889)
+++ trunk/zoo-project/zoo-kernel/ulinet.c	(revision 917)
@@ -4,5 +4,5 @@
  * Author : Gérald FENOY
  *
- * Copyright (c) 2008-2015 GeoLabs SARL
+ * Copyright (c) 2008-2019 GeoLabs SARL
  *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -29,6 +29,8 @@
 #define MAX_WAIT_MSECS 180*1000 /* Wait max. 180 seconds */
 #include "ulinet.h"
+#include "server_internal.h"
 #include <assert.h>
 #include <ctype.h>
+#include "fcgi_stdio.h"
 
 /**
@@ -69,4 +71,32 @@
 
 /**
+ * Write the downloaded content in the file pouted by the _HINTERNET structure
+ *
+ * @param buffer the buffer to read
+ * @param size size of each member
+ * @param nmemb number of element to read
+ * @param data the _HINTERNET structure to write in
+ * @return the size red, -1 if buffer is NULL
+ */
+size_t write_data_into_file(void *buffer, size_t size, size_t nmemb, void *data) 
+{ 
+   size_t realsize = size * nmemb;
+   int writen=0;
+   _HINTERNET *psInternet;
+   if(buffer==NULL){
+     buffer=NULL;
+     return -1;
+   }
+   psInternet=(_HINTERNET *)data;
+   writen+=fwrite(buffer, size, nmemb, psInternet->file);
+   fflush(psInternet->file);
+   psInternet->nDataLen += realsize;
+
+   buffer=NULL;
+   return realsize;
+}
+
+
+/**
  * In case of presence of "Set-Cookie" in the headers red, store the cookie
  * identifier in cookie
@@ -83,6 +113,4 @@
     int i;
     char* tmp;
-    int cnt;
-    _HINTERNET *psInternet;
     for(i=0;i<12;i++)
 #ifndef WIN32
@@ -92,6 +120,6 @@
 #endif
     tmp=strtok((char*) buffer,";"); // knut: added cast to char*
-    cnt=0;
-    psInternet=(_HINTERNET *)data;
+    int cnt=0;
+    _HINTERNET *psInternet=(_HINTERNET *)data;
     if(tmp!=NULL && psInternet!=NULL){
       psInternet->cookie=(char*)malloc(sizeof(char)*(strlen(tmp)+1));
@@ -211,8 +239,59 @@
   HINTERNET ret;
   ret.handle=curl_multi_init();
-  ret.agent=strdup(lpszAgent);
+  ret.agent=zStrdup(lpszAgent);
   ret.nb=0;
+  ret.waitingRequests[ret.nb] = NULL;
   ret.ihandle[ret.nb].header=NULL;
+  ret.ihandle[ret.nb].handle=NULL;
+  ret.ihandle[ret.nb].hasCacheFile=0;
+  ret.ihandle[ret.nb].nDataAlloc = 0;
+  ret.ihandle[ret.nb].url = NULL;
+  ret.ihandle[ret.nb].mimeType = NULL;
+  ret.ihandle[ret.nb].cookie = NULL;
+  ret.ihandle[ret.nb].nDataLen = 0;
+  ret.ihandle[ret.nb].nDataAlloc = 0;
+  ret.ihandle[ret.nb].pabyData = NULL;
+  ret.ihandle[ret.nb].post = NULL;
   return ret;
+}
+
+/**
+ * Verify if the URL should use a shared cache or not.
+ *
+ * In case the security section contains a key named "shared", then if the
+ * domain listed in the shared key are contained in the url given as parameter
+ * then it return "SHARED" in other cases, it returns "OTHER".
+ *
+ * @param conf the main configuration file maps
+ * @param url the URL to evaluate
+ * @return a string "SHARED" in case the host is in a domain listed in the
+ * shared key, "OTHER" in other cases.
+ */
+char* getProvenance(maps* conf,const char* url){
+  map* sharedCache=getMapFromMaps(conf,"security","shared");
+  char *res="OTHER";
+  char *paths[2]={
+    "mapserverAddress",
+    "tmpUrl"
+  };
+  if(sharedCache!=NULL){
+    char *hosts=sharedCache->value;
+    char *curs=strtok(hosts,",");
+    while(curs!=NULL){
+      if(strstr(url,curs)==NULL){
+	return "SHARED";
+      }
+      curs=strtok(NULL,",");
+    }
+  }
+  for(int i=0;i<2;i++){
+    sharedCache=getMapFromMaps(conf,"main",paths[i]);
+    if(sharedCache!=NULL){
+      if(strstr(url,sharedCache->value)!=NULL){
+	return "LOCAL";
+      }
+    }
+  }
+  return res;
 }
 
@@ -244,31 +323,31 @@
  * @return 1 if the host is listed as protected, 0 in other case
  */
-int isProtectedHost(const char* protectedHosts,const char* url){
-  char *token, *saveptr;
-  int cnt;
-  char* host; 
-  
-  // knut: make a copy of url since strtok family modifies first argument and cannot be used on constant strings  
-  char* urlcpy = (char*) malloc(sizeof(char)*(strlen(url)+1)); 
-  urlcpy = strncpy(urlcpy, url, strlen(url)+1); // since count > strlen(url), a null character is properly appended
- 
-  //token = strtok_r (url, "//", &saveptr);
-  token = strtok_r (urlcpy, "//", &saveptr);   // knut
-  cnt=0;
-  while(token!=NULL && cnt<=1){
-    fprintf(stderr,"%s %d %s \n",__FILE__,__LINE__,token);
-    if(cnt==1)
-      fprintf(stderr,"%s %d %s \n",__FILE__,__LINE__,strstr(protectedHosts,token));
-    fflush(stderr);
-    if(cnt==1 && strstr(protectedHosts,token)!=NULL){
-      fprintf(stderr,"%s %d %s \n",__FILE__,__LINE__,strstr(protectedHosts,token));
-      free(urlcpy); 
-      return 1;
-    }
-    token = strtok_r (NULL, "/", &saveptr);
-    cnt+=1;
-  }
-  free(urlcpy);
-  return 0;
+int isProtectedHost(const char* protectedHosts, const char* url) {
+	char *token, *saveptr;
+	int cnt;
+	char* host;
+
+	// knut: make a copy of url since strtok family modifies first argument and cannot be used on constant strings  
+	char* urlcpy = (char*)malloc(sizeof(char)*(strlen(url) + 1));
+	urlcpy = strncpy(urlcpy, url, strlen(url) + 1); // since count > strlen(url), a null character is properly appended
+
+	//token = strtok_r (url, "//", &saveptr);
+	token = strtok_r(urlcpy, "//", &saveptr);   // knut
+	cnt = 0;
+	while (token != NULL && cnt <= 1) {
+		fprintf(stderr, "%s %d %s \n", __FILE__, __LINE__, token);
+		if (cnt == 1)
+			fprintf(stderr, "%s %d %s \n", __FILE__, __LINE__, strstr(protectedHosts, token));
+		fflush(stderr);
+		if (cnt == 1 && strstr(protectedHosts, token) != NULL) {
+			fprintf(stderr, "%s %d %s \n", __FILE__, __LINE__, strstr(protectedHosts, token));
+			free(urlcpy);
+			return 1;
+		}
+		token = strtok_r(NULL, "/", &saveptr);
+		cnt += 1;
+	}
+	free(urlcpy);
+	return 0;
 }
 
@@ -289,29 +368,29 @@
   if(passThrough!=NULL && targetHosts!=NULL){
     char *tmp=zStrdup(passThrough->value);
-    char *token, *saveptr;
-    int i;    
-    token = strtok_r (tmp, ",", &saveptr);
+    int i;
     for(i=0;i<handle->nb;i++){
-      if(targetHosts->value[0]=='*' || isProtectedHost(targetHosts->value,handle->ihandle[i].url)==1){
+      if(strstr(targetHosts->value,"*")!=NULL || isProtectedHost(targetHosts->value,handle->ihandle[i].url)==1){
+	char *token, *saveptr;
+	token = strtok_r (tmp, ",", &saveptr);
 	while (token != NULL){
-	  int j;
-      map* tmpMap;	  
 	  int length=strlen(token)+6;
 	  char* tmp1=(char*)malloc(length*sizeof(char));
+	  map* tmpMap;
 	  snprintf(tmp1,6,"HTTP_");
+	  int j;
 	  for(j=0;token[j]!='\0';j++){
 	    if(token[j]!='-')
-	      tmp1[5+j]=toupper(token[i]);
+	      tmp1[5+j]=toupper(token[j]);
 	    else
 	      tmp1[5+j]='_';
 	    tmp1[5+j+1]='\0';
 	  }
-	  fprintf(stderr,"%s %d %s \n",__FILE__,__LINE__,tmp1);
 	  tmpMap = getMapFromMaps(conf,"renv",tmp1);
-	  if(tmpMap!=NULL)	    
+	  if(tmpMap!=NULL){
 	    AddMissingHeaderEntry(&handle->ihandle[i],token,tmpMap->value);
-	  free(tmp1);
+	  }
 	  if(handle->ihandle[i].header!=NULL)
 	    curl_easy_setopt(handle->ihandle[i].handle,CURLOPT_HTTPHEADER,handle->ihandle[i].header);
+	  free(tmp1);
 	  cnt+=1;
 	  token = strtok_r (NULL, ",", &saveptr);
@@ -330,32 +409,47 @@
 void InternetCloseHandle(HINTERNET* handle0){
   int i=0;
-  for(i=0;i<handle0->nb;i++){
-    _HINTERNET handle=handle0->ihandle[i];
-    if(handle.hasCacheFile>0){
-      fclose(handle.file);
-      unlink(handle.filename);
-    }
-    else{
-      handle.pabyData = NULL;
-      handle.nDataAlloc = handle.nDataLen = 0;
-    }
-    if(handle0->ihandle[i].header!=NULL){
-      curl_slist_free_all(handle0->ihandle[i].header);
-      handle0->ihandle[i].header=NULL;
-    }
-    if(handle.post!=NULL)
-      free(handle.post);
-    if(handle.url!=NULL)
-      free(handle.url);
-    if(handle.mimeType!=NULL)
-      free(handle.mimeType);
-    if(handle.cookie!=NULL)
-      free(handle.cookie);
-  }
-  if(handle0->handle)
-    curl_multi_cleanup(handle0->handle);
-  free(handle0->agent);
-  for(i=handle0->nb-1;i>=0;i--){
-    free(handle0->waitingRequests[i]);
+  if(handle0!=NULL){
+    for(i=0;i<handle0->nb;i++){
+      _HINTERNET handle=handle0->ihandle[i];
+      if(handle.hasCacheFile>0){
+	fclose(handle.file);
+	unlink(handle.filename);
+	free(handle.filename);
+      }
+      else{
+	handle.pabyData = NULL;
+	handle.nDataAlloc = handle.nDataLen = 0;
+      }
+      if(handle.header!=NULL){
+	curl_slist_free_all(handle.header);
+	handle.header=NULL;
+      }
+      if(handle.post!=NULL){
+	free(handle.post);
+	handle.post=NULL;
+      }
+      if(handle.url!=NULL){
+	free(handle.url);
+	handle.url=NULL;
+      }
+      if(handle.mimeType!=NULL){
+	free(handle.mimeType);
+	handle.mimeType=NULL;
+      }
+      if(handle.cookie!=NULL){
+	free(handle.cookie);
+	handle.cookie=NULL;
+      }
+      if(handle0->waitingRequests[i]!=NULL){
+	free(handle0->waitingRequests[i]);
+	handle0->waitingRequests[i]=NULL;
+      }
+    }
+    if(handle0->handle)
+      curl_multi_cleanup(handle0->handle);
+    if(handle0->agent!=NULL){
+      free(handle0->agent);
+      handle0->agent=NULL;
+    }
   }
 }
@@ -370,9 +464,13 @@
  * @param dwFlags desired download mode (INTERNET_FLAG_NO_CACHE_WRITE for not using cache file)
  * @param dwContext not used
- */
-HINTERNET InternetOpenUrl(HINTERNET* hInternet,LPCTSTR lpszUrl,LPCTSTR lpszHeaders,size_t dwHeadersLength,size_t dwFlags,size_t dwContext){
+ * @param conf the main configuration file maps pointer
+ * @return the updated HINTERNET 
+ */
+HINTERNET InternetOpenUrl(HINTERNET* hInternet,LPCTSTR lpszUrl,LPCTSTR lpszHeaders,size_t dwHeadersLength,size_t dwFlags,size_t dwContext,const maps* conf){
 
   char filename[255];
+  int ldwFlags=INTERNET_FLAG_NEED_FILE;
   struct MemoryStruct header;
+  map* memUse=getMapFromMaps((maps*) conf,"main","memory"); // knut: addad cast to maps*
 
   hInternet->ihandle[hInternet->nb].handle=curl_easy_init( );
@@ -407,25 +505,31 @@
 #endif
 
-      
-  switch(dwFlags)
+  if(memUse!=NULL && strcasecmp(memUse->value,"load")==0)
+    ldwFlags=INTERNET_FLAG_NO_CACHE_WRITE;
+  
+  switch(ldwFlags)
     {
     case INTERNET_FLAG_NO_CACHE_WRITE:
-      hInternet->ihandle[hInternet->nb].hasCacheFile=-1;
       curl_easy_setopt(hInternet->ihandle[hInternet->nb].handle, CURLOPT_WRITEFUNCTION, write_data_into);
       curl_easy_setopt(hInternet->ihandle[hInternet->nb].handle, CURLOPT_WRITEDATA, (void*)&hInternet->ihandle[hInternet->nb]);
+      hInternet->ihandle[hInternet->nb].hasCacheFile=-1;
       break;
     default:
-      sprintf(hInternet->ihandle[hInternet->nb].filename,"/tmp/ZOO_Cache%d",(int)time(NULL));
-      hInternet->ihandle[hInternet->nb].filename[24]=0;
-#ifdef MSG_LAF_VERBOSE
-      fprintf(stderr,"file=%s",hInternet->ihandle[hInternet->nb].filename);
-#endif
-      hInternet->ihandle[hInternet->nb].filename=filename;
+      memset(filename,0,255);
+      char* tmpUuid=get_uuid();
+      map* tmpPath=NULL;
+      if(conf!=NULL){
+	tmpPath=getMapFromMaps((maps*) conf,"main","tmpPath"); // knut added cast to maps*
+      }
+      if(tmpPath==NULL)
+	sprintf(filename,"/tmp/ZOO_Cache%s", tmpUuid);
+      else
+	sprintf(filename,"%s/ZOO_Cache%s", tmpPath->value,tmpUuid);
+      free(tmpUuid);
+      hInternet->ihandle[hInternet->nb].filename=zStrdup(filename);
       hInternet->ihandle[hInternet->nb].file=fopen(hInternet->ihandle[hInternet->nb].filename,"w+");
-    
       hInternet->ihandle[hInternet->nb].hasCacheFile=1;
-      curl_easy_setopt(hInternet->ihandle[hInternet->nb].handle, CURLOPT_WRITEFUNCTION, NULL);
-      curl_easy_setopt(hInternet->ihandle[hInternet->nb].handle, CURLOPT_WRITEDATA, hInternet->ihandle[hInternet->nb].file);
-      hInternet->ihandle[hInternet->nb].nDataLen=0;
+      curl_easy_setopt(hInternet->ihandle[hInternet->nb].handle, CURLOPT_WRITEFUNCTION, write_data_into_file);
+      curl_easy_setopt(hInternet->ihandle[hInternet->nb].handle, CURLOPT_WRITEDATA, (void*)&hInternet->ihandle[hInternet->nb]);
       break;
     }
@@ -443,5 +547,5 @@
     curl_easy_setopt(hInternet->ihandle[hInternet->nb].handle,CURLOPT_VERBOSE,1);
 #endif
-    hInternet->ihandle[hInternet->nb].post=strdup(lpszHeaders);
+    hInternet->ihandle[hInternet->nb].post=zStrdup(lpszHeaders);
     curl_easy_setopt(hInternet->ihandle[hInternet->nb].handle,CURLOPT_POSTFIELDS,hInternet->ihandle[hInternet->nb].post);
     curl_easy_setopt(hInternet->ihandle[hInternet->nb].handle,CURLOPT_POSTFIELDSIZE,(long)dwHeadersLength);
@@ -457,4 +561,5 @@
   hInternet->ihandle[hInternet->nb].header=NULL;
   ++hInternet->nb;
+  hInternet->ihandle[hInternet->nb].header=NULL;
 
 #ifdef ULINET_DEBUG
@@ -472,9 +577,47 @@
  */
 int processDownloads(HINTERNET* hInternet){
-  int still_running=0;
+  int still_running=0,numfds;
   int msgs_left=0;
   int i=0;
   do{
-    curl_multi_perform(hInternet->handle, &still_running);
+    CURLMcode mc;
+    mc = curl_multi_perform(hInternet->handle, &still_running);
+    if(mc==CURLM_OK){
+#if LIBCURL_VERSION_MINOR >= 28
+      mc = curl_multi_wait(hInternet->handle, NULL, 0, 1000, &numfds);
+#else
+      struct timeval timeout;
+      fd_set fdread;
+      fd_set fdwrite;
+      fd_set fdexcep;
+      int maxfd = -1;
+
+      long curl_timeo = -1;
+
+      FD_ZERO(&fdread);
+      FD_ZERO(&fdwrite);
+      FD_ZERO(&fdexcep);
+
+      /* set a suitable timeout to play around with */
+      timeout.tv_sec = 1;
+      timeout.tv_usec = 0;
+
+      curl_multi_timeout(hInternet->handle, &curl_timeo);
+      if(curl_timeo >= 0) {
+	timeout.tv_sec = curl_timeo / 1000;
+	if(timeout.tv_sec > 1)
+	  timeout.tv_sec = 1;
+	else
+	  timeout.tv_usec = (curl_timeo % 1000) * 1000;
+      }
+
+      /* get file descriptors from the transfers */
+      mc = curl_multi_fdset(hInternet->handle, &fdread, &fdwrite, &fdexcep, &maxfd);
+#endif
+    }
+    if(mc != CURLM_OK) {
+      fprintf(stderr, "curl_multi failed, code %d.n", mc);
+      break;
+    }
   }while(still_running);  
   for(i=0;i<hInternet->nb;i++){
@@ -482,5 +625,5 @@
     curl_easy_getinfo(hInternet->ihandle[i].handle,CURLINFO_CONTENT_TYPE,&tmp);
     if(tmp!=NULL)
-      hInternet->ihandle[i].mimeType=strdup(tmp);
+      hInternet->ihandle[i].mimeType=zStrdup(tmp);
     curl_easy_getinfo(hInternet->ihandle[i].handle,CURLINFO_RESPONSE_CODE,&hInternet->ihandle[i].code);
     curl_multi_remove_handle(hInternet->handle, hInternet->ihandle[i].handle);
@@ -498,7 +641,5 @@
  */
 int freeCookieList(HINTERNET hInternet){
-  if(hInternet.ihandle[hInternet.nb].cookie)
-    free(hInternet.ihandle[hInternet.nb].cookie);
-  hInternet.ihandle[hInternet.nb].cookie=NULL;
+  hInternet.ihandle[hInternet.nb].cookie=zStrdup("");
 #ifndef TIGER
   curl_easy_setopt(hInternet.ihandle[hInternet.nb].handle, CURLOPT_COOKIELIST, "ALL");
@@ -522,5 +663,7 @@
     fseek (hInternet.file , 0 , SEEK_END);
     dwDataSize=ftell(hInternet.file); //taille du ficher
-    rewind (hInternet.file);
+    //dwDataSize=hInternet.nDataLen;
+    //rewind (hInternet.file);
+    fseek(hInternet.file, 0, SEEK_SET);
   }
   else{
@@ -532,13 +675,15 @@
   }
 
-  if( dwNumberOfBytesToRead /* buffer size */ < dwDataSize )
+  if( dwNumberOfBytesToRead /* buffer size */ < dwDataSize ){
     return 0;
+  }
 
 #ifdef MSG_LAF_VERBOSE
-  printf("\nfile size : %dko\n",dwDataSize/1024);
+  fprintf(stderr,"\nfile size : %dko\n",dwDataSize/1024);
 #endif
 
   if(hInternet.hasCacheFile>0){
-    *lpdwNumberOfBytesRead = fread(lpBuffer,1,dwDataSize,hInternet.file); 
+    int freadRes = fread(lpBuffer,dwDataSize+1,1,hInternet.file); 
+    *lpdwNumberOfBytesRead = hInternet.nDataLen;
   }
   else{
Index: trunk/zoo-project/zoo-kernel/ulinet.h
===================================================================
--- trunk/zoo-project/zoo-kernel/ulinet.h	(revision 889)
+++ trunk/zoo-project/zoo-kernel/ulinet.h	(revision 917)
@@ -2,5 +2,5 @@
  * Author : Gérald FENOY
  *
- *  Copyright 2008-2009 GeoLabs SARL. All rights reserved.
+ *  Copyright 2008-2019 GeoLabs SARL. All rights reserved.
  *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -26,8 +26,8 @@
 #define _ULINET_H
 
-#include "fcgi_stdio.h"
 #include <stdlib.h>
 #include <fcntl.h>
 #include <curl/curl.h>
+#include <curl/curlver.h>
 #include "service.h"
 #ifndef WIN32
@@ -44,13 +44,14 @@
 #include "jsapi.h"
 #endif
-/* knut: see new definition of bool in service.h
-#ifndef bool
-#define bool int
+#ifndef __cplusplus
+// knut: see new def of bool in service.h
+//#ifndef bool
+//#define bool int
+//#endif
+//#ifndef true
+//#define true 1
+//#define false 0
+//#endif
 #endif
-#ifndef true
-#define true 1
-#define false 0
-#endif
-*/
 
 #define MAX_REQ 50
@@ -102,4 +103,6 @@
   size_t write_data_into(void*,size_t,size_t,void*);
 
+  size_t write_data_into_file(void*,size_t,size_t,void*);
+
   size_t header_write_data(void*,size_t,size_t,void*);
 
@@ -130,4 +133,5 @@
   HINTERNET InternetOpen(char*,int,char*,char*,int);
 
+  char* getProvenance(maps*,const char*);
   int isProtectedHost(const char*,const char*);
   int AddMissingHeaderEntry(_HINTERNET*,const char*,const char*);
@@ -153,13 +157,12 @@
   typedef size_t* LPDWORD;
 #endif
-/* knut: see new definition of bool in service.h
-#ifndef bool
-#define bool int
-#endif
-*/
+// knut: see new definition of bool in service.h
+//#ifndef bool
+//#define bool int
+//#endif
 
 #  define CHECK_INET_HANDLE(h) (h.handle != 0)
 
-  HINTERNET InternetOpenUrl(HINTERNET*,LPCTSTR,LPCTSTR,size_t,size_t,size_t);
+  HINTERNET InternetOpenUrl(HINTERNET*,LPCTSTR,LPCTSTR,size_t,size_t,size_t,const maps*);
 
   int processDownloads(HINTERNET*);
Index: trunk/zoo-project/zoo-kernel/xslt/updateExecute.xsl
===================================================================
--- trunk/zoo-project/zoo-kernel/xslt/updateExecute.xsl	(revision 917)
+++ trunk/zoo-project/zoo-kernel/xslt/updateExecute.xsl	(revision 917)
@@ -0,0 +1,63 @@
+<xsl:stylesheet version="1.0"
+                xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+                xmlns:ows="http://www.opengis.net/ows/1.1"
+                xmlns:ns14="http://www.opengis.net/wps/2.0"
+                xmlns:wps="http://www.opengis.net/wps/2.0"
+                xmlns:xlink="http://www.w3.org/1999/xlink">
+
+  <!--
+      This template is used by the ZOO-Kernel to generate a specific
+      OGC WPS Execute request in case of rest service callback use.
+      In such a case the ZOO-Kernel replace every input provided by
+      value in the initial request and replace the data section by the
+      reference to the published ressource.
+      So, this template is basically made to replace any input provided
+      by value to the corresponding local WCS/WFS OGC web service
+      references.
+      --> 
+  <xsl:output method="xml"/>
+  <xsl:param name="value" select="string('-1')"/>
+  <xsl:param name="attr" select="string('-1')"/>
+  <xsl:param name="cnt" select="string('-1')"/>
+  <xsl:param name="index" select="0"/>
+
+  <xsl:template match="@*|node()">
+    <xsl:copy>
+      <xsl:apply-templates select="@*|node()"/>
+    </xsl:copy>
+  </xsl:template>
+
+  
+  <xsl:template match="/wps:Execute/wps:Input">
+    <xsl:choose>
+      <xsl:when test="@id=$attr">
+        <xsl:copy>
+          <xsl:attribute name="id">
+            <xsl:value-of select="@id"/>
+          </xsl:attribute>
+          <ns14:Reference>
+            <xsl:attribute name="xlink:href">
+              <xsl:value-of select="$value"/>
+            </xsl:attribute>
+            <xsl:if test="./wps:Data[@mimeType!='']">
+              <xsl:attribute name="mimeType">
+                <xsl:value-of select="./wps:Data[@mimeType]"/>
+              </xsl:attribute>
+              <xsl:attribute name="encoding">
+                <xsl:value-of select="./wps:Data[@encoding]"/>
+              </xsl:attribute>
+              <xsl:attribute name="schema">
+                <xsl:value-of select="./wps:Data[@schema]"/>
+              </xsl:attribute>
+            </xsl:if>
+          </ns14:Reference>
+        </xsl:copy>
+      </xsl:when>
+      <xsl:otherwise>
+        <xsl:copy-of select="."/>
+      </xsl:otherwise>
+    </xsl:choose>
+  </xsl:template>
+
+  
+</xsl:stylesheet>
Index: trunk/zoo-project/zoo-kernel/zoo_loader.c
===================================================================
--- trunk/zoo-project/zoo-kernel/zoo_loader.c	(revision 889)
+++ trunk/zoo-project/zoo-kernel/zoo_loader.c	(revision 917)
@@ -65,4 +65,10 @@
 #endif
 
+int cgiInit(){
+  fprintf(FCGI_stderr,"ZOO-Kernel initialization %s %d ... \n",__FILE__,__LINE__);
+  fflush(FCGI_stderr);
+  return 0;
+}
+
 /**
  * Main entry point for cgic.
@@ -117,5 +123,5 @@
        if(res!=NULL)
 	 free(res);
-    }else{
+    }else{		
       char *buffer=new char[cgiContentLength+1];
       if(fread(buffer,sizeof(char),cgiContentLength,cgiIn)>0){
@@ -157,5 +163,5 @@
     }	
   }
-  else{
+  else{	  
 #ifdef DEBUG
     dumpMap(tmpMap);
@@ -181,9 +187,9 @@
     cgiStringArrayFree(array);
   }
-
+ 
 #ifdef WIN32
-  map *tmpReq=getMap(tmpMap,"rfile");
-  if(tmpReq!=NULL){
-    FILE *lf=fopen(tmpReq->value,"r");
+  map *tmpReq=getMap(tmpMap,"rfile");  
+  if(tmpReq!=NULL){	  	  
+    FILE *lf=fopen(tmpReq->value,"r");	
     fseek(lf,0,SEEK_END);
     long flen=ftell(lf);
@@ -389,5 +395,5 @@
     }
   }
-
+  
   if(strncasecmp(cgiContentType,"multipart/form-data",19)==0){
     map* tmp=getMap(tmpMap,"dataInputs");
@@ -402,5 +408,5 @@
   if(strQuery!=NULL)
     free(strQuery);
-
+  
   runRequest(&tmpMap);
 
Index: trunk/zoo-project/zoo-kernel/zoo_service_loader.c
===================================================================
--- trunk/zoo-project/zoo-kernel/zoo_service_loader.c	(revision 889)
+++ trunk/zoo-project/zoo-kernel/zoo_service_loader.c	(revision 917)
@@ -26,6 +26,21 @@
 extern "C" int crlex ();
 
+#ifdef META_DB
+#include "ogrsf_frmts.h"
+#if GDAL_VERSION_MAJOR >= 2
+#include <gdal_priv.h>
+#endif
+#endif
+
 #ifdef USE_OTB
 #include "service_internal_otb.h"
+#endif
+
+#ifdef USE_R
+#include "service_internal_r.h"
+#endif
+
+#ifdef USE_HPC
+#include "service_internal_hpc.h"
 #endif
 
@@ -55,4 +70,8 @@
 #endif
 
+#ifdef META_DB
+#include "meta_sql.h"
+#endif
+
 #ifdef USE_PYTHON
 #include "service_internal_python.h"
@@ -87,6 +106,14 @@
 #endif
 
+#ifdef USE_CALLBACK
+#include "service_json.h"
+#include "service_callback.h"
+#endif
+
 #include <dirent.h>
 #include <signal.h>
+#ifndef WIN32
+#include <execinfo.h>
+#endif
 #include <unistd.h>
 #ifndef WIN32
@@ -105,6 +132,40 @@
 #include <stdarg.h>
 
+#include <libxml/tree.h>
+#include <libxml/parser.h>
+#include <libxml/xpath.h>
+#include <libxml/xpathInternals.h>
+
+#include <libxslt/xslt.h>
+#include <libxslt/xsltInternals.h>
+#include <libxslt/transform.h>
+#include <libxslt/xsltutils.h>
+
 #ifndef WIN32
 extern char **environ;
+#endif
+
+
+#ifdef WIN32
+extern "C"
+{
+  __declspec (dllexport) char *strcasestr (char const *a, char const *b)
+#ifndef USE_MS
+  {
+    char *x = zStrdup (a);
+    char *y = zStrdup (b);
+
+      x = _strlwr (x);
+      y = _strlwr (y);
+    char *pos = strstr (x, y);
+    char *ret = pos == NULL ? NULL : (char *) (a + (pos - x));
+      free (x);
+      free (y);
+      return ret;
+  };
+#else
+   ;
+#endif
+}
 #endif
 
@@ -119,7 +180,7 @@
 
 #ifdef WIN32
-  #ifndef PROGRAMNAME
-    #define PROGRAMNAME "zoo_loader.cgi"
-  #endif
+#ifndef PROGRAMNAME
+#define PROGRAMNAME "zoo_loader.cgi"
+#endif
 #endif
 
@@ -159,22 +220,22 @@
   lockShm (lid);
 #endif
-  FILE *f3 = fopen (fbkp, "wb+");  
-  free (fbkp);  
+  FILE *f3 = fopen (fbkp, "wb+");
+  free (fbkp);
   fseek (f2, 0, SEEK_END);
   long flen = ftell (f2);
   fseek (f2, 0, SEEK_SET);
   char *tmps1 = (char *) malloc ((flen + 1) * sizeof (char));
-  fread (tmps1, flen, 1, f2);  
+  fread (tmps1, flen, 1, f2);
 #ifdef WIN32
   /* knut: I think this block can be dropped; pchr may be NULL if result is not in XML format
-  char *pchr=strrchr(tmps1,'>');   
-  flen=strlen(tmps1)-strlen(pchr)+1;  
-  tmps1[flen]=0;  
+  char *pchr=strrchr(tmps1,'>');
+  flen=strlen(tmps1)-strlen(pchr)+1;
+  tmps1[flen]=0;
   */
-#endif  
+#endif
   fwrite (tmps1, 1, flen, f3);
+  fclose (f2);
+  fclose (f3);
   free(tmps1);
-  fclose (f2);
-  fclose (f3);  
   return 1;
 }
@@ -197,7 +258,7 @@
  */
 int
-recursReaddirF ( maps * m, registry *r, xmlNodePtr n, char *conf_dir, 
+recursReaddirF ( maps * m, registry *r, xmlDocPtr doc, xmlNodePtr n, char *conf_dir, 
 		 char *prefix, int saved_stdout, int level, 
-		 void (func) (registry *, maps *, xmlNodePtr, service *) )
+		 void (func) (registry *, maps *, xmlDocPtr, xmlNodePtr, service *) )
 {
   struct dirent *dp;
@@ -246,5 +307,5 @@
             setMapInMaps (m, "lenv", "level", levels1);
             res =
-              recursReaddirF (m, r, n, tmp, prefix, saved_stdout, level + 1,
+              recursReaddirF (m, r, doc, n, tmp, prefix, saved_stdout, level + 1,
                               func);
             sprintf (levels1, "%d", level);
@@ -264,5 +325,5 @@
       {
         char* extn = strstr(dp->d_name, ".zcfg");
-        if(dp->d_name[0] != '.' && extn != NULL && strlen(extn) == 5)
+        if(dp->d_name[0] != '.' && extn != NULL && strlen(extn) == 5 && strlen(dp->d_name)>6)
           {
             int t;
@@ -271,13 +332,14 @@
             snprintf (tmps1, 1024, "%s/%s", conf_dir, dp->d_name);
 
-            char *tmpsn = zStrdup (dp->d_name);
-            tmpsn[strlen (tmpsn) - 5] = 0;
+	    char *tmpsn = (char*)malloc((strlen(dp->d_name)-4)*sizeof(char));//zStrdup (dp->d_name);
+	    memset (tmpsn, 0, strlen(dp->d_name)-4);
+	    snprintf(tmpsn,strlen(dp->d_name)-4,"%s",dp->d_name);
             
             map* import = getMapFromMaps (m, IMPORTSERVICE, tmpsn);
             if (import == NULL || import->value == NULL || zoo_path_compare(tmps1, import->value) != 0 ) { // service is not in [include] block 
-              service *s1 = (service *) malloc (SERVICE_SIZE);
+              service *s1 = createService();
               if (s1 == NULL)
                 {
-                  dup2 (saved_stdout, fileno (stdout));
+                  zDup2 (saved_stdout, fileno (stdout));
                   errorException (m, _("Unable to allocate memory"),
                                   "InternalError", NULL);
@@ -300,5 +362,5 @@
                     sprintf (tmp01, _("Unable to parse the ZCFG file: %s."),
                              dp->d_name);
-                  dup2 (saved_stdout, fileno (stdout));
+                  zDup2 (saved_stdout, fileno (stdout));
                   errorException (m, tmp01, "InternalError", NULL);
                   return -1;
@@ -309,6 +371,7 @@
               fflush (stderr);
   #endif
-        inheritance(r,&s1);
-              func (r, m, n, s1);
+	      if(s1!=NULL)
+		inheritance(r,&s1);
+              func (r, m, doc, n, s1);
               freeService (&s1);
               free (s1);
@@ -344,4 +407,5 @@
 sig_handler (int sig)
 {
+  
   char tmp[100];
   const char *ssig;
@@ -372,5 +436,5 @@
   sprintf (tmp,
            _
-           ("ZOO Kernel failed to process your request, receiving signal %d = %s"),
+           ("ZOO Kernel failed to process your request, receiving signal %d = %s "),
            sig, ssig);
   errorException (NULL, tmp, "InternalError", NULL);
@@ -420,6 +484,5 @@
 #endif
 
-  map* libp = getMapFromMaps(m, "main", "libPath");
-
+  map* libp = getMapFromMaps(m, "main", "libPath");  
   if (strlen (r_inputs->value) == 1
       && strncasecmp (r_inputs->value, "C", 1) == 0)
@@ -610,6 +673,17 @@
   else
 
+#ifdef USE_HPC
+  if (strncasecmp (r_inputs->value, "HPC", 3) == 0)
+    {
+      *eres =
+        zoo_hpc_support (&m, request_inputs, s1,
+                            &request_input_real_format,
+                            &request_output_real_format);
+    }
+  else
+#endif
+
 #ifdef USE_SAGA
-  if (strncasecmp (r_inputs->value, "SAGA", 6) == 0)
+  if (strncasecmp (r_inputs->value, "SAGA", 4) == 0)
     {
       *eres =
@@ -622,5 +696,5 @@
 
 #ifdef USE_OTB
-  if (strncasecmp (r_inputs->value, "OTB", 6) == 0)
+  if (strncasecmp (r_inputs->value, "OTB", 3) == 0)
     {
       *eres =
@@ -633,7 +707,18 @@
 #ifdef USE_PYTHON
   if (strncasecmp (r_inputs->value, "PYTHON", 6) == 0)
+    {		  
+      *eres =
+        zoo_python_support (&m, request_inputs, s1,
+                            &request_input_real_format,
+                            &request_output_real_format);	  
+    }
+  else
+#endif
+
+#ifdef USE_R
+  if (strncasecmp (r_inputs->value, "R", 6) == 0)
     {	  
       *eres =
-        zoo_python_support (&m, request_inputs, s1,
+        zoo_r_support (&m, request_inputs, s1,
                             &request_input_real_format,
                             &request_output_real_format);
@@ -713,5 +798,5 @@
     }
   *myMap = m;
-  *ioutputs = request_output_real_format;
+  *ioutputs = request_output_real_format;  
 }
 
@@ -902,6 +987,9 @@
 #endif
 
+  
   map *r_inputs = NULL;
   map *request_inputs = *inputs;
+  //fprintf(stderr,"%s \n",json_object_to_json_string_ext(mapToJson(request_inputs),JSON_C_TO_STRING_PLAIN));
+  
 #ifdef IGNORE_METAPATH
   addToMap(request_inputs, "metapath", "");
@@ -935,7 +1023,7 @@
 #ifdef ETC_DIR
 #ifndef WIN32
-    getcwd (ntmp, 1024);
+  getcwd (ntmp, 1024);
 #else
-    _getcwd (ntmp, 1024);
+  _getcwd (ntmp, 1024);
 #endif
 #endif
@@ -1013,5 +1101,5 @@
       char tmp1[13];
       sprintf (tmp1, "LC_ALL=%s", tmp);
-      putenv (tmp1);
+      _putenv (tmp1);
 #endif
       free (tmp);
@@ -1025,5 +1113,5 @@
       char tmp1[13];
       sprintf (tmp1, "LC_ALL=en_US");
-      putenv (tmp1);
+      _putenv (tmp1);
 #endif
       setMapInMaps (m, "main", "language", "en-US");
@@ -1035,5 +1123,5 @@
   char tmp1[17];
   sprintf (tmp1, "LC_NUMERIC=C");
-  putenv (tmp1);
+  _putenv (tmp1);
 #endif
   bind_textdomain_codeset ("zoo-kernel", "UTF-8");
@@ -1127,5 +1215,6 @@
   };
   r_inputs = getMap (request_inputs, "Request");
-  REQUEST = zStrdup (r_inputs->value);
+  if(r_inputs!=NULL)
+    REQUEST = zStrdup (r_inputs->value);
   int reqId=-1;
   if (strncasecmp (REQUEST, "GetCapabilities", 15) != 0){
@@ -1134,5 +1223,5 @@
     for(j=0;j<nbSupportedRequests;j++){
       if(requests[vid][j]!=NULL && requests[vid][j+1]!=NULL){
-	if(j<nbReqIdentifier && strncasecmp(REQUEST,requests[vid][j+1],strlen(REQUEST))==0){
+	if(j<nbReqIdentifier && strncasecmp(REQUEST,requests[vid][j+1],strlen(requests[vid][j+1]))==0){
 	  checkValidValue(request_inputs,&err,"identifier",NULL,1);
 	  reqId=j+1;
@@ -1141,5 +1230,5 @@
 	else
 	  if(j>=nbReqIdentifier && j<nbReqIdentifier+nbReqJob && 
-	     strncasecmp(REQUEST,requests[vid][j+1],strlen(REQUEST))==0){
+	     strncasecmp(REQUEST,requests[vid][j+1],strlen(requests[vid][j+1]))==0){
 	    checkValidValue(request_inputs,&err,"jobid",NULL,1);
 	    reqId=j+1;
@@ -1217,16 +1306,22 @@
   registry* zooRegistry=NULL;
   if(reg!=NULL){
-    int saved_stdout = dup (fileno (stdout));
-    dup2 (fileno (stderr), fileno (stdout));
+#ifndef WIN32
+    int saved_stdout = zDup (fileno (stdout));
+    zDup2 (fileno (stderr), fileno (stdout));
+#endif
     if(createRegistry (m,&zooRegistry,reg->value)<0){
       map *message=getMapFromMaps(m,"lenv","message");
       map *type=getMapFromMaps(m,"lenv","type");
-      dup2 (saved_stdout, fileno (stdout));
+#ifndef WIN32
+      zDup2 (saved_stdout, fileno (stdout));
+#endif
       errorException (m, message->value,
 		      type->value, NULL);
       return 0;
     }
-    dup2 (saved_stdout, fileno (stdout));
-    close(saved_stdout);
+#ifndef WIN32
+    zDup2 (saved_stdout, fileno (stdout));
+    zClose(saved_stdout);
+#endif
   }
 
@@ -1242,6 +1337,6 @@
        * has been found in the zcfg and then printed on stdout
        */
-      int saved_stdout = dup (fileno (stdout));
-      dup2 (fileno (stderr), fileno (stdout));
+      int saved_stdout = zDup (fileno (stdout));
+      zDup2 (fileno (stderr), fileno (stdout));
 
       maps* imports = getMaps(m, IMPORTSERVICE);
@@ -1258,5 +1353,5 @@
 	    }
 	    inheritance(zooRegistry, &svc);
-	    printGetCapabilitiesForProcess(zooRegistry, m, n, svc);
+	    printGetCapabilitiesForProcess(zooRegistry, m, doc, n, svc);
 	    freeService(&svc);
 	    free(svc);                             
@@ -1267,5 +1362,5 @@
 
       if (int res =		  
-          recursReaddirF (m, zooRegistry, n, conf_dir, NULL, saved_stdout, 0,
+          recursReaddirF (m, zooRegistry, doc, n, conf_dir, NULL, saved_stdout, 0,
                           printGetCapabilitiesForProcess) < 0)
         {
@@ -1282,6 +1377,10 @@
         }
       fflush (stdout);
-      dup2 (saved_stdout, fileno (stdout));
-      printDocument (m, doc, getpid ());
+      zDup2 (saved_stdout, fileno (stdout));
+#ifdef META_DB
+      fetchServicesFromDb(zooRegistry,m,doc,n,printGetCapabilitiesForProcess,1);
+      close_sql(m,0);
+#endif      
+      printDocument (m, doc, zGetpid ());
       freeMaps (&m);
       free (m);
@@ -1299,9 +1398,16 @@
       r_inputs = getMap (request_inputs, "JobId");
       if(reqId>nbReqIdentifier){
-	if (strncasecmp (REQUEST, "GetStatus", strlen(REQUEST)) == 0 ||
-	    strncasecmp (REQUEST, "GetResult", strlen(REQUEST)) == 0){
+	if (strncasecmp (REQUEST, "GetStatus", 9) == 0 ||
+	    strncasecmp (REQUEST, "GetResult", 9) == 0){
 	  runGetStatus(m,r_inputs->value,REQUEST);
+#ifdef RELY_ON_DB
+	  map* dsNb=getMapFromMaps(m,"lenv","ds_nb");
+	  if(dsNb!=NULL && atoi(dsNb->value)>1)
+	    close_sql(m,1);
+	  close_sql(m,0);
+#endif
+	  
 	  freeMaps (&m);
-	  free (m);
+	  free(m);
 	  if(zooRegistry!=NULL){
 	    freeRegistry(&zooRegistry);
@@ -1355,4 +1461,8 @@
 	    r_inputs = NULL;
 	    r_inputs = getMap (request_inputs, "version");
+#ifdef DEBUG
+	    fprintf(stderr," ** DEBUG %s %d \n",__FILE__,__LINE__);
+	    fflush(stderr);
+#endif
 	    xmlNodePtr n = printWPSHeader(doc,m,"DescribeProcess",
 					  root_nodes[vid][1],(version!=NULL?version->value:"1.0.0"),1);
@@ -1362,6 +1472,6 @@
 	    char *orig = zStrdup (r_inputs->value);
 
-	    int saved_stdout = dup (fileno (stdout));
-	    dup2 (fileno (stderr), fileno (stdout));
+	    int saved_stdout = zDup (fileno (stdout));
+	    zDup2 (fileno (stderr), fileno (stdout));
 	    if (strcasecmp ("all", orig) == 0)
 	      {
@@ -1379,5 +1489,9 @@
 		      }
 		      inheritance(zooRegistry, &svc);
-		      printDescribeProcessForProcess(zooRegistry, m, n, svc);
+#ifdef USE_HPC
+		      addNestedOutputs(&svc);
+#endif
+
+		      printDescribeProcessForProcess(zooRegistry, m, doc, n, svc);
 		      freeService(&svc);
 		      free(svc);                             
@@ -1388,7 +1502,12 @@
   
 		if (int res =
-		    recursReaddirF (m, zooRegistry, n, conf_dir, NULL, saved_stdout, 0,
+		    recursReaddirF (m, zooRegistry, doc, n, conf_dir, NULL, saved_stdout, 0,
 				    printDescribeProcessForProcess) < 0)
 		  return res;
+#ifdef META_DB
+		fetchServicesFromDb(zooRegistry,m,doc,n,printDescribeProcessForProcess,0);
+		close_sql(m,0);
+#endif      
+
 	      }
 	    else
@@ -1406,47 +1525,56 @@
 		    if (import != NULL && import->value != NULL) 
 		      {
-			s1 = (service *) malloc (SERVICE_SIZE);
-			t = readServiceFile (m, import->value, &s1, import->name);
+#ifdef META_DB			
+			service* s2=extractServiceFromDb(m,import->name,0);
+			if(s2==NULL){
+#endif
+			  s1 = createService();
+			  t = readServiceFile (m, import->value, &s1, import->name);
                 
-			if (t < 0) // failure reading zcfg
-			  {
-			    map *tmp00 = getMapFromMaps (m, "lenv", "message");
-			    char tmp01[1024];
-			    if (tmp00 != NULL)
-			      sprintf (tmp01, _("Unable to parse the ZCFG file: %s (%s)"), import->value, tmp00->value);
-			    else
-			      sprintf (tmp01, _("Unable to parse the ZCFG file: %s."), import->value);
-
-			    dup2 (saved_stdout, fileno (stdout));
-			    errorException (m, tmp01, "InternalError", NULL);
-            
-			    freeMaps (&m);
-			    free (m);
-
-			    if(zooRegistry!=NULL){
-			      freeRegistry(&zooRegistry);
-			      free(zooRegistry);
+			  if (t < 0) // failure reading zcfg
+			    {
+			      map *tmp00 = getMapFromMaps (m, "lenv", "message");
+			      char tmp01[1024];
+			      if (tmp00 != NULL)
+				sprintf (tmp01, _("Unable to parse the ZCFG file: %s (%s)"), import->value, tmp00->value);
+			      else
+				sprintf (tmp01, _("Unable to parse the ZCFG file: %s."), import->value);
+			      
+			      zDup2 (saved_stdout, fileno (stdout));
+			      errorException (m, tmp01, "InternalError", NULL);
+			      
+			      freeMaps (&m);
+			      free (m);
+
+			      if(zooRegistry!=NULL){
+				freeRegistry(&zooRegistry);
+				free(zooRegistry);
+			      }
+			      free (orig);
+			      free (REQUEST);
+			      closedir (dirp);
+			      //xmlFreeDoc (doc);
+			      xmlCleanupParser ();
+			      zooXmlCleanupNs ();
+                    
+			      return 1;
 			    }
-			    free (orig);
-			    free (REQUEST);
-			    closedir (dirp);
-			    xmlFreeDoc (doc);
-			    xmlCleanupParser ();
-			    zooXmlCleanupNs ();
-                    
-			    return 1;
-			  }
-#ifdef DEBUG
-			dumpService (s1);
-#endif
-
-			inheritance(zooRegistry,&s1);
-			printDescribeProcessForProcess (zooRegistry,m, n, s1);
-			freeService (&s1);
-			free (s1);
-			s1 = NULL;
-			scount++;
-			hasVal = 1;                
-		    }
+#ifdef DEBUG
+			  dumpService (s1);
+#endif
+			  inheritance(zooRegistry,&s1);
+#ifdef USE_HPC
+			  addNestedOutputs(&s1);
+#endif
+			  printDescribeProcessForProcess (zooRegistry, m, doc, n, s1);
+			  freeService (&s1);
+			  free (s1);
+			  s1 = NULL;
+			  scount++;
+			  hasVal = 1;                
+#ifdef META_DB
+			}
+#endif
+		      }
 		    else if (strstr (corig, ".") != NULL)
 		      {
@@ -1457,6 +1585,12 @@
 			  addToMap (request_inputs, "metapath", tmpMap->value);
 			map *tmpMapI = getMapFromMaps (m, "lenv", "Identifier");
-
-			s1 = (service *) malloc (SERVICE_SIZE);
+			/**
+			 * No support for dot in service name stored in metadb!?
+			 #ifdef META_DB
+			 service* s2=extractServiceFromDb(m,tmpMapI->value,0);
+			 if(s2==NULL){
+			 #endif
+			*/
+			s1 = createService();
 			t = readServiceFile (m, buff1, &s1, tmpMapI->value);
 			if (t < 0)
@@ -1474,5 +1608,5 @@
 				       ("Unable to parse the ZCFG file for the following ZOO-Service: %s."),
 				       tmps);
-			    dup2 (saved_stdout, fileno (stdout));
+			    zDup2 (saved_stdout, fileno (stdout));
 			    errorException (m, tmp01, "InvalidParameterValue",
 					    "identifier");
@@ -1489,5 +1623,5 @@
 			    free (s1);
 			    closedir (dirp);
-			    xmlFreeDoc (doc);
+			    //xmlFreeDoc (doc);
 			    xmlCleanupParser ();
 			    zooXmlCleanupNs ();
@@ -1498,5 +1632,8 @@
 #endif
 			inheritance(zooRegistry,&s1);
-			printDescribeProcessForProcess (zooRegistry,m, n, s1);
+#ifdef USE_HPC
+			addNestedOutputs(&s1);
+#endif
+			printDescribeProcessForProcess (zooRegistry, m, doc, n, s1);
 			freeService (&s1);
 			free (s1);
@@ -1508,81 +1645,110 @@
 		    else
 		      {
-			memset (buff, 0, 256);
-			snprintf (buff, 256, "%s.zcfg", corig);
-			memset (buff1, 0, 1024);
-#ifdef DEBUG
-			printf ("\n#######%s\n########\n", buff);
-#endif
-			while ((dp = readdir (dirp)) != NULL)
-			  {
-			    if (strcasecmp (dp->d_name, buff) == 0)
-			      {
-				memset (buff1, 0, 1024);
-				snprintf (buff1, 1024, "%s/%s", conf_dir,
-					  dp->d_name);
-				s1 = (service *) malloc (SERVICE_SIZE);
-				if (s1 == NULL)
-				  {
-				    dup2 (saved_stdout, fileno (stdout));
-				    return errorException (m,
-							   _
-							   ("Unable to allocate memory"),
-							   "InternalError",
-							   NULL);
-				  }
+#ifdef META_DB
+			_init_sql(m,"metadb");
+			//FAILED CONNECTING DB
+			if(getMapFromMaps(m,"lenv","dbIssue")!=NULL){
+			  fprintf(stderr,"ERROR CONNECTING METADB");
+			}
+			service* s2=extractServiceFromDb(m,corig,0);
+			if(s2!=NULL){
+			  inheritance(zooRegistry,&s2);
+#ifdef USE_HPC
+			  addNestedOutputs(&s2);
+#endif
+			  printDescribeProcessForProcess (zooRegistry,m, doc, n, s2);
+			  freeService (&s2);
+			  free (s2);
+			  s2 = NULL;
+			  hasVal = 1;
+			}else /*TOTO*/{
+#endif
+			  memset (buff, 0, 256);
+			  snprintf (buff, 256, "%s.zcfg", corig);
+			  memset (buff1, 0, 1024);
+#ifdef DEBUG
+			  printf ("\n#######%s\n########\n", buff);
+#endif
+			  while ((dp = readdir (dirp)) != NULL)
+			    {
+			      if (strcasecmp (dp->d_name, buff) == 0)
+				{
+				  memset (buff1, 0, 1024);
+				  snprintf (buff1, 1024, "%s/%s", conf_dir,
+					    dp->d_name);
+				  s1 = createService();
+				  if (s1 == NULL)
+				    {
+				      zDup2 (saved_stdout, fileno (stdout));
+				      return errorException (m,
+							     _
+							     ("Unable to allocate memory"),
+							     "InternalError",
+							     NULL);
+				    }
 #ifdef DEBUG_SERVICE_CONF
-				fprintf
-				  (stderr,"#################\n(%s) %s\n#################\n",
-				   r_inputs->value, buff1);
-#endif
-				char *tmp0 = zStrdup (dp->d_name);
-				tmp0[strlen (tmp0) - 5] = 0;
-				t = readServiceFile (m, buff1, &s1, tmp0);
-				free (tmp0);
-				if (t < 0)
-				  {
-				    map *tmp00 =
-				      getMapFromMaps (m, "lenv", "message");
-				    char tmp01[1024];
-				    if (tmp00 != NULL)
-				      sprintf (tmp01,
-					       _
-					       ("Unable to parse the ZCFG file: %s (%s)"),
-					       dp->d_name, tmp00->value);
-				    else
-				      sprintf (tmp01,
-					       _
-					       ("Unable to parse the ZCFG file: %s."),
-					       dp->d_name);
-				    dup2 (saved_stdout, fileno (stdout));
-				    errorException (m, tmp01, "InternalError",
-						    NULL);
-				    freeMaps (&m);
-				    free (m);
-				    if(zooRegistry!=NULL){
-				      freeRegistry(&zooRegistry);
-				      free(zooRegistry);
+				  fprintf
+				    (stderr,"#################\n(%s) %s\n#################\n",
+				     r_inputs->value, buff1);
+#endif
+				  char *tmp0 = zStrdup (dp->d_name);
+				  tmp0[strlen (tmp0) - 5] = 0;
+				  t = readServiceFile (m, buff1, &s1, tmp0);
+				  free (tmp0);
+				  if (t < 0)
+				    {
+				      map *tmp00 =
+					getMapFromMaps (m, "lenv", "message");
+				      char tmp01[1024];
+				      if (tmp00 != NULL)
+					sprintf (tmp01,
+						 _
+						 ("Unable to parse the ZCFG file: %s (%s)"),
+						 dp->d_name, tmp00->value);
+				      else
+					sprintf (tmp01,
+						 _
+						 ("Unable to parse the ZCFG file: %s."),
+						 dp->d_name);
+				      zDup2 (saved_stdout, fileno (stdout));
+				      errorException (m, tmp01, "InternalError",
+						      NULL);
+				      freeMaps (&m);
+				      free (m);
+				      if(zooRegistry!=NULL){
+					freeRegistry(&zooRegistry);
+					free(zooRegistry);
+				      }
+				      free (orig);
+				      free (REQUEST);
+				      closedir (dirp);
+				      //xmlFreeDoc (doc);
+				      xmlCleanupParser ();
+				      zooXmlCleanupNs ();
+				      return 1;
 				    }
-				    free (orig);
-				    free (REQUEST);
-				    closedir (dirp);
-				    xmlFreeDoc (doc);
-				    xmlCleanupParser ();
-				    zooXmlCleanupNs ();
-				    return 1;
-				  }
-#ifdef DEBUG
-				dumpService (s1);
-#endif
-				inheritance(zooRegistry,&s1);
-				printDescribeProcessForProcess (zooRegistry,m, n, s1);
-				freeService (&s1);
-				free (s1);
-				s1 = NULL;
-				scount++;
-				hasVal = 1;
-			      }
-			  }
-		      }
+#ifdef DEBUG
+				  dumpService (s1);
+#endif
+				  inheritance(zooRegistry,&s1);
+#ifdef USE_HPC
+				  addNestedOutputs(&s1);
+#endif
+				  /*json_object* jobj=serviceToJson(s1);
+				  const char* jsonStr=json_object_to_json_string_ext(jobj,JSON_C_TO_STRING_PLAIN);
+				  fprintf(stderr,"*** %s %d %s \n",__FILE__,__LINE__,jsonStr);*/
+
+				  printDescribeProcessForProcess (zooRegistry,m, doc, n, s1);
+				  freeService (&s1);
+				  free (s1);
+				  s1 = NULL;
+				  scount++;
+				  hasVal = 1;
+				}
+			    }
+#ifdef META_DB
+			}
+#endif
+		      }		      
 		    if (hasVal < 0)
 		      {
@@ -1597,5 +1763,5 @@
 				   _("Unable to parse the ZCFG file: %s."),
 				   buff);
-			dup2 (saved_stdout, fileno (stdout));
+			zDup2 (saved_stdout, fileno (stdout));
 			errorException (m, tmp01, "InvalidParameterValue",
 					"Identifier");
@@ -1609,4 +1775,6 @@
 			free (REQUEST);
 			closedir (dirp);
+			if (corig != NULL)
+			  free (corig);
 			xmlFreeDoc (doc);
 			xmlCleanupParser ();
@@ -1618,11 +1786,11 @@
 		    if (corig != NULL)
 		      free (corig);
-		  }
+		  }		  
 	      }
 	    closedir (dirp);
 	    fflush (stdout);
-	    dup2 (saved_stdout, fileno (stdout));
+	    zDup2 (saved_stdout, fileno (stdout));
 	    free (orig);
-	    printDocument (m, doc, getpid ());
+	    printDocument (m, doc, zGetpid ());
 	    freeMaps (&m);
 	    free (m);
@@ -1634,4 +1802,8 @@
 	    free (SERVICE_URL);
 	    fflush (stdout);
+#ifdef META_DB
+	    close_sql(m,0);
+	    //end_sql();
+#endif
 	    return 0;
 	  }
@@ -1640,6 +1812,6 @@
 	    map* version=getMapFromMaps(m,"main","rversion");
 	    int vid=getVersionId(version->value);	    
-		int len = 0;
-		int j = 0;
+	    int len = 0;
+	    int j = 0;
 	    for(j=0;j<nbSupportedRequests;j++){
 	      if(requests[vid][j]!=NULL)
@@ -1712,26 +1884,11 @@
   }
   s1 = NULL;
-  s1 = (service *) malloc (SERVICE_SIZE);
-  if (s1 == NULL)
-    {
-      freeMaps (&m);
-      free (m);
-      if(zooRegistry!=NULL){
-	freeRegistry(&zooRegistry);
-	free(zooRegistry);
-      }
-      free (REQUEST);
-      free (SERVICE_URL);
-      return errorException (m, _("Unable to allocate memory"),
-                             "InternalError", NULL);
-    }
-
+ 
   r_inputs = getMap (request_inputs, "Identifier");
-
   map* import = getMapFromMaps (m, IMPORTSERVICE, r_inputs->value); 
   if (import != NULL && import->value != NULL) { 
-      strncpy(tmps1, import->value, 1024);
-      setMapInMaps (m, "lenv", "Identifier", r_inputs->value);
-      setMapInMaps (m, "lenv", "oIdentifier", r_inputs->value);
+    strncpy(tmps1, import->value, 1024);
+    setMapInMaps (m, "lenv", "Identifier", r_inputs->value);
+    setMapInMaps (m, "lenv", "oIdentifier", r_inputs->value);
   } 
   else {
@@ -1757,32 +1914,76 @@
 
   r_inputs = getMapFromMaps (m, "lenv", "Identifier");
-  int saved_stdout = dup (fileno (stdout));
-  dup2 (fileno (stderr), fileno (stdout));
-  t = readServiceFile (m, tmps1, &s1, r_inputs->value);
-  inheritance(zooRegistry,&s1);
-  if(zooRegistry!=NULL){
-    freeRegistry(&zooRegistry);
-    free(zooRegistry);
+  
+#ifdef META_DB
+  int metadb_id=_init_sql(m,"metadb");
+  //FAILED CONNECTING DB
+  if(getMapFromMaps(m,"lenv","dbIssue")!=NULL || metadb_id<0){
+    fprintf(stderr,"ERROR CONNECTING METADB\n");
   }
-  fflush (stdout);
-  dup2 (saved_stdout, fileno (stdout));
-  if (t < 0)
-    {
-      char *tmpMsg = (char *) malloc (2048 + strlen (r_inputs->value));
-      sprintf (tmpMsg,
-               _
-               ("The value for <identifier> seems to be wrong (%s). Please specify one of the processes in the list returned by a GetCapabilities request."),
-               r_inputs->value);
-      errorException (m, tmpMsg, "InvalidParameterValue", "identifier");
-      free (tmpMsg);
-      free (s1);
-      freeMaps (&m);
-      free (m);
-      free (REQUEST);
-      free (SERVICE_URL);
-      return 0;
-    }
-  close (saved_stdout);
-
+  if(metadb_id>=0)
+    s1=extractServiceFromDb(m,r_inputs->value,0);
+  //close_sql(m,0);
+  if(s1!=NULL){
+    inheritance(zooRegistry,&s1);
+#ifdef USE_HPC
+    addNestedOutputs(&s1);
+#endif
+    if(zooRegistry!=NULL){
+      freeRegistry(&zooRegistry);
+      free(zooRegistry);
+    }
+  }else /* Not found in MetaDB */{
+#endif
+    s1 = createService();
+    if (s1 == NULL)
+      {
+	freeMaps (&m);
+	free (m);
+	if(zooRegistry!=NULL){
+	  freeRegistry(&zooRegistry);
+	  free(zooRegistry);
+	}
+	free (REQUEST);
+	free (SERVICE_URL);
+	return errorException (m, _("Unable to allocate memory"),
+			       "InternalError", NULL);
+      }
+
+    int saved_stdout = zDup (fileno (stdout));
+    zDup2 (fileno (stderr), fileno (stdout));
+    t = readServiceFile (m, tmps1, &s1, r_inputs->value);
+    if(t>=0){
+      inheritance(zooRegistry,&s1);
+#ifdef USE_HPC
+      addNestedOutputs(&s1);
+#endif
+    }
+    if(zooRegistry!=NULL){
+      freeRegistry(&zooRegistry);
+      free(zooRegistry);
+    }
+    fflush (stdout);
+    zDup2 (saved_stdout, fileno (stdout));
+    if (t < 0)
+      {
+	char *tmpMsg = (char *) malloc (2048 + strlen (r_inputs->value));
+	sprintf (tmpMsg,
+		 _
+		 ("The value for <identifier> seems to be wrong (%s). Please specify one of the processes in the list returned by a GetCapabilities request."),
+		 r_inputs->value);
+	errorException (m, tmpMsg, "InvalidParameterValue", "identifier");
+	free (tmpMsg);
+	free (s1);
+	freeMaps (&m);
+	free (m);
+	free (REQUEST);
+	free (SERVICE_URL);
+	return 0;
+      }
+    zClose (saved_stdout);
+#ifdef META_DB
+  }
+#endif
+  
 #ifdef DEBUG
   dumpService (s1);
@@ -1821,5 +2022,6 @@
     return 0;
   }
-
+  //InternetCloseHandle (&hInternet);
+  
   // Define each env variable in runing environment
   maps *curs = getMaps (m, "env");
@@ -1862,9 +2064,10 @@
                      2) * sizeof (char));
           sprintf (toto, "%s=%s", mapcs->name, mapcs->value);
-          putenv (toto);
+          _putenv (toto);
 #ifdef DEBUG
           fflush (stderr);
 #endif
 #endif
+
 #ifdef DEBUG
           fprintf (stderr, "[ZOO: setenv (%s=%s)]\n", mapcs->name,
@@ -1959,6 +2162,12 @@
 
   int eres = SERVICE_STARTED;
-  int cpid = getpid ();
-
+  int cpid = zGetpid ();
+
+  // Create a map containing a copy of the request map
+  maps *_tmpMaps = createMaps("request");
+  addMapToMap(&_tmpMaps->content,request_inputs);
+  addMapsToMaps (&m, _tmpMaps);
+  freeMaps (&_tmpMaps);
+  free (_tmpMaps);
   /**
    * Initialize the specific [lenv] section which contains runtime variables:
@@ -1981,5 +2190,5 @@
    *
    */
-  maps *_tmpMaps = createMaps("lenv");
+  _tmpMaps = createMaps("lenv");
   char tmpBuff[100];
   struct ztimeval tp;
@@ -2009,53 +2218,16 @@
     addToMap (_tmpMaps->content, "soap", "false");
 
-  // Parse the session file and add it to the main maps 
+  // Parse the session file and add it to the main maps
+  char* originalCookie=NULL;
   if (cgiCookie != NULL && strlen (cgiCookie) > 0)
     {
       int hasValidCookie = -1;
-      char *tcook = zStrdup (cgiCookie);
-      char *tmp = NULL;
+      char *tcook = originalCookie = zStrdup (cgiCookie);
       map *testing = getMapFromMaps (m, "main", "cookiePrefix");
-      if (testing == NULL)
+      parseCookie(&m,originalCookie);
+      map *sessId=getMapFromMaps(m,"cookies",(testing==NULL?"ID":testing->value));
+      if (sessId!=NULL)
         {
-          tmp = zStrdup ("ID=");
-        }
-      else
-        {
-          tmp =
-            (char *) malloc ((strlen (testing->value) + 2) * sizeof (char));
-          sprintf (tmp, "%s=", testing->value);
-        }
-      if (strstr (cgiCookie, ";") != NULL)
-        {
-          char *token, *saveptr;
-          token = strtok_r (cgiCookie, ";", &saveptr);
-          while (token != NULL)
-            {
-              if (strcasestr (token, tmp) != NULL)
-                {
-                  if (tcook != NULL)
-                    free (tcook);
-                  tcook = zStrdup (token);
-                  hasValidCookie = 1;
-                }
-              token = strtok_r (NULL, ";", &saveptr);
-            }
-        }
-      else
-        {
-          if (strstr (cgiCookie, "=") != NULL
-              && strcasestr (cgiCookie, tmp) != NULL)
-            {
-              tcook = zStrdup (cgiCookie);
-              hasValidCookie = 1;
-            }
-          if (tmp != NULL)
-            {
-              free (tmp);
-            }
-        }
-      if (hasValidCookie > 0)
-        {
-          addToMap (_tmpMaps->content, "sessid", strstr (tcook, "=") + 1);
+	  addToMap (_tmpMaps->content, "sessid", sessId->value);
           char session_file_path[1024];
           map *tmpPath = getMapFromMaps (m, "main", "sessPath");
@@ -2065,8 +2237,8 @@
           if (tmp1 != NULL)
             sprintf (session_file_path, "%s/sess_%s.cfg", tmpPath->value,
-                     strstr (tmp1, "=") + 1);
+                     sessId->value);
           else
             sprintf (session_file_path, "%s/sess_%s.cfg", tmpPath->value,
-                     strstr (cgiCookie, "=") + 1);
+                     sessId->value);
           free (tcook);
           maps *tmpSess = (maps *) malloc (MAPS_SIZE);
@@ -2076,7 +2248,12 @@
           if (istat == 0 && file_status.st_size > 0)
             {
+	      int saved_stdout = zDup (fileno (stdout));
+	      zDup2 (fileno (stderr), fileno (stdout));
               conf_read (session_file_path, tmpSess);
               addMapsToMaps (&m, tmpSess);
               freeMaps (&tmpSess);
+	      fflush(stdout);
+	      zDup2 (saved_stdout, fileno (stdout));
+	      zClose(saved_stdout);
             }
 	  free (tmpSess);
@@ -2091,26 +2268,53 @@
 #endif
   int ei = 1;
-  char *s = 
+  
 #ifdef WIN32
-    GetEnvironmentStrings();
+  LPVOID orig = GetEnvironmentStrings();
+  LPTSTR s = (LPTSTR) orig;
 #else
-    *environ;
-#endif
+  char **orig = environ;
+  char *s=*orig;
+#endif
+
   _tmpMaps = createMaps("renv");
-  for (; s; ei++) {
-    char* tmpName=zStrdup(s);
-    char* tmpValue=strstr(s,"=")+1;
-    tmpName[strlen(tmpName)-strlen(tmpValue)-1]=0;
-    if(_tmpMaps->content == NULL)
-      _tmpMaps->content = createMap (tmpName,tmpValue);
-    else
-      addToMap (_tmpMaps->content,tmpName,tmpValue);
-    free(tmpName);
-    s = *(environ+ei);
+if(orig!=NULL)
+  for (; 
+#ifdef WIN32
+       *s;
+       s++
+#else
+       s;
+       ei++
+#endif
+       ) {
+    if(strstr(s,"=")!=NULL && strlen(strstr(s,"="))>1){
+      int len=strlen(s);
+      char* tmpName=zStrdup(s);
+      char* tmpValue=strstr(s,"=")+1;
+      char* tmpName1=(char*)malloc((1+(len-(strlen(tmpValue)+1)))*sizeof(char));
+      snprintf(tmpName1,(len-strlen(tmpValue)),"%s",tmpName);
+      if(_tmpMaps->content == NULL)
+	_tmpMaps->content = createMap (tmpName1,tmpValue);
+      else
+	addToMap (_tmpMaps->content,tmpName1,tmpValue);
+      free(tmpName1);
+      free(tmpName);
+    }
+#ifndef WIN32
+    s = *(orig+ei);
+#endif
+  }
+  if(_tmpMaps->content!=NULL && getMap(_tmpMaps->content,"HTTP_COOKIE")!=NULL){
+    addToMap(_tmpMaps->content,"HTTP_COOKIE1",&cgiCookie[0]);
   }
   addMapsToMaps (&m, _tmpMaps);
   freeMaps (&_tmpMaps);
   free (_tmpMaps);
-
+#ifdef WIN32
+  FreeEnvironmentStrings((LPCH)orig);
+#endif
+  if(postRequest!=NULL)
+    setMapInMaps (m, "renv", "xrequest", postRequest->value);
+  //dumpMaps(m);
 #ifdef WIN32
   char *cgiSidL = NULL;
@@ -2160,6 +2364,13 @@
 	return -1;
       }
+      map* testMap=getMapFromMaps(m,"main","memory");
+      if(testMap==NULL || strcasecmp(testMap->value,"load")!=0)
+	dumpMapsValuesToFiles(&m,&request_input_real_format);
       loadServiceAndRun (&m, s1, request_inputs, &request_input_real_format,
-                         &request_output_real_format, &eres);
+                         &request_output_real_format, &eres);	  
+
+#ifdef META_DB
+      close_sql(m,0);      
+#endif      
     }
   else
@@ -2169,5 +2380,4 @@
       fprintf (stderr, "\nPID : %d\n", cpid);
 #endif
-
 #ifndef WIN32
       pid = fork ();
@@ -2175,97 +2385,100 @@
       if (cgiSid == NULL)
         {
-          createProcess (m, request_inputs, s1, NULL, cpid,
-                         request_input_real_format,
-                         request_output_real_format);
-          pid = cpid;
+	  createProcess (m, request_inputs, s1, NULL, cpid,
+			 request_input_real_format,
+			 request_output_real_format);
+	  pid = cpid;
         }
       else
         {
-          pid = 0;
-          cpid = atoi (cgiSid);
+	  pid = 0;
+	  cpid = atoi (cgiSid);
 	  updateStatus(m,0,_("Initializing"));
         }
 #endif
       if (pid > 0)
-        {
-	  /**
-	   * dady :
-	   * set status to SERVICE_ACCEPTED
-	   */
-#ifdef DEBUG
-          fprintf (stderr, "father pid continue (origin %d) %d ...\n", cpid,
-                   getpid ());
-#endif
-          eres = SERVICE_ACCEPTED;
-        }
+	{
+	  //
+	  // dady :
+	  // set status to SERVICE_ACCEPTED
+	  //
+#ifdef DEBUG
+	  fprintf (stderr, "father pid continue (origin %d) %d ...\n", cpid,
+		   zGetpid ());
+#endif
+	  eres = SERVICE_ACCEPTED;
+	}
       else if (pid == 0)
-        {
-	  /**
-	   * son : have to close the stdout, stdin and stderr to let the parent
-	   * process answer to http client.
-	   */
+	{
+	  eres = SERVICE_ACCEPTED;
+	  //
+	  // son : have to close the stdout, stdin and stderr to let the parent
+	  // process answer to http client.
+	  //
 	  map* usid = getMapFromMaps (m, "lenv", "uusid");
-          map* tmpm = getMapFromMaps (m, "lenv", "osid");
-          int cpid = atoi (tmpm->value);
-          r_inputs = getMapFromMaps (m, "main", "tmpPath");
+	  map* tmpm = getMapFromMaps (m, "lenv", "osid");
+	  int cpid = atoi (tmpm->value);
+	  pid=cpid;
+	  r_inputs = getMapFromMaps (m, "main", "tmpPath");
+	  setMapInMaps (m, "lenv", "async","true");
 	  map* r_inputs1 = createMap("ServiceName", s1->name);
 
 	  // Create the filename for the result file (.res)
-          fbkpres =
-            (char *)
-            malloc ((strlen (r_inputs->value) +
-                     strlen (usid->value) + 7) * sizeof (char));                    
-          sprintf (fbkpres, "%s/%s.res", r_inputs->value, usid->value);
+	  fbkpres =
+	    (char *)
+	    malloc ((strlen (r_inputs->value) +
+		     strlen (usid->value) + 7) * sizeof (char));                    
+	  sprintf (fbkpres, "%s/%s.res", r_inputs->value, usid->value);
 	  bmap = createMaps("status");
 	  bmap->content=createMap("usid",usid->value);
 	  addToMap(bmap->content,"sid",tmpm->value);
-	  addIntToMap(bmap->content,"pid",getpid());
-	  	  
+	  addIntToMap(bmap->content,"pid",zGetpid());
+	  
 	  // Create PID file referencing the OS process identifier
-          fbkpid =
-            (char *)
-            malloc ((strlen (r_inputs->value) +
-                     strlen (usid->value) + 7) * sizeof (char));
-          sprintf (fbkpid, "%s/%s.pid", r_inputs->value, usid->value);
+	  fbkpid =
+	    (char *)
+	    malloc ((strlen (r_inputs->value) +
+		     strlen (usid->value) + 7) * sizeof (char));
+	  sprintf (fbkpid, "%s/%s.pid", r_inputs->value, usid->value);
 	  setMapInMaps (m, "lenv", "file.pid", fbkpid);
 
-          f0 = freopen (fbkpid, "w+",stdout);
-	  printf("%d",getpid());
+	  f0 = freopen (fbkpid, "w+",stdout);
+	  printf("%d",zGetpid());
 	  fflush(stdout);
 
 	  // Create SID file referencing the semaphore name
-          fbkp =
-            (char *)
-            malloc ((strlen (r_inputs->value) + strlen (r_inputs1->value) +
-                     strlen (usid->value) + 7) * sizeof (char));
-          sprintf (fbkp, "%s/%s.sid", r_inputs->value, usid->value);
+	  fbkp =
+	    (char *)
+	    malloc ((strlen (r_inputs->value) + strlen (r_inputs1->value) +
+		     strlen (usid->value) + 7) * sizeof (char));
+	  sprintf (fbkp, "%s/%s.sid", r_inputs->value, usid->value);
 	  setMapInMaps (m, "lenv", "file.sid", fbkp);
-          FILE* f2 = freopen (fbkp, "w+",stdout);
+	  FILE* f2 = freopen (fbkp, "w+",stdout);
 	  printf("%s",tmpm->value);
 	  fflush(f2);
 	  free(fbkp);
 
-          fbkp =
-            (char *)
-            malloc ((strlen (r_inputs->value) + strlen (r_inputs1->value) +
-                     strlen (usid->value) + 7) * sizeof (char));
-          sprintf (fbkp, "%s/%s_%s.xml", r_inputs->value, r_inputs1->value,
-                   usid->value);
+	  fbkp =
+	    (char *)
+	    malloc ((strlen (r_inputs->value) + strlen (r_inputs1->value) +
+		     strlen (usid->value) + 7) * sizeof (char));
+	  sprintf (fbkp, "%s/%s_%s.xml", r_inputs->value, r_inputs1->value,
+		   usid->value);
 	  setMapInMaps (m, "lenv", "file.responseInit", fbkp);
-          flog =
-            (char *)
-            malloc ((strlen (r_inputs->value) + strlen (r_inputs1->value) +
-                     strlen (usid->value) + 13) * sizeof (char));
-          sprintf (flog, "%s/%s_%s_error.log", r_inputs->value,
-                   r_inputs1->value, usid->value);
+	  flog =
+	    (char *)
+	    malloc ((strlen (r_inputs->value) + strlen (r_inputs1->value) +
+		     strlen (usid->value) + 13) * sizeof (char));
+	  sprintf (flog, "%s/%s_%s_error.log", r_inputs->value,
+		   r_inputs1->value, usid->value);
 	  setMapInMaps (m, "lenv", "file.log", flog);
 #ifdef DEBUG
-          fprintf (stderr, "RUN IN BACKGROUND MODE \n");
-          fprintf (stderr, "son pid continue (origin %d) %d ...\n", cpid,
-                   getpid ());
-          fprintf (stderr, "\nFILE TO STORE DATA %s\n", r_inputs->value);
-#endif
-          freopen (flog, "w+", stderr);
-          fflush (stderr);
+	  fprintf (stderr, "RUN IN BACKGROUND MODE \n");
+	  fprintf (stderr, "son pid continue (origin %d) %d ...\n", cpid,
+		   zGetpid ());
+	  fprintf (stderr, "\nFILE TO STORE DATA %s\n", r_inputs->value);
+#endif
+	  freopen (flog, "w+", stderr);
+	  fflush (stderr);
 	  f0 = freopen (fbkp, "w+", stdout);
 	  rewind (stdout);
@@ -2277,11 +2490,14 @@
 	  recordServiceStatus(m);
 #endif
+#ifdef USE_CALLBACK
+	  invokeCallback(m,NULL,NULL,0,0);
+#endif
 	  if(vid==0){
-	    /**
-	     * set status to SERVICE_STARTED and flush stdout to ensure full 
-	     * content was outputed (the file used to store the ResponseDocument).
-	     * The rewind stdout to restart writing from the bgining of the file,
-	     * this way the data will be updated at the end of the process run.
-	     */
+	    //
+	    // set status to SERVICE_STARTED and flush stdout to ensure full 
+	    // content was outputed (the file used to store the ResponseDocument).
+	    // Then, rewind stdout to restart writing from the begining of the file.
+	    // This way, the data will be updated at the end of the process run.
+	    //
 	    printProcessResponse (m, request_inputs, cpid, s1, r_inputs1->value,
 				  SERVICE_STARTED, request_input_real_format,
@@ -2293,25 +2509,59 @@
 	  }
 
-          fflush (stderr);
-
-          fbkp1 =
-            (char *)
-            malloc ((strlen (r_inputs->value) + strlen (r_inputs1->value) +
-                     strlen (usid->value) + 13) * sizeof (char));
-          sprintf (fbkp1, "%s/%s_final_%s.xml", r_inputs->value,
-                   r_inputs1->value, usid->value);
+	  fflush (stderr);
+
+	  fbkp1 =
+	    (char *)
+	    malloc ((strlen (r_inputs->value) + strlen (r_inputs1->value) +
+		     strlen (usid->value) + 13) * sizeof (char));
+	  sprintf (fbkp1, "%s/%s_final_%s.xml", r_inputs->value,
+		   r_inputs1->value, usid->value);
 	  setMapInMaps (m, "lenv", "file.responseFinal", fbkp1);
 
-          f1 = freopen (fbkp1, "w+", stdout);
-
+	  f1 = freopen (fbkp1, "w+", stdout);
+
+	  map* serviceTypeMap=getMap(s1->content,"serviceType");
+	  if(serviceTypeMap!=NULL)
+	    setMapInMaps (m, "lenv", "serviceType", serviceTypeMap->value);
+
+	  char *flenv =
+	    (char *)
+	    malloc ((strlen (r_inputs->value) + 
+		     strlen (usid->value) + 12) * sizeof (char));
+	  sprintf (flenv, "%s/%s_lenv.cfg", r_inputs->value, usid->value);
+	  maps* lenvMaps=getMaps(m,"lenv");
+	  dumpMapsToFile(lenvMaps,flenv,0);
+	  free(flenv);
+
+#ifdef USE_CALLBACK
+	  invokeCallback(m,request_input_real_format,NULL,1,0);
+#endif
 	  if(validateRequest(&m,s1,request_inputs, &request_input_real_format,&request_output_real_format,&hInternet)<0){
 	    freeService (&s1);
 	    free (s1);
+	    fflush (stdout);
+	    fflush (stderr);
 	    fclose (f0);
 	    fclose (f1);
 	    if(dumpBackFinalFile(m,fbkp,fbkp1)<0)
 	      return -1;
-	    unlink (fbkpid);		
+#ifndef RELY_ON_DB
+	    dumpMapsToFile(bmap,fbkpres,1);
+	    removeShmLock (m, 1);
+#else
+	    recordResponse(m,fbkp1);
+#ifdef USE_CALLBACK
+	    invokeCallback(m,NULL,NULL,7,0);
+#endif
+#endif
+	    zUnlink (fbkpid);
 	    unhandleStatus (m);
+#ifdef RELY_ON_DB
+#ifdef META_DB
+	    cleanupCallbackThreads();
+	    close_sql(m,1);
+#endif
+	    close_sql(m,0);
+#endif
 	    freeMaps (&m);
 	    free (m);
@@ -2324,12 +2574,21 @@
 	    freeMaps (&tmpmaps);
 	    free (tmpmaps);
-	    fflush (stdout);
-	    fflush (stderr);
 	    return -1;
 	  }
-          loadServiceAndRun (&m, s1, request_inputs,
-                             &request_input_real_format,
-                             &request_output_real_format, &eres);
-        }
+	  if(getMapFromMaps(m,"lenv","mapError")!=NULL){
+	    setMapInMaps(m,"lenv","message",_("Issue with geographic data"));
+#ifdef USE_CALLBACK
+	    invokeCallback(m,NULL,NULL,7,0);
+#endif
+	    eres=-1;//SERVICE_FAILED;
+	  }else{
+	    map* testMap=getMapFromMaps(m,"main","memory");
+	    if(testMap==NULL || strcasecmp(testMap->value,"load")!=0)
+	      dumpMapsValuesToFiles(&m,&request_input_real_format);
+	    loadServiceAndRun (&m, s1, request_inputs,
+			       &request_input_real_format,
+			       &request_output_real_format, &eres);
+	  }
+	}
       else
         {
@@ -2338,14 +2597,19 @@
 	   * error response here !!!
 	   */
-          eres = -1;
-          errorException (m, _("Unable to run the child process properly"),
-                          "InternalError", NULL);
+	  eres = -1;
+	  errorException (m, _("Unable to run the child process properly"),
+			  "InternalError", NULL);
         }
     }
-
-#ifdef DEBUG
+	
+#ifdef DEBUG
+  fprintf (stderr, "RUN IN BACKGROUND MODE %s %d \n",__FILE__,__LINE__);
   dumpMaps (request_output_real_format);
-#endif
-
+  fprintf (stderr, "RUN IN BACKGROUND MODE %s %d \n",__FILE__,__LINE__);
+#endif
+  fflush(stdout);
+  rewind(stdout);
+
+  //fprintf(stderr,"%s %d %d\n",__FILE__,__LINE__,eres);  
   if (eres != -1)
     outputResponse (s1, request_input_real_format,
@@ -2353,5 +2617,5 @@
                     cpid, m, eres);
   fflush (stdout);
-
+  
   /**
    * Ensure that if error occurs when freeing memory, no signal will return
@@ -2367,16 +2631,22 @@
   signal (SIGABRT, donothing);
 #endif
-  if (((int) getpid ()) != cpid || cgiSid != NULL)
-    {	  
+
+  if (((int) zGetpid ()) != cpid || cgiSid != NULL)
+    {
+      if (eres == SERVICE_SUCCEEDED)
+#ifdef USE_CALLBACK
+	invokeCallback(m,NULL,request_output_real_format,5,1);
+#endif
+      fflush(stderr);
+      fflush(stdout);
+
       fclose (stdout);
-      fclose (stderr);
 
       fclose (f0);
       fclose (f1);
-	 
-	  if (dumpBackFinalFile(m, fbkp, fbkp1) < 0)
-		  return -1;
-	
-      unlink (fbkpid);	  
+
+      if(dumpBackFinalFile(m,fbkp,fbkp1)<0)
+	return -1;
+      zUnlink (fbkpid);
       switch(eres){
       default:
@@ -2390,24 +2660,45 @@
 	break;
       }      
-#ifndef RELY_ON_DB	  
+#ifndef RELY_ON_DB
       dumpMapsToFile(bmap,fbkpres,1);
       removeShmLock (m, 1);
 #else
       recordResponse(m,fbkp1);
+      if (eres == SERVICE_SUCCEEDED)
+#ifdef USE_CALLBACK
+	invokeCallback(m,NULL,request_output_real_format,6,0);
+#endif
 #endif
       freeMaps(&bmap);
       free(bmap);
-      unlink (fbkp1);
-      unlink (flog);
+      zUnlink (fbkp1);
       unhandleStatus (m);
+#ifdef RELY_ON_DB
+#ifdef META_DB
+      cleanupCallbackThreads();
+      close_sql(m,1);
+#endif
+      close_sql(m,0);
+      end_sql();
+#endif
       free(fbkpid);
       free(fbkpres); 
-      free (flog);           
       free (fbkp1);
-      // free (tmps1); // tmps1 is stack memory and should not be freed
       if(cgiSid!=NULL)
 	free(cgiSid);
-    }
-
+      //InternetCloseHandle (&hInternet);
+      fprintf (stderr, "RUN IN BACKGROUND MODE %s %d \n",__FILE__,__LINE__);
+      fflush(stderr);
+      fclose (stderr);
+      zUnlink (flog);
+      free (flog);
+    }
+  else{
+    //InternetCloseHandle (&hInternet);  
+#ifdef META_DB
+    close_sql(m,0);
+#endif
+  }
+  
   freeService (&s1);
   free (s1);
@@ -2429,5 +2720,5 @@
 #endif
 
-  if (((int) getpid ()) != cpid || cgiSid != NULL)
+  if (((int) zGetpid ()) != cpid || cgiSid != NULL)
     {
       exit (0);
Index: trunk/zoo-project/zoo-services/cgal/Makefile
===================================================================
--- trunk/zoo-project/zoo-services/cgal/Makefile	(revision 889)
+++ trunk/zoo-project/zoo-services/cgal/Makefile	(revision 917)
@@ -1,5 +1,5 @@
 ZRPATH=../..
 include ${ZRPATH}/zoo-kernel/ZOOMakefile.opts
-CFLAGS=-I${INST_INCLUDE} ${ZOO_CFLAGS} ${XML2CFLAGS} ${GDAL_CFLAGS} ${PYTHONCFLAGS} ${CGAL_CFLAGS} -frounding-math -fPIC -DLINUX_FREE_ISSUE #-DDEBUG
+CFLAGS= ${ZOO_CFLAGS} ${XML2CFLAGS} ${GDAL_CFLAGS} ${PYTHONCFLAGS} ${CGAL_CFLAGS} -frounding-math -fPIC -DLINUX_FREE_ISSUE #-DDEBUG
 CC=gcc
 
@@ -7,5 +7,5 @@
 	g++ ${CFLAGS} -c ./delaunay.c
 	g++ ${CFLAGS} -c ./voronoi.c
-	g++ ${CFLAGS} -shared -o cgi-env/cgal_service.zo ./delaunay.o ./voronoi.o ./cgal_service.o ${GDAL_LIBS} ${MACOS_LD_FLAGS} ${CGAL_LDFLAGS} -lCGAL -lgmp ${GDAL_LIBS} -L${ZRPATH}/zoo-kernel/ -lzoo_service
+	g++ ${CFLAGS} -shared -o cgi-env/cgal_service.zo ./delaunay.o ./voronoi.o ./cgal_service.o ${GDAL_LIBS} ${CGAL_LDFLAGS} -lCGAL -lgmp ${GDAL_LIBS} -L${ZRPATH}/zoo-kernel/ -lzoo_service -lfcgi
 
 cgal_service.o: cgal_service.c cgal_service.h
Index: trunk/zoo-project/zoo-services/cgal/cgal_service.c
===================================================================
--- trunk/zoo-project/zoo-services/cgal/cgal_service.c	(revision 889)
+++ trunk/zoo-project/zoo-services/cgal/cgal_service.c	(revision 917)
@@ -24,17 +24,32 @@
 #include "cgal_service.h"
 
-int parseInput(maps* conf,maps* inputs, std::vector<Point>* points,char* filename){
+int parseInput(maps* conf,maps* inputs, std::vector<Pointz>* points,char* filename){
   map* tmpm=NULL;
-  tmpm=getMapFromMaps(inputs,"InputPoints","value");
-  VSILFILE *ifile=VSIFileFromMemBuffer(filename,(GByte*)tmpm->value,strlen(tmpm->value),FALSE);
-  VSIFCloseL(ifile);
+  tmpm=getMapFromMaps(inputs,"InputPoints","cache_file");
 #if GDAL_VERSION_MAJOR >= 2
-  GDALDataset *ipoDS =
-    (GDALDataset*) GDALOpenEx( filename,
-			       GDAL_OF_READONLY | GDAL_OF_VECTOR,
-			       NULL, NULL, NULL );
+  GDALDataset *ipoDS;
 #else
-  OGRDataSource* ipoDS = OGRSFDriverRegistrar::Open(filename,FALSE);
+  OGRDataSource* ipoDS;
 #endif
+  if(tmpm==NULL){
+    tmpm=getMapFromMaps(inputs,"InputPoints","value");
+    VSILFILE *ifile=VSIFileFromMemBuffer(filename,(GByte*)tmpm->value,strlen(tmpm->value),FALSE);
+    VSIFCloseL(ifile);
+#if GDAL_VERSION_MAJOR >= 2
+  ipoDS = (GDALDataset*) GDALOpenEx( filename,
+				     GDAL_OF_READONLY | GDAL_OF_VECTOR,
+				     NULL, NULL, NULL );
+#else
+  ipoDS = OGRSFDriverRegistrar::Open(filename,FALSE);
+#endif
+  }else
+#if GDAL_VERSION_MAJOR >= 2
+    ipoDS = (GDALDataset*) GDALOpenEx( tmpm->value,
+				       GDAL_OF_READONLY | GDAL_OF_VECTOR,
+				       NULL, NULL, NULL );
+#else
+    ipoDS = OGRSFDriverRegistrar::Open(tmpm->value,FALSE);
+#endif
+    
   if( ipoDS == NULL )
     {
@@ -87,5 +102,5 @@
 	  break;
 	if(poFeature->GetGeometryRef() != NULL){
-	  points->push_back(Point(OGR_G_GetX(poFeature->GetGeometryRef(),0),OGR_G_GetY(poFeature->GetGeometryRef(),0)));
+	  points->push_back(Pointz(OGR_G_GetX(poFeature->GetGeometryRef(),0),OGR_G_GetY(poFeature->GetGeometryRef(),0)));
 	}
       }
Index: trunk/zoo-project/zoo-services/cgal/cgal_service.h
===================================================================
--- trunk/zoo-project/zoo-services/cgal/cgal_service.h	(revision 889)
+++ trunk/zoo-project/zoo-services/cgal/cgal_service.h	(revision 917)
@@ -38,7 +38,7 @@
 
 typedef CGAL::Exact_predicates_inexact_constructions_kernel            Kernel;
-typedef Kernel::Point_2                                                Point;
+typedef Kernel::Point_2                                                Pointz;
 
-int parseInput(maps*,maps*, std::vector<Point>*,char*);
+int parseInput(maps*,maps*, std::vector<Pointz>*,char*);
 
 #endif
Index: trunk/zoo-project/zoo-services/cgal/cgi-env/Voronoi.zcfg
===================================================================
--- trunk/zoo-project/zoo-services/cgal/cgi-env/Voronoi.zcfg	(revision 889)
+++ trunk/zoo-project/zoo-services/cgal/cgi-env/Voronoi.zcfg	(revision 917)
@@ -46,4 +46,10 @@
     </Default>
     <Supported>
+      mimeType = image/png
+      useMapserver = true
+      asReference = true
+      msStyle = STYLE COLOR 125 0 105 OUTLINECOLOR 0 0 0 WIDTH 0.3 OPACITY 65 END
+    </Supported>
+    <Supported>
      mimeType = text/xml
      encoding = base64
Index: trunk/zoo-project/zoo-services/cgal/delaunay.c
===================================================================
--- trunk/zoo-project/zoo-services/cgal/delaunay.c	(revision 889)
+++ trunk/zoo-project/zoo-services/cgal/delaunay.c	(revision 917)
@@ -40,5 +40,5 @@
     OGRRegisterAll();
 
-    std::vector<Point> points;
+    std::vector<Pointz> points;
     if(int res=parseInput(conf,inputs,&points,"/vsimem/tmp")!=SERVICE_SUCCEEDED)
       return res;
Index: trunk/zoo-project/zoo-services/cgal/voronoi.c
===================================================================
--- trunk/zoo-project/zoo-services/cgal/voronoi.c	(revision 889)
+++ trunk/zoo-project/zoo-services/cgal/voronoi.c	(revision 917)
@@ -24,7 +24,7 @@
 
 #include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
-#include <CGAL/Triangulation_euclidean_traits_xy_3.h>
+//#include <CGAL/Triangulation_euclidean_traits_2.h>
 #include <CGAL/Delaunay_triangulation_2.h>
-#include <CGAL/Constrained_Delaunay_triangulation_2.h>
+//#include <CGAL/Constrained_Delaunay_triangulation_2.h>
 #include <CGAL/Triangulation_conformer_2.h>
 #include <CGAL/Triangulation_face_base_2.h>
@@ -39,4 +39,5 @@
 
 typedef CGAL::Delaunay_triangulation_2<Kernel>  Triangulation;
+typedef Triangulation::Face_iterator  Face_iterator;
 typedef Triangulation::Edge_iterator  Edge_iterator;
 typedef Triangulation::Vertex_circulator Vertex_circulator;
@@ -45,7 +46,8 @@
 
   int Voronoi(maps*& conf,maps*& inputs,maps*& outputs){
-#ifdef DEBUG
+    //#ifdef DEBUG
     fprintf(stderr,"\nService internal print\nStarting\n");
-#endif
+    //#endif
+    //return SERVICE_FAILED;
     maps* cursor=inputs;
     OGRGeometryH geometry,res;
@@ -54,14 +56,22 @@
     tmpm=getMapFromMaps(inputs,"InputPoints","value");
 
+    fprintf(stderr," **** %s %d\n",__FILE__,__LINE__);
+    fflush(stderr);
+
     OGRRegisterAll();
 
-    std::vector<Point> points;
-    if(int res=parseInput(conf,inputs,&points,"/vsimem/tmp")!=SERVICE_SUCCEEDED)
-      return res;
+    std::vector<Pointz> points;
+    if(int res=parseInput(conf,inputs,&points,"/vsimem/tmp")!=SERVICE_SUCCEEDED){
+      fprintf(stderr," **** %s %d\n",__FILE__,__LINE__);
+      fflush(stderr);
+      return SERVICE_FAILED;
+    }
+    fprintf(stderr," **** %s %d\n",__FILE__,__LINE__);
+    fflush(stderr);
     
     Triangulation T;
     T.insert(points.begin(), points.end());
 
-    OGRRegisterAll();
+    //OGRRegisterAll();
     /* -------------------------------------------------------------------- */
     /*      Try opening the output datasource as an existing, writable      */
@@ -187,10 +197,21 @@
     int ns = 0;
     int nr = 0;
+    int nf = 0;
+    Face_iterator fit =T.faces_begin();
+    FILE* f=fopen("/tmp/toto.log","w+");
+    for ( ; fit !=T.faces_end(); ++fit) {
+      fprintf(stderr," *** %s %d %d %d\n",__FILE__,__LINE__,nf,fit.info());
+      fflush(stderr);
+      
+      nf++;
+    }
+    fclose(f);
     Edge_iterator eit =T.edges_begin();
     for ( ; eit !=T.edges_end(); ++eit) {
       CGAL::Object o = T.dual(eit);
       if (const Kernel::Segment_2 *tmp=CGAL::object_cast<Kernel::Segment_2>(&o)) {
-	const Point p1=tmp->source();
-	const Point p2=tmp->target();
+	const Pointz p1=tmp->source();
+	const Pointz p2=tmp->target();
+	fprintf(stderr,"P1 %d %d | P2 %d %d\n",p1.x(),p1.y(),p2.x(),p2.y());
 #ifdef DEBUG
 	fprintf(stderr,"P1 %d %d | P2 %d %d\n",p1.x(),p1.y(),p2.x(),p2.y());
@@ -210,6 +231,6 @@
       }
       else if (const Kernel::Ray_2 *tmp=CGAL::object_cast<Kernel::Ray_2>(&o)) { 
-	const Point p1=tmp->source();
-	const Point p2=tmp->point(2);
+	const Pointz p1=tmp->source();
+	const Pointz p2=tmp->point(2);
 	OGRFeatureH hFeature = OGR_F_Create( OGR_L_GetLayerDefn( poDstLayer ) );
 	OGRGeometryH currLine=OGR_G_CreateGeometry(wkbLineString);
@@ -250,5 +271,5 @@
     fprintf(stderr,"\nService internal print\n===\n");
 #endif
-    OGRCleanupAll();
+    //OGRCleanupAll();
     return SERVICE_SUCCEEDED;
   }
Index: trunk/zoo-project/zoo-services/gdal/dem/cgi-env/Gdal_Dem.zcfg
===================================================================
--- trunk/zoo-project/zoo-services/gdal/dem/cgi-env/Gdal_Dem.zcfg	(revision 889)
+++ trunk/zoo-project/zoo-services/gdal/dem/cgi-env/Gdal_Dem.zcfg	(revision 917)
@@ -44,4 +44,13 @@
     <Default />
    </LiteralData>
+  [co]
+   Title = Creation Option
+   Abstract = string representing options (NAME=VALUE)
+   minOccurs = 0
+   maxOccurs = 1
+   <LiteralData>
+    DataType = string
+    <Default />
+   </LiteralData>
  </DataInputs>
  <DataOutputs>
Index: trunk/zoo-project/zoo-services/gdal/dem/service.c
===================================================================
--- trunk/zoo-project/zoo-services/gdal/dem/service.c	(revision 889)
+++ trunk/zoo-project/zoo-services/gdal/dem/service.c	(revision 917)
@@ -2486,4 +2486,19 @@
       setMapInMaps(outputs,"Result","value",tmpMap->value);
     }
+    
+    tmpMap=getMapFromMaps(inputs,"co","value");
+    if(tmpMap!=NULL){
+      papszCreateOptions = CSLAddString( papszCreateOptions, tmpMap->value );  
+      map* tmpMap1;
+      maps* tmpMaps=getMaps(inputs,"co");
+      if((tmpMap1=getMapFromMaps(inputs,"co","length"))!=NULL){
+        int i=1;
+        int length=atoi(tmpMap1->value);
+        for(;i<length;i++){
+          tmpMap=getMapArray(tmpMaps->content,"value",i);
+          papszCreateOptions = CSLAddString( papszCreateOptions, tmpMap->value );
+        }
+      } 
+    }    
 
     tmpMap=NULL;
Index: trunk/zoo-project/zoo-services/hello-mono/cgi-env/longProcessMono.zcfg
===================================================================
--- trunk/zoo-project/zoo-services/hello-mono/cgi-env/longProcessMono.zcfg	(revision 889)
+++ trunk/zoo-project/zoo-services/hello-mono/cgi-env/longProcessMono.zcfg	(revision 917)
@@ -1,5 +1,5 @@
 [longProcessMono]
- Title = Create a welcome message string.
- Abstract = Create a welcome string.
+ Title = Demo long process.
+ Abstract = This service doesn't do anything except taking its time, it demonstrates how to use the updateStatus function from your ZOO Service.
  processVersion = 2
  storeSupported = true
@@ -13,22 +13,9 @@
    Title = Input string
    Abstract = The name to display in the welcome message.
-   minOccurs = 1
+   minOccurs = 0
    maxOccurs = 1
    <LiteralData>
     dataType = int
-    <Default>
-    AllowedValues = 101,202,303,404
-    rangeMin = -100
-    rangeMax = 100
-    rangeSpacing = 1
-    rangeClosure = co
-      value = 11
-    </Default>
-    <Supported>
-    	AllowedValues = 405,502,503,504
-    </Supported>
-    <Supported>
-    	AllowedValues = 540,502,603,604
-    </Supported>
+    <Default />
    </LiteralData>
  </DataInputs>
Index: trunk/zoo-project/zoo-services/hello-mono/makefile.vc
===================================================================
--- trunk/zoo-project/zoo-services/hello-mono/makefile.vc	(revision 917)
+++ trunk/zoo-project/zoo-services/hello-mono/makefile.vc	(revision 917)
@@ -0,0 +1,9 @@
+!INCLUDE ../../zoo-kernel/nmake.opt
+	
+all: cgi-env/TestService.dll
+
+cgi-env/TestService.dll: test.cs
+	$(MONO_DIR)\bin\mcs /target:library -r:../../zoo-api/mono/ZMaps.dll -out:cgi-env/TestService.dll test.cs
+
+clean:
+	rm -rf cgi-env/*dll
Index: trunk/zoo-project/zoo-services/hello-r/cgi-env/RVoronoi.zcfg
===================================================================
--- trunk/zoo-project/zoo-services/hello-r/cgi-env/RVoronoi.zcfg	(revision 917)
+++ trunk/zoo-project/zoo-services/hello-r/cgi-env/RVoronoi.zcfg	(revision 917)
@@ -0,0 +1,56 @@
+[RVoronoi]
+ Title = Voronoi Diagram. 
+ Abstract = Computes the edges of Voronoi diagram for a set of data points.
+ Profile = urn:ogc:wps:1.0.0:voronoi
+ processVersion = 2
+ storeSupported = true
+ statusSupported = true
+ serviceProvider = hello.R
+ serviceType = R
+ <DataInputs>
+  [InputPoints]
+   Title = Data points
+   Abstract = The set of data points.
+   minOccurs = 1
+   maxOccurs = 1
+   <ComplexData>
+    <Default>
+     mimeType = text/xml
+     encoding = UTF-8
+     schema = http://schemas.opengis.net/gml/3.1.0/base/feature.xsd
+    </Default>
+    <Supported>
+     mimeType = text/xml
+     encoding = base64
+     schema = http://schemas.opengis.net/gml/3.1.0/base/feature.xsd
+    </Supported>
+   </ComplexData>
+ </DataInputs>
+ <DataOutputs>
+  [Result]
+   Title = Voronoi Diagram.
+   Abstract = JSON String / GML Entity of the Voronoi Diagram.
+   <ComplexOutput>
+    <Default>
+     mimeType = application/json
+     encoding = UTF-8
+    </Default>
+    <Supported>
+     mimeType = image/png
+     useMapserver = true
+     msStyle = STYLE COLOR 125 0 105 OUTLINECOLOR 0 0 0 WIDTH 0.3 OPACITY 65 END
+    </Supported>
+    <Supported>
+     mimeType = text/xml
+     encoding = base64
+     schema = http://schemas.opengis.net/gml/3.1.0/base/feature.xsd
+     useMapserver = true
+    </Supported>
+    <Supported>
+     mimeType = text/xml
+     encoding = UTF-8
+     schema = http://schemas.opengis.net/gml/3.1.0/base/feature.xsd
+     useMapserver = true
+    </Supported>
+   </ComplexOutput>
+ </DataOutputs>  
Index: trunk/zoo-project/zoo-services/hello-r/cgi-env/failR.zcfg
===================================================================
--- trunk/zoo-project/zoo-services/hello-r/cgi-env/failR.zcfg	(revision 917)
+++ trunk/zoo-project/zoo-services/hello-r/cgi-env/failR.zcfg	(revision 917)
@@ -0,0 +1,28 @@
+[failR]
+ Title = HelloWorld Service in R
+ Abstract = Output and Hello Wolrd string
+ processVersion = 2
+ storeSupported = true
+ statusSupported = true
+ serviceProvider = hello.R
+ serviceType = R
+ <DataInputs>
+  [S]
+   Title = Name
+   Abstract = The name to display in the hello message
+   minOccurs = 0
+   maxOccurs = 1
+   <LiteralData>
+    dataType = string
+    <Default />
+   </LiteralData>
+ </DataInputs>
+ <DataOutputs>
+  [Result]
+   Title = The resulting string
+   Abstract = The string created by service.
+   <LiteralOutput>
+     dataType = string
+    <Default />
+   </LiteralOutput>
+ </DataOutputs>  
Index: trunk/zoo-project/zoo-services/hello-r/cgi-env/hello.R
===================================================================
--- trunk/zoo-project/zoo-services/hello-r/cgi-env/hello.R	(revision 917)
+++ trunk/zoo-project/zoo-services/hello-r/cgi-env/hello.R	(revision 917)
@@ -0,0 +1,61 @@
+source("minimal.r")
+
+hellor <- function(a,b,c) {
+    # Create a useless graph
+    cars <- c(1,2,3,4,5)
+    filePath <- paste(a[["main"]][["tmpPath"]],paste("cars",zoo[["conf"]][["lenv"]][["usid"]],".png",sep=""),sep="/")
+    png(filePath)
+    plot(cars)
+    quartzFonts(avenir = c("Avenir Book", "Avenir Black", "Avenir Book Oblique", "Avenir Black Oblique"))
+    par(family = 'avenir')
+    title("Hello from R World!")
+    dev.off()
+    # Set the result
+    zoo[["outputs"]][["Result"]][["value"]] <<- paste("Hello",b[["S"]][["value"]],"from the R World! (plot ref:",filePath,")",sep=" ")
+    # Update the main conf settings
+    zoo[["conf"]][["lenv"]][["message"]] <<- "Running from R world!"
+    # Return SERVICE_SUCCEEDEED
+    return(zoo[["SERVICE_SUCCEEDEED"]])
+}
+
+failR <- function(conf,inputs,outputs){
+    zoo[["conf"]][["lenv"]][["message"]] <<- ZOOTranslate("Failed running from R world!")
+    return(zoo[["SERVICE_FAILED"]])
+}
+
+voronoipolygons <- function(x,poly) {
+  require(deldir)
+  if (.hasSlot(x, 'coords')) {
+    crds <- x@coords  
+  } else crds <- x
+  bb = bbox(poly)
+  rw = as.numeric(t(bb))
+  z <- deldir(crds[,1], crds[,2],rw=rw)
+  w <- tile.list(z)
+  polys <- vector(mode='list', length=length(w)) 
+  require(sp)
+  finalCoordinates <- c()
+  for (i in seq(along=polys)) {
+    pcrds <- cbind(w[[i]]$x, w[[i]]$y)
+    pcrds <- rbind(pcrds, pcrds[1,])
+    finalCoordinates[[i]] <- i
+    polys[[i]] <- Polygons(list(Polygon(pcrds)), ID=as.character(i))
+  }
+  SP <- SpatialPolygons(polys)
+  voronoi <- SpatialPolygonsDataFrame(SP, data=data.frame(identifier=finalCoordinates))
+  return(voronoi)
+}
+
+RVoronoi <- function(conf,inputs,outputs){
+    require(rgdal)
+    require(rgeos)
+    message(names(inputs[["InputPoints"]]))
+    message(inputs[["InputPoints"]])
+    myGeoData <- readOGR(inputs[["InputPoints"]][["cache_file"]],layer=ogrListLayers(inputs[["InputPoints"]][["cache_file"]])[1], verbose = FALSE);
+    voronoiData <- voronoipolygons(myGeoData,myGeoData)
+    filePath <- paste(conf[["main"]][["tmpPath"]],paste("RBuffer_",zoo[["conf"]][["lenv"]][["usid"]],".shp",sep=""),sep="/")
+    writeOGR(voronoiData, dsn=filePath, layer="Voronoi", driver="ESRI Shapefile", verbose = FALSE)
+    zoo[["outputs"]][["Result"]][["storage"]] <<- filePath
+    return(zoo[["SERVICE_SUCCEEDEED"]])
+}
+
Index: trunk/zoo-project/zoo-services/hello-r/cgi-env/hellor.zcfg
===================================================================
--- trunk/zoo-project/zoo-services/hello-r/cgi-env/hellor.zcfg	(revision 917)
+++ trunk/zoo-project/zoo-services/hello-r/cgi-env/hellor.zcfg	(revision 917)
@@ -0,0 +1,28 @@
+[hellor]
+ Title = HelloWorld Service in R
+ Abstract = Output and Hello Wolrd string
+ processVersion = 2
+ storeSupported = true
+ statusSupported = true
+ serviceProvider = hello.R
+ serviceType = R
+ <DataInputs>
+  [S]
+   Title = Name
+   Abstract = The name to display in the hello message
+   minOccurs = 1
+   maxOccurs = 1
+   <LiteralData>
+    dataType = string
+    <Default />
+   </LiteralData>
+ </DataInputs>
+ <DataOutputs>
+  [Result]
+   Title = The resulting string
+   Abstract = The string created by service.
+   <LiteralOutput>
+     dataType = string
+    <Default />
+   </LiteralOutput>
+ </DataOutputs>  
Index: trunk/zoo-project/zoo-services/ogr/base-vect-ops-py/cgi-env/ogr_sp.py
===================================================================
--- trunk/zoo-project/zoo-services/ogr/base-vect-ops-py/cgi-env/ogr_sp.py	(revision 889)
+++ trunk/zoo-project/zoo-services/ogr/base-vect-ops-py/cgi-env/ogr_sp.py	(revision 917)
@@ -95,4 +95,16 @@
 
 def extractInputs(conf,obj):
+    if obj.keys().count("cache_file"):
+        print >> sys.stderr,obj
+        geometry=[]
+        ds = osgeo.ogr.Open(obj["cache_file"])
+        lyr = ds.GetLayer(0)
+        feat = lyr.GetNextFeature()
+        while feat is not None:
+            geometry+=[feat.Clone()]
+            feat.Destroy()
+            feat = lyr.GetNextFeature()
+        ds.Destroy()
+        return geometry    
     if obj["mimeType"]=="application/json":
         return createLayerFromJson(conf,obj["value"])
Index: trunk/zoo-project/zoo-services/ogr/base-vect-ops/service.c
===================================================================
--- trunk/zoo-project/zoo-services/ogr/base-vect-ops/service.c	(revision 889)
+++ trunk/zoo-project/zoo-services/ogr/base-vect-ops/service.c	(revision 917)
@@ -473,11 +473,11 @@
 	  {
 
-	    if( EQUAL(
+	    if( 
 #if GDAL_VERSION_MAJOR >=2
-		      poR->GetDriver(iDriver)->GetDescription()
-#else
-		      poR->GetDriver(iDriver)->GetName()
-#endif
-		      ,oDriver1) )
+		EQUAL(poR->GetDriver(iDriver)->GetDescription(),oDriver1)
+#else
+		EQUAL(poR->GetDriver(iDriver)->GetName(),oDriver1)
+#endif
+		)
 	      {
 		poDriver = poR->GetDriver(iDriver);
Index: trunk/zoo-project/zoo-services/ogr/ogr2ogr/service.c
===================================================================
--- trunk/zoo-project/zoo-services/ogr/ogr2ogr/service.c	(revision 889)
+++ trunk/zoo-project/zoo-services/ogr/ogr2ogr/service.c	(revision 917)
@@ -96,4 +96,5 @@
 #endif
 {
+    char  *pszDialect = NULL;
     const char  *pszFormat = "ESRI Shapefile";
     const char  *pszDataSource = NULL;
@@ -155,5 +156,5 @@
       sprintf(serverAddress,"%s",tmpMap->value);
     }
-    
+
     tmpMap=NULL;
     char tmpurl[1024];
@@ -223,4 +224,9 @@
     if(tmpMap!=NULL && strncasecmp(tmpMap->value,"NULL",4)!=0){
       pszSQLStatement = tmpMap->value;
+    }
+
+    tmpMap=getMapFromMaps(inputs,"dialect","value");
+    if(tmpMap!=NULL){
+      pszDialect=strdup(tmpMap->value);
     }
 
@@ -360,11 +366,5 @@
 	  dfMaxSegmentLength = atof(tmpMap->value);
     }
-
-    /*tmpMap=NULL;
-    tmpMap=getMapFromMaps(inputs,"segmentize","value");
-    if(tmpMap!=NULL){
-	  dfMaxSegmentLength = atof(tmpMap->value);
-    }*/
-
+   
     tmpMap=NULL;
     tmpMap=getMapFromMaps(inputs,"InputDSN","value");
@@ -825,5 +825,5 @@
         
         poResultSet = poDS->ExecuteSQL( pszSQLStatement, poSpatialFilter, 
-                                        NULL );
+                                        pszDialect );
 
         if( poResultSet != NULL )
@@ -841,6 +841,13 @@
             }
             poDS->ReleaseResultSet( poResultSet );
-        }
-    }
+        }else{
+	  setMapInMaps(conf,"lenv","message","There was an error when running yoru SQL query.");
+	  if(pszDialect!=NULL)
+	    free(pszDialect);
+	  return SERVICE_FAILED;
+	}
+    }
+    if(pszDialect!=NULL)
+      free(pszDialect);
 
 /* -------------------------------------------------------------------- */
@@ -901,5 +908,6 @@
 
 #ifdef ZOO_SERVICE
-    outputs->content=createMap("value",(char*)pszwebDestData);
+    setMapInMaps(outputs,"OutputedDataSourceName","value",(char*)pszwebDestData);
+    //outputs->content=createMap("value",(char*)pszwebDestData);
 #endif
 
@@ -930,5 +938,5 @@
     fprintf(stderr,"%s %d\n",__FILE__,__LINE__);
 
-    OGRCleanupAll();
+    //OGRCleanupAll();
     fprintf(stderr,"%s %d\n",__FILE__,__LINE__);
 
@@ -939,4 +947,5 @@
     
 #ifdef ZOO_SERVICE
+    //sleep(10);
     return SERVICE_SUCCEEDED;
 #else
Index: trunk/zoo-project/zoo-services/ogr/tindex/Makefile
===================================================================
--- trunk/zoo-project/zoo-services/ogr/tindex/Makefile	(revision 917)
+++ trunk/zoo-project/zoo-services/ogr/tindex/Makefile	(revision 917)
@@ -0,0 +1,14 @@
+ZRPATH=../../..
+include ${ZRPATH}/zoo-kernel/ZOOMakefile.opts
+CFLAGS=-DZOO_SERVICE ${ZOO_CFLAGS} ${XML2CFLAGS} ${GDAL_CFLAGS} ${PYTHONCFLAGS} -DLINUX_FREE_ISSUE #-DDEBUG
+CC=gcc
+
+cgi-env/ogrtindex_service.zo: service.c $(DEP_LIBS)
+	g++ $(CFLAGS) $(CPPFLAGS) -shared -fpic $<  -o $@ ${GDAL_LIBS} -L${ZRPATH}/zoo-kernel/ -lzoo_service -lfcgi -L/usr/local/Cellar/gettext/0.19.8.1/lib/ -lintl
+
+install:
+	install -d ${CGI_DIR}/ogr/
+	install cgi-env/* ${CGI_DIR}/ogr/
+
+clean:
+	rm -f cgi-env/*zo
Index: trunk/zoo-project/zoo-services/ogr/tindex/cgi-env/Ogrtindex.zcfg
===================================================================
--- trunk/zoo-project/zoo-services/ogr/tindex/cgi-env/Ogrtindex.zcfg	(revision 917)
+++ trunk/zoo-project/zoo-services/ogr/tindex/cgi-env/Ogrtindex.zcfg	(revision 917)
@@ -0,0 +1,67 @@
+[Ogrtindex]
+ Title = Create a tileindex. 
+ Abstract = http://www.gdal.org/ogrtindex.html
+ processVersion = 1
+ storeSupported = true
+ statusSupported = true
+ serviceType = C
+ serviceProvider = ogrtindex_service.zo
+ <MetaData>
+   title = My Demo
+ </MetaData>
+ <DataInputs>
+  [f]
+   Title = Format of the output data
+   Abstract = Select the output format.
+   minOccurs = 0
+   maxOccurs = 1
+   <LiteralData>
+    DataType = string
+    <Default>
+     value = ESRI ShapeFile
+     AllowedValues = KML,geojson,ESRI Shapefile,csv
+    </Default>
+   </LiteralData>
+  [of]
+   Title = Format of the output data
+   Abstract = Select the output format.
+   minOccurs = 0
+   maxOccurs = 1
+   <LiteralData>
+    DataType = string
+    <Default>
+     value = ESRI ShapeFile     
+     AllowedValues = KML,geojson,ESRI Shapefile,csv
+    </Default>
+    <Supported>
+     value = KML
+    </Supported>
+   </LiteralData>
+  [files]
+   Title = The input data source name
+   Abstract = The input data source name to use as source for convertion.
+   minOccurs = 1
+   maxOccurs = 1024
+   <LiteralData>
+    DataType = string
+    <Default />
+   </LiteralData>
+  [OutputName]
+   Title = The output data source name
+   Abstract = The output data name.
+   minOccurs = 1
+   maxOccurs = 1
+   <LiteralData>
+    DataType = string
+    <Default />
+   </LiteralData>
+ </DataInputs>
+ <DataOutputs>
+  [Result]
+   Title = The resulting converted file
+   Abstract = The file name resulting of the convertion
+   <LiteralData>
+    DataType = string
+    <Default />
+   </LiteralData>
+ </DataOutputs>  
Index: trunk/zoo-project/zoo-services/ogr/tindex/service.c
===================================================================
--- trunk/zoo-project/zoo-services/ogr/tindex/service.c	(revision 917)
+++ trunk/zoo-project/zoo-services/ogr/tindex/service.c	(revision 917)
@@ -0,0 +1,1102 @@
+/******************************************************************************
+ *
+ * Project:  OpenGIS Simple Features Reference Implementation
+ * Purpose:  Program to generate a UMN MapServer compatible tile index for a
+ *           set of OGR data sources.
+ * Author:   Frank Warmerdam, warmerdam@pobox.com
+ *
+ ******************************************************************************
+ * Copyright (c) 2002, Frank Warmerdam
+ * Copyright (c) 2007-2010, Even Rouault <even dot rouault at mines-paris dot org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ ****************************************************************************/
+
+#include "cpl_port.h"
+
+#include <cassert>
+#include <vector>
+
+#include "cpl_conv.h"
+#include "cpl_string.h"
+#include "ogr_api.h"
+#include "ogrsf_frmts.h"
+#include "ogr_p.h"
+#include "gdal_version.h"
+//#include "commonutils.h"
+#if GDAL_VERSION_MAJOR >= 2
+#include "gdal.h"
+#include "gdal_priv.h"
+#endif
+#ifdef ZOO_SERVICE
+#include "service.h"
+#include "service_internal.h"
+#endif
+
+CPL_CVSID("$Id$")
+
+#ifdef ZOO_SERVICE
+extern "C" {
+#endif
+
+typedef enum
+{
+    FORMAT_AUTO,
+    FORMAT_WKT,
+    FORMAT_EPSG,
+    FORMAT_PROJ
+} SrcSRSFormat;
+
+/************************************************************************/
+/*                               Usage()                                */
+/************************************************************************/
+
+static void Usage()
+
+{
+    printf("Usage: ogrtindex [-lnum n]... [-lname name]... [-f output_format]\n"
+           "                 [-write_absolute_path] [-skip_different_projection]\n"
+           "                 [-t_srs target_srs]\n"
+           "                 [-src_srs_name field_name] [-src_srs_format [AUTO|WKT|EPSG|PROJ]\n"
+           "                 [-accept_different_schemas]\n"
+           "                 output_dataset src_dataset...\n");
+    printf("\n");
+    printf("  -lnum n: Add layer number 'n' from each source file\n"
+           "           in the tile index.\n");
+    printf("  -lname name: Add the layer named 'name' from each source file\n"
+           "               in the tile index.\n");
+    printf("  -f output_format: Select an output format name.\n");
+    printf("  -tileindex field_name: The name to use for the dataset name.\n"
+           "                         Defaults to LOCATION.\n");
+    printf("  -write_absolute_path: Filenames are written with absolute paths.\n");
+    printf("  -skip_different_projection: Only layers with same projection ref \n"
+           "        as layers already inserted in the tileindex will be inserted.\n");
+    printf("  -accept_different_schemas: by default ogrtindex checks that all layers inserted\n"
+           "                             into the index have the same attribute schemas. If you\n"
+           "                             specify this option, this test will be disabled. Be aware that\n"
+           "                             resulting index may be incompatible with MapServer!\n");
+    printf(
+           "  - If -t_srs is specified, geometries of input files will be transformed to the desired\n"
+           "    target coordinate reference system.\n"
+           "    Note that using this option generates files that are NOT compatible with MapServer < 7.2.\n"
+           "  - Simple rectangular polygons are generated in the same coordinate reference system\n"
+           "    as the vectors, or in target reference system if the -t_srs option is used.\n");
+    printf("\n");
+    printf("If no -lnum or -lname arguments are given it is assumed that\n"
+           "all layers in source datasets should be added to the tile index\n"
+           "as independent records.\n");
+    exit(1);
+}
+
+/************************************************************************/
+/*                                main()                                */
+/************************************************************************/
+
+#ifdef ZOO_SERVICE
+#ifdef WIN32
+  __declspec(dllexport)
+#endif
+  int Ogrtindex(maps*& conf,maps*& inputs,maps*& outputs)
+#else
+  MAIN_START(nArgc, papszArgv)
+#endif
+{
+  FILE* log=fopen("/tmp/error.log","w+");
+  fprintf(log,"**** %s %d \n",__FILE__,__LINE__);
+  fflush(log);
+  //return SERVICE_FAILED;
+    // Check strict compilation and runtime library version as we use C++ API.
+#ifdef ZOO_SERVICE
+  if( !GDAL_CHECK_VERSION("ogrtindex") )
+      {
+	setMapInMaps(conf,"lenv","message",_("Compilation and runtime library versions differ"));
+	return SERVICE_FAILED;
+      }
+    fprintf(log,"**** %s %d \n",__FILE__,__LINE__);
+    fflush(log);
+#else
+    if( !GDAL_CHECK_VERSION(papszArgv[0]) )
+      exit(1);
+#endif
+/* -------------------------------------------------------------------- */
+/*      Register format(s).                                             */
+/* -------------------------------------------------------------------- */
+    OGRRegisterAll();
+
+/* -------------------------------------------------------------------- */
+/*      Processing command line arguments.                              */
+/* -------------------------------------------------------------------- */
+    int nFirstSourceDataset = -1;
+    bool bLayersWildcarded = true;
+    const char *pszFormat = nullptr;
+    const char *pszTileIndexField = "LOCATION";
+    const char *pszOutputName = nullptr;
+    bool write_absolute_path = false;
+    bool skip_different_projection = false;
+    char* current_path = nullptr;
+    bool accept_different_schemas = false;
+    bool bFirstWarningForNonMatchingAttributes = true;
+    const char *pszTargetSRS = "";
+    bool bSetTargetSRS = false;
+    const char* pszSrcSRSName = nullptr;
+    int i_SrcSRSName = -1;
+    bool bSrcSRSFormatSpecified = false;
+    SrcSRSFormat eSrcSRSFormat = FORMAT_AUTO;
+    size_t nMaxFieldSize = 254;
+
+    fprintf(log,"**** %s %d \n",__FILE__,__LINE__);
+    fflush(log);
+#ifdef ZOO_SERVICE
+      // f / of
+      map* tmpMap=getMapFromMaps(inputs,"f","value");
+      if(tmpMap==NULL)
+	tmpMap=getMapFromMaps(inputs,"of","value");
+      if(tmpMap!=NULL)
+	pszFormat = zStrdup(tmpMap->value);
+      fprintf(log,"**** %s %d \n",__FILE__,__LINE__);
+      fflush(log);
+
+      // write_absolute_path
+      tmpMap=getMapFromMaps(inputs,"write_absolute_path","value");
+      if(tmpMap!=NULL && strncasecmp(tmpMap->value,"true",4)==0)
+	write_absolute_path = true;
+      // skip_different_projection
+      tmpMap=getMapFromMaps(inputs,"skip_different_projection","value");
+      if(tmpMap!=NULL && strncasecmp(tmpMap->value,"true",4)==0)
+	skip_different_projection = true;
+      // accept_different_schemas
+      tmpMap=getMapFromMaps(inputs,"accept_different_schemas","value");
+      if(tmpMap!=NULL && strncasecmp(tmpMap->value,"true",4)==0)
+	accept_different_schemas = true;
+      fprintf(log,"**** %s %d \n",__FILE__,__LINE__);
+      fflush(log);
+      // tileindex
+      tmpMap=getMapFromMaps(inputs,"tileindex","value");
+      if(tmpMap!=NULL)
+	pszTileIndexField = zStrdup(tmpMap->value);
+      fprintf(log,"**** %s %d \n",__FILE__,__LINE__);
+      fflush(log);
+      // lname / lnum
+      tmpMap=getMapFromMaps(inputs,"lname","value");
+      if(tmpMap==NULL)
+	tmpMap=getMapFromMaps(inputs,"lnum","value");
+      if(tmpMap!=NULL)
+	bLayersWildcarded = false;
+      fprintf(log,"**** %s %d \n",__FILE__,__LINE__);
+      fflush(log);
+      //dumpMaps(inputs);
+      fprintf(log,"**** %s %d \n",__FILE__,__LINE__);
+      fflush(log);
+      // t_srs
+      tmpMap=getMapFromMaps(inputs,"t_srs","value");
+      fprintf(log,"**** %s %d \n",__FILE__,__LINE__);
+      fflush(log);
+      if(tmpMap!=NULL){
+	pszTargetSRS = zStrdup(tmpMap->value);
+	bSetTargetSRS = true;
+      }
+      fprintf(log,"**** %s %d \n",__FILE__,__LINE__);
+      fflush(log);
+      // src_srs_name
+      //dumpMaps(inputs);
+      tmpMap=getMapFromMaps(inputs,"src_srs_name","value");
+      if(tmpMap!=NULL){
+	pszSrcSRSName = zStrdup(tmpMap->value);
+      }
+      fprintf(log,"**** %s %d \n",__FILE__,__LINE__);
+      fflush(log);
+      // src_srs_format
+      tmpMap=getMapFromMaps(inputs,"src_srs_format","value");
+      if(tmpMap!=NULL){
+	bSrcSRSFormatSpecified = true;
+	const char* pszSRSFormat = zStrdup(tmpMap->value);
+	if( EQUAL(pszSRSFormat, "AUTO") )
+	  eSrcSRSFormat = FORMAT_AUTO;
+	else if( EQUAL(pszSRSFormat, "WKT") )
+	  eSrcSRSFormat = FORMAT_WKT;
+	else if( EQUAL(pszSRSFormat, "EPSG") )
+	  eSrcSRSFormat = FORMAT_EPSG;
+	else if( EQUAL(pszSRSFormat, "PROJ") )
+	  eSrcSRSFormat = FORMAT_PROJ;	
+      }
+      fprintf(log,"**** %s %d \n",__FILE__,__LINE__);
+      fflush(log);
+      // OutputName
+      tmpMap=getMapFromMaps(inputs,"OutputName","value");
+      if(tmpMap!=NULL){
+	pszOutputName = zStrdup(tmpMap->value);
+      }
+      nFirstSourceDataset = 0;
+      fprintf(log,"**** %s %d \n",__FILE__,__LINE__);
+      fflush(log);
+#else      
+    for( int iArg = 1; iArg < nArgc; iArg++ )
+    {
+        if( EQUAL(papszArgv[iArg], "--utility_version") )
+        {
+            printf("%s was compiled against GDAL %s and "
+                   "is running against GDAL %s\n",
+                   papszArgv[0], GDAL_RELEASE_NAME,
+                   GDALVersionInfo("RELEASE_NAME"));
+            return 0;
+        }
+        else if( iArg < nArgc-1 &&
+                 (EQUAL(papszArgv[iArg],"-f") || EQUAL(papszArgv[iArg],"-of")) )
+        {
+            pszFormat = papszArgv[++iArg];
+        }
+        else if( EQUAL(papszArgv[iArg],"-write_absolute_path"))
+        {
+            write_absolute_path = true;
+        }
+        else if( EQUAL(papszArgv[iArg],"-skip_different_projection"))
+        {
+            skip_different_projection = true;
+        }
+        else if( EQUAL(papszArgv[iArg],"-accept_different_schemas"))
+        {
+            accept_different_schemas = true;
+        }
+        else if( iArg < nArgc-1 && EQUAL(papszArgv[iArg],"-tileindex") )
+        {
+            pszTileIndexField = papszArgv[++iArg];
+        }
+        else if( EQUAL(papszArgv[iArg],"-lnum")
+                 || EQUAL(papszArgv[iArg],"-lname") )
+        {
+            iArg++;
+            bLayersWildcarded = false;
+        }
+        else if( iArg < nArgc-1 && strcmp(papszArgv[iArg],"-t_srs") == 0 )
+        {
+            pszTargetSRS = papszArgv[++iArg];
+            bSetTargetSRS = true;
+        }
+        else if( iArg < nArgc-1 &&
+                 strcmp(papszArgv[iArg], "-src_srs_name") == 0 )
+        {
+            pszSrcSRSName = papszArgv[++iArg];
+        }
+        else if( iArg < nArgc-1 &&
+                 strcmp(papszArgv[iArg], "-src_srs_format") == 0 )
+        {
+            bSrcSRSFormatSpecified = true;
+            const char* pszSRSFormat = papszArgv[++iArg];
+            if( EQUAL(pszSRSFormat, "AUTO") )
+                eSrcSRSFormat = FORMAT_AUTO;
+            else if( EQUAL(pszSRSFormat, "WKT") )
+                eSrcSRSFormat = FORMAT_WKT;
+            else if( EQUAL(pszSRSFormat, "EPSG") )
+                eSrcSRSFormat = FORMAT_EPSG;
+            else if( EQUAL(pszSRSFormat, "PROJ") )
+                eSrcSRSFormat = FORMAT_PROJ;
+        }
+        else if( papszArgv[iArg][0] == '-' )
+        {
+            Usage();
+        }
+        else if( pszOutputName == nullptr )
+        {
+            pszOutputName = papszArgv[iArg];
+        }
+        else if( nFirstSourceDataset == -1 )
+        {
+            nFirstSourceDataset = iArg;
+        }
+    }
+#endif
+    fprintf(log,"**** %s %d \n",__FILE__,__LINE__);
+    fflush(log);
+    if( pszOutputName == nullptr || nFirstSourceDataset == -1 )
+        Usage();
+    fprintf(log,"**** %s %d \n",__FILE__,__LINE__);
+    fflush(log);
+
+    if( bSrcSRSFormatSpecified && pszSrcSRSName == nullptr )
+    {
+        fprintf(log,
+                "-src_srs_name must be specified when -src_srs_format is "
+                "specified.\n");
+        Usage();
+    }
+    fprintf(log,"**** %s %d \n",__FILE__,__LINE__);
+    fflush(log);
+
+/* -------------------------------------------------------------------- */
+/*      Create and validate target SRS if given.                        */
+/* -------------------------------------------------------------------- */
+    OGRSpatialReference* poTargetSRS = nullptr;
+    if( bSetTargetSRS )
+    {
+        if( skip_different_projection )
+        {
+            fprintf(log,
+                    "Warning : -skip_different_projection does not apply "
+                    "when -t_srs is requested.\n");
+        }
+        poTargetSRS = new OGRSpatialReference();
+        // coverity[tainted_data]
+        if( poTargetSRS->SetFromUserInput( pszTargetSRS ) != CE_None )
+        {
+            delete poTargetSRS;
+            fprintf(log, "Invalid target SRS `%s'.\n",
+                    pszTargetSRS);
+            exit(1);
+        }
+    }
+    fprintf(log,"**** %s %d \n",__FILE__,__LINE__);
+    fflush(log);
+
+/* -------------------------------------------------------------------- */
+/*      Try to open as an existing dataset for update access.           */
+/* -------------------------------------------------------------------- */
+    GDALDataset *poDstDS = reinterpret_cast<GDALDataset*>(
+        OGROpen(pszOutputName, TRUE, nullptr));
+    fprintf(log,"**** %s %d \n",__FILE__,__LINE__);
+    fflush(log);
+
+/* -------------------------------------------------------------------- */
+/*      If that failed, find the driver so we can create the tile index.*/
+/* -------------------------------------------------------------------- */
+    OGRLayer *poDstLayer = nullptr;
+    int                      nArgc;
+
+    fprintf(log,"**** %s %d \n",__FILE__,__LINE__);
+    fflush(log);
+    if( poDstDS == nullptr )
+    {
+        CPLString osFormat;
+	
+	OGRSFDriverRegistrar     *poR = OGRSFDriverRegistrar::GetRegistrar();
+        GDALDriver              *poDriver = NULL;
+        int                      iDriver;
+	
+	fprintf(log,"**** %s %d \n",__FILE__,__LINE__);
+	fflush(log);
+        for( iDriver = 0;
+             iDriver < poR->GetDriverCount() && poDriver == NULL;
+             iDriver++ )
+        {
+            if( EQUAL(poR->GetDriver(iDriver)->GetDescription(),pszFormat) )
+            {
+	      osFormat=pszFormat;
+                poDriver = poR->GetDriver(iDriver);
+            }
+        }
+
+	fprintf(log,"**** %s %d \n",__FILE__,__LINE__);
+	fflush(log);
+        if( poDriver == NULL )
+        {
+            fprintf( log, "Unable to find driver `%s'.\n", pszFormat );
+            fprintf( log, "The following drivers are available:\n" );
+
+            for( iDriver = 0; iDriver < poR->GetDriverCount(); iDriver++ )
+            {
+                fprintf( log, "  -> `%s'\n", poR->GetDriver(iDriver)->GetDescription() );
+            }
+#ifdef ZOO_SERVICE
+	    setMapInMaps(conf,"lenv","message",_("Unable to find driver!"));	    
+	    return SERVICE_FAILED;
+#else
+            exit( 1 );
+#endif
+        }
+	fprintf(log,"**** %s %d \n",__FILE__,__LINE__);
+	fflush(log);
+
+	/*        if( !CPLTestBool( CSLFetchNameValueDef(poDriver->GetMetadata(), GDAL_DCAP_CREATE, "FALSE") ) )
+        {
+            fprintf( log, "%s driver does not support data source creation.\n",
+                    pszFormat );
+#ifdef ZOO_SERVICE
+	    setMapInMaps(conf,"lenv","message",_("This driver does not support data source creation!"));	    
+	    return SERVICE_FAILED;
+#else
+            exit( 1 );
+#endif
+}*/
+	fprintf(log,"**** %s %d \n",__FILE__,__LINE__);
+	fflush(log);
+
+/* -------------------------------------------------------------------- */
+/*      Now create it.                                                  */
+/* -------------------------------------------------------------------- */
+
+        poDstDS = reinterpret_cast<GDALDataset*>(
+            GDALCreate(poDriver, pszOutputName, 0, 0, 0, GDT_Unknown, nullptr));
+	fprintf(log,"**** %s %d \n",__FILE__,__LINE__);
+	fflush(log);
+        if( poDstDS == nullptr )
+        {
+            fprintf(log, "%s driver failed to create %s\n",
+                    osFormat.c_str(), pszOutputName);
+#ifdef ZOO_SERVICE
+	    setMapInMaps(conf,"lenv","message",_("This driver failed to create!"));
+	    return SERVICE_FAILED;
+#else
+            exit( 1 );
+#endif
+        }
+	fprintf(log,"**** %s %d \n",__FILE__,__LINE__);
+	fflush(log);
+
+        if( poDstDS->GetLayerCount() == 0 )
+        {
+#ifndef ZOO_SERVICE
+	  if( nFirstSourceDataset < nArgc &&
+	      papszArgv[nFirstSourceDataset][0] == '-' )
+            {
+	      nFirstSourceDataset++;
+	    }
+#else
+	  fprintf(log,"**** %s %d \n",__FILE__,__LINE__);
+	  fflush(log);
+	  map* lengthMap=getMapFromMaps(inputs,"files","length");
+	  maps* tmpMaps=getMaps(inputs,"files");
+	  if(lengthMap!=NULL)
+	    nArgc=atoi(lengthMap->value);
+	  else
+	    nArgc=1;
+	  fprintf(log,"**** %s %d \n",__FILE__,__LINE__);
+	  fflush(log);
+#endif	  
+            OGRSpatialReference* poSrcSpatialRef = nullptr;
+            if( bSetTargetSRS )
+            {
+                // Fetches the SRS from target SRS (if set), or from the SRS of
+                // the first layer and use it when creating the
+                // tileindex layer.
+                poSrcSpatialRef = poTargetSRS->Clone();
+            }
+            else if( nFirstSourceDataset < nArgc )
+            {
+#ifdef ZOO_SERVICE
+	  fprintf(log,"**** %s %d %s \n",__FILE__,__LINE__,nFirstSourceDataset);
+	  fflush(log);
+	  fprintf(log,"**** %s %d \n",__FILE__,__LINE__);
+	  fflush(log);
+	  tmpMap=getMapArray(tmpMaps->content,"value",0);
+	  fprintf(log,"**** %s %d \n",__FILE__,__LINE__);
+	  fflush(log);
+	  //dumpMap(tmpMap);
+	  fprintf(log,"**** %s %d \n",__FILE__,__LINE__);
+	  fflush(log);
+#endif
+	  GDALDataset* poDS =
+	    reinterpret_cast<GDALDataset*>(
+#ifndef ZOO_SERVICE
+                    OGROpen(papszArgv[nFirstSourceDataset], FALSE, nullptr)
+#else
+                    OGROpen(tmpMap->value, FALSE, nullptr)
+#endif
+	    );
+	  fprintf(log,"**** %s %d \n",__FILE__,__LINE__);
+	  fflush(log);
+                if( poDS != nullptr )
+                {
+                    for( int iLayer = 0;
+                         iLayer < poDS->GetLayerCount();
+                         iLayer++ )
+                    {
+                        bool bRequested = bLayersWildcarded;
+                        OGRLayer *poLayer = poDS->GetLayer(iLayer);
+
+                        if( !bRequested )
+                            continue;
+
+                        if( poLayer->GetSpatialRef() )
+                            poSrcSpatialRef = poLayer->GetSpatialRef()->Clone();
+                        break;
+                    }
+                }
+
+                GDALClose(poDS);
+            }
+	  fprintf(log,"**** %s %d \n",__FILE__,__LINE__);
+	  fflush(log);
+
+            poDstLayer = poDstDS->CreateLayer("tileindex", poSrcSpatialRef);
+
+            OGRFieldDefn oLocation(pszTileIndexField, OFTString);
+            oLocation.SetWidth(200);
+            poDstLayer->CreateField(&oLocation);
+
+            if( pszSrcSRSName != nullptr )
+            {
+                OGRFieldDefn oSrcSRSNameField(pszSrcSRSName, OFTString);
+                poDstLayer->CreateField(&oSrcSRSNameField);
+            }
+
+            if( poSrcSpatialRef )
+                poSrcSpatialRef->Release();
+	  fprintf(log,"**** %s %d \n",__FILE__,__LINE__);
+	  fflush(log);
+        }
+	fprintf(log,"**** %s %d \n",__FILE__,__LINE__);
+	fflush(log);
+    }
+
+/* -------------------------------------------------------------------- */
+/*      Identify target layer and field.                                */
+/* -------------------------------------------------------------------- */
+
+	fprintf(log,"**** %s %d \n",__FILE__,__LINE__);
+	fflush(log);
+    poDstLayer = poDstDS->GetLayer(0);
+    if( poDstLayer == nullptr )
+    {
+        fprintf(log, "Can't find any layer in output tileindex!\n");
+        exit(1);
+    }
+	fprintf(log,"**** %s %d \n",__FILE__,__LINE__);
+	fflush(log);
+
+    const int iTileIndexField =
+        poDstLayer->GetLayerDefn()->GetFieldIndex(pszTileIndexField);
+    if( iTileIndexField == -1 )
+    {
+        fprintf(log, "Can't find %s field in tile index dataset.\n",
+                pszTileIndexField);
+        exit(1);
+    }
+	fprintf(log,"**** %s %d \n",__FILE__,__LINE__);
+	fflush(log);
+
+    if( pszSrcSRSName != nullptr )
+        i_SrcSRSName = poDstLayer->GetLayerDefn()->GetFieldIndex(pszSrcSRSName);
+
+    OGRFeatureDefn* poFeatureDefn = nullptr;
+
+    // Load in memory existing file names in SHP.
+    char **existingLayersTab = nullptr;
+    OGRSpatialReference* alreadyExistingSpatialRef = nullptr;
+    bool alreadyExistingSpatialRefValid = false;
+    const int nExistingLayers = static_cast<int>(poDstLayer->GetFeatureCount());
+    if( nExistingLayers )
+    {
+        existingLayersTab = static_cast<char **>(
+            CPLMalloc(nExistingLayers * sizeof(char*)));
+        for( int i = 0; i < nExistingLayers; i++ )
+        {
+            OGRFeature* feature = poDstLayer->GetNextFeature();
+            existingLayersTab[i] =
+                CPLStrdup(feature->GetFieldAsString( iTileIndexField));
+            if( i == 0 )
+            {
+                char* filename = CPLStrdup(existingLayersTab[i]);
+                // j used after for.
+                int j = static_cast<int>(strlen(filename)) - 1;
+                for( ; j >= 0; j-- )
+                {
+                    if( filename[j] == ',' )
+                        break;
+                }
+                GDALDataset *poDS = nullptr;
+                if( j >= 0 )
+                {
+                    const int iLayer = atoi(filename + j + 1);
+                    filename[j] = 0;
+                    poDS = reinterpret_cast<GDALDataset *>(
+                        OGROpen(filename, FALSE, nullptr));
+                    if( poDS != nullptr )
+                    {
+                        OGRLayer *poLayer = poDS->GetLayer(iLayer);
+                        if( poLayer )
+                        {
+                            alreadyExistingSpatialRefValid = true;
+                            alreadyExistingSpatialRef =
+                                poLayer->GetSpatialRef() ?
+                                poLayer->GetSpatialRef()->Clone() : nullptr;
+
+                            if( poFeatureDefn == nullptr )
+                                poFeatureDefn =
+                                    poLayer->GetLayerDefn()->Clone();
+                        }
+                        GDALClose(poDS);
+                    }
+                }
+            }
+        }
+    }
+
+	fprintf(log,"**** %s %d \n",__FILE__,__LINE__);
+	fflush(log);
+    if( write_absolute_path )
+    {
+        current_path = CPLGetCurrentDir();
+        if( current_path == nullptr )
+        {
+            fprintf(log,
+                    "This system does not support the CPLGetCurrentDir call. "
+                    "The option -write_absolute_path will have no effect\n");
+            write_absolute_path = false;
+        }
+    }
+	fprintf(log,"**** %s %d \n",__FILE__,__LINE__);
+	fflush(log);
+/* ==================================================================== */
+/*      Process each input datasource in turn.                          */
+/* ==================================================================== */
+#ifdef ZOO_SERVICE
+    maps* tmpMaps=getMaps(inputs,"files");
+    nFirstSourceDataset=0;
+#endif
+    for( ; nFirstSourceDataset < nArgc; nFirstSourceDataset++ )
+    {
+#ifndef ZOO_SERVICE
+      if( papszArgv[nFirstSourceDataset][0] == '-' )
+        {
+            nFirstSourceDataset++;
+            continue;
+        }
+#else
+      tmpMap=getMapArray(tmpMaps->content,"value",nFirstSourceDataset);
+      fprintf(log,"**** %s %d \n",__FILE__,__LINE__);
+      fflush(log);
+      //dumpMap(tmpMap);
+      fprintf(log,"**** %s %d \n",__FILE__,__LINE__);
+      fflush(log);
+
+#endif
+      char* fileNameToWrite = nullptr;
+      VSIStatBuf sStatBuf;
+      if( write_absolute_path &&
+#ifdef ZOO_SERVICE
+            CPLIsFilenameRelative( tmpMap->value ) &&
+            VSIStat( tmpMap->value, &sStatBuf ) == 0
+#else
+            CPLIsFilenameRelative( papszArgv[nFirstSourceDataset] ) &&
+            VSIStat( papszArgv[nFirstSourceDataset], &sStatBuf ) == 0	    
+#endif
+	    )
+        {
+            fileNameToWrite =
+                CPLStrdup(CPLProjectRelativeFilename(
+						     current_path,
+#ifdef ZOO_SERVICE
+						     tmpMap->value
+#else
+						     papszArgv[nFirstSourceDataset]
+#endif
+						     ));
+        }
+        else
+        {
+#ifdef ZOO_SERVICE
+	  fileNameToWrite = CPLStrdup(tmpMap->value);
+#else
+	  fileNameToWrite = CPLStrdup(papszArgv[nFirstSourceDataset]);
+#endif
+        }
+
+        GDALDataset *poDS = reinterpret_cast<GDALDataset*>(
+							   OGROpen(
+#ifdef ZOO_SERVICE
+								   tmpMap->value
+#else
+								   papszArgv[nFirstSourceDataset]
+#endif		    
+								   ,
+								   FALSE,
+								   nullptr )
+							   );
+
+        if( poDS == nullptr )
+        {
+	  fprintf(log, "Failed to open dataset %s, skipping.\n",
+#ifndef ZOO_SERVICE
+		  papszArgv[nFirstSourceDataset]
+#else
+		  tmpMap->value
+#endif
+		  );
+            CPLFree(fileNameToWrite);
+            continue;
+        }
+
+/* -------------------------------------------------------------------- */
+/*      Check all layers, and see if they match requests.               */
+/* -------------------------------------------------------------------- */
+        for( int iLayer = 0; iLayer < poDS->GetLayerCount(); iLayer++ )
+        {
+            bool bRequested = bLayersWildcarded;
+            OGRLayer *poLayer = poDS->GetLayer(iLayer);
+
+#ifndef ZOO_SERVICE
+            for( int iArg = 1; iArg < nArgc && !bRequested; iArg++ )
+            {
+                if( EQUAL(papszArgv[iArg], "-lnum")
+                    && atoi(papszArgv[iArg+1]) == iLayer )
+                    bRequested = true;
+                else if( EQUAL(papszArgv[iArg], "-lname" )
+                         && EQUAL(papszArgv[iArg+1],
+                                  poLayer->GetLayerDefn()->GetName()) )
+                    bRequested = true;
+            }
+#endif
+	    
+            if( !bRequested )
+                continue;
+
+            // Checks that the layer is not already in tileindex.
+            int i = 0;  // Used after for.
+            for( ; i < nExistingLayers; i++ )
+            {
+                // TODO(schwehr): Move this off of the stack.
+                char szLocation[5000] = {};
+                snprintf(szLocation, sizeof(szLocation), "%s,%d",
+                         fileNameToWrite, iLayer);
+                if( EQUAL(szLocation, existingLayersTab[i]) )
+                {
+                    fprintf(log, "Layer %d of %s is already in tileindex. "
+                            "Skipping it.\n",
+                            iLayer, szLocation);
+                    break;
+                }
+            }
+            if( i != nExistingLayers )
+            {
+                continue;
+            }
+
+            OGRSpatialReference* spatialRef = poLayer->GetSpatialRef();
+            // If not set target srs, test that the current file uses same
+            // projection as others.
+            if( !bSetTargetSRS )
+            {
+                if( alreadyExistingSpatialRefValid )
+                {
+                    if( (spatialRef != nullptr &&
+                         alreadyExistingSpatialRef != nullptr &&
+                        spatialRef->IsSame(alreadyExistingSpatialRef) ==
+                          FALSE) ||
+                        ((spatialRef != nullptr) !=
+                        (alreadyExistingSpatialRef != nullptr)) )
+                    {
+                        fprintf(
+                            log,
+                            "Warning : layer %d of %s is not using the same "
+                            "projection system as other files in the "
+                            "tileindex. This may cause problems when using it "
+                            "in MapServer for example.%s\n",
+                            iLayer,
+#ifdef ZOO_SERVICE
+			    tmpMap->value
+#else
+			    papszArgv[nFirstSourceDataset]
+#endif
+			    ,
+                            skip_different_projection ? " Skipping it" : "");
+                        if( skip_different_projection )
+                        {
+                            continue;
+                        }
+                    }
+                }
+                else
+                {
+                    alreadyExistingSpatialRefValid = true;
+                    alreadyExistingSpatialRef =
+                        spatialRef ? spatialRef->Clone() : nullptr;
+                }
+            }
+
+/* -------------------------------------------------------------------- */
+/*      Check if all layers in dataset have the same attributes schema. */
+/* -------------------------------------------------------------------- */
+            if( poFeatureDefn == nullptr )
+            {
+                poFeatureDefn = poLayer->GetLayerDefn()->Clone();
+            }
+            else if( !accept_different_schemas )
+            {
+                OGRFeatureDefn* poFeatureDefnCur = poLayer->GetLayerDefn();
+                assert(nullptr != poFeatureDefnCur);
+
+                const int fieldCount = poFeatureDefnCur->GetFieldCount();
+
+                if( fieldCount != poFeatureDefn->GetFieldCount())
+                {
+                    fprintf( log, "Number of attributes of layer %s of %s "
+                             "does not match ... skipping it.\n",
+                             poLayer->GetLayerDefn()->GetName(),
+#ifdef ZOO_SERVICE
+			     tmpMap->value
+#else		     
+                             papszArgv[nFirstSourceDataset]
+#endif			     
+			     );
+                    if( bFirstWarningForNonMatchingAttributes )
+                    {
+                        fprintf(
+                            log, "Note : you can override this "
+                            "behaviour with -accept_different_schemas option\n"
+                            "but this may result in a tileindex incompatible "
+                            "with MapServer\n");
+                        bFirstWarningForNonMatchingAttributes = false;
+                    }
+                    continue;
+                }
+
+                bool bSkip = false;
+                for( int fn = 0; fn < poFeatureDefnCur->GetFieldCount(); fn++ )
+                {
+                    OGRFieldDefn* poField = poFeatureDefn->GetFieldDefn(fn);
+                    OGRFieldDefn* poFieldCur =
+                        poFeatureDefnCur->GetFieldDefn(fn);
+
+                    // XXX - Should those pointers be checked against NULL?
+                    assert(nullptr != poField);
+                    assert(nullptr != poFieldCur);
+
+                    if( poField->GetType() != poFieldCur->GetType()
+                        || poField->GetWidth() != poFieldCur->GetWidth()
+                        || poField->GetPrecision() != poFieldCur->GetPrecision()
+                        || !EQUAL( poField->GetNameRef(),
+                                   poFieldCur->GetNameRef() ) )
+                    {
+                        fprintf(
+                            log, "Schema of attributes of layer %s of %s "
+                            "does not match. Skipping it.\n",
+                            poLayer->GetLayerDefn()->GetName(),
+#ifdef ZOO_SERVICE
+			    tmpMap->value
+#else		     
+			    papszArgv[nFirstSourceDataset]
+#endif
+				);
+                        if( bFirstWarningForNonMatchingAttributes )
+                        {
+                            fprintf(
+                                log, "Note : you can override this "
+                                "behaviour with -accept_different_schemas "
+                                "option,\nbut this may result in a tileindex "
+                                "incompatible with MapServer\n");
+                            bFirstWarningForNonMatchingAttributes = false;
+                        }
+                        bSkip = true;
+                        break;
+                    }
+                }
+
+                if( bSkip )
+                    continue;
+            }
+
+/* -------------------------------------------------------------------- */
+/*      Get layer extents, and create a corresponding polygon           */
+/*      geometry.                                                       */
+/* -------------------------------------------------------------------- */
+            OGREnvelope sExtents;
+
+            if( poLayer->GetExtent( &sExtents, TRUE ) != OGRERR_NONE )
+            {
+                fprintf(log,
+                        "GetExtent() failed on layer %s of %s, skipping.\n",
+                        poLayer->GetLayerDefn()->GetName(),
+#ifdef ZOO_SERVICE
+			tmpMap->value
+#else		     
+			papszArgv[nFirstSourceDataset]
+#endif
+			);
+                continue;
+            }
+
+            OGRLinearRing oRing;
+            oRing.addPoint(sExtents.MinX, sExtents.MinY);
+            oRing.addPoint(sExtents.MinX, sExtents.MaxY);
+            oRing.addPoint(sExtents.MaxX, sExtents.MaxY);
+            oRing.addPoint(sExtents.MaxX, sExtents.MinY);
+            oRing.addPoint(sExtents.MinX, sExtents.MinY);
+
+            OGRPolygon oRegion;
+            oRegion.addRing(&oRing);
+
+            // If set target srs, do the forward transformation of all points.
+            if( bSetTargetSRS && spatialRef != nullptr )
+            {
+                OGRCoordinateTransformation* poCT = nullptr;
+                if( !spatialRef->IsSame(poTargetSRS) )
+                {
+                    poCT = OGRCreateCoordinateTransformation(spatialRef,
+                                                             poTargetSRS);
+                    if( poCT == nullptr ||
+                        oRegion.transform(poCT) == OGRERR_FAILURE )
+                    {
+                        char* pszSourceWKT = nullptr;
+                        spatialRef->exportToWkt(&pszSourceWKT);
+                        fprintf(
+                            log,
+                            "Warning : unable to transform points from source "
+                            "SRS `%s' to target SRS `%s'\n"
+                            "for file `%s' - file skipped\n",
+                            pszSourceWKT, pszTargetSRS,
+#ifdef ZOO_SERVICE
+			    tmpMap->value
+#else		     
+			    papszArgv[nFirstSourceDataset]
+#endif
+				);
+                        CPLFree(pszSourceWKT);
+                        delete poCT;
+                        continue;
+                    }
+                    delete poCT;
+                }
+            }
+
+/* -------------------------------------------------------------------- */
+/*      Add layer to tileindex.                                         */
+/* -------------------------------------------------------------------- */
+            OGRFeature oTileFeat(poDstLayer->GetLayerDefn());
+
+            // TODO(schwehr): Move this off of the stack.
+            char szLocation[5000] = {};
+            snprintf(szLocation, sizeof(szLocation), "%s,%d",
+                     fileNameToWrite, iLayer);
+            oTileFeat.SetGeometry(&oRegion);
+            oTileFeat.SetField(iTileIndexField, szLocation);
+
+            if( i_SrcSRSName >= 0 && spatialRef != nullptr )
+            {
+                const char* pszAuthorityCode =
+                    spatialRef->GetAuthorityCode(nullptr);
+                const char* pszAuthorityName =
+                    spatialRef->GetAuthorityName(nullptr);
+                char* pszWKT = nullptr;
+                spatialRef->exportToWkt(&pszWKT);
+                if( eSrcSRSFormat == FORMAT_AUTO )
+                {
+                    if( pszAuthorityName != nullptr &&
+                        pszAuthorityCode != nullptr )
+                    {
+                        oTileFeat.SetField(i_SrcSRSName,
+                            CPLSPrintf("%s:%s",
+                                       pszAuthorityName, pszAuthorityCode));
+                    }
+                    else if( nMaxFieldSize == 0 ||
+                            strlen(pszWKT) <= nMaxFieldSize )
+                    {
+                        oTileFeat.SetField(i_SrcSRSName, pszWKT);
+                    }
+                    else
+                    {
+                        char* pszProj4 = nullptr;
+                        if( spatialRef->exportToProj4(&pszProj4) ==
+                              OGRERR_NONE )
+                        {
+                            oTileFeat.SetField(i_SrcSRSName, pszProj4);
+                            CPLFree(pszProj4);
+                        }
+                        else
+                        {
+                            oTileFeat.SetField(i_SrcSRSName, pszWKT);
+                        }
+                    }
+                }
+                else if( eSrcSRSFormat == FORMAT_WKT )
+                {
+                    if( nMaxFieldSize == 0 ||
+                        strlen(pszWKT) <= nMaxFieldSize )
+                    {
+                        oTileFeat.SetField(i_SrcSRSName, pszWKT);
+                    }
+                    else
+                    {
+                        fprintf(
+                            log,
+                            "Cannot write WKT for file %s as it is too long!\n",
+                            fileNameToWrite);
+                    }
+                }
+                else if( eSrcSRSFormat == FORMAT_PROJ )
+                {
+                    char* pszProj4 = nullptr;
+                    if( spatialRef->exportToProj4(&pszProj4) == OGRERR_NONE )
+                    {
+                        oTileFeat.SetField(i_SrcSRSName, pszProj4);
+                        CPLFree(pszProj4);
+                    }
+                }
+                else if( eSrcSRSFormat == FORMAT_EPSG )
+                {
+                    if( pszAuthorityName != nullptr &&
+                        pszAuthorityCode != nullptr )
+                        oTileFeat.SetField(i_SrcSRSName,
+                            CPLSPrintf("%s:%s",
+                                       pszAuthorityName, pszAuthorityCode));
+                }
+                CPLFree(pszWKT);
+            }
+            if( poDstLayer->CreateFeature(&oTileFeat) != OGRERR_NONE )
+            {
+                fprintf(log,
+                        "Failed to create feature on tile index. "
+                        "Terminating.");
+                GDALClose(poDstDS);
+                exit(1);
+            }
+        }
+
+/* -------------------------------------------------------------------- */
+/*      Cleanup this data source.                                       */
+/* -------------------------------------------------------------------- */
+        CPLFree(fileNameToWrite);
+        GDALClose(poDS);
+    }
+
+/* -------------------------------------------------------------------- */
+/*      Close tile index and clear buffers.                             */
+/* -------------------------------------------------------------------- */
+    GDALClose(poDstDS);
+    OGRFeatureDefn::DestroyFeatureDefn(poFeatureDefn);
+
+    if( alreadyExistingSpatialRef != nullptr )
+        alreadyExistingSpatialRef->Release();
+    delete poTargetSRS;
+
+    CPLFree(current_path);
+
+    if( nExistingLayers )
+    {
+        for( int i = 0; i < nExistingLayers; i++ )
+        {
+            CPLFree(existingLayersTab[i]);
+        }
+        CPLFree(existingLayersTab);
+    }
+
+    OGRCleanupAll();
+#ifdef ZOO_SERVICE
+    //setMapInMaps(outputs,"Result","generated_file",pszOutputName);
+    setMapInMaps(outputs,"Result","value",pszOutputName);
+    return  SERVICE_SUCCEEDED;
+#else
+    return 0;
+#endif
+}
+#ifndef ZOO_SERVICE
+MAIN_END
+#endif
+  
+#ifdef ZOO_SERVICE
+}
+#endif
Index: trunk/zoo-project/zoo-services/utils/hpc/Makefile
===================================================================
--- trunk/zoo-project/zoo-services/utils/hpc/Makefile	(revision 917)
+++ trunk/zoo-project/zoo-services/utils/hpc/Makefile	(revision 917)
@@ -0,0 +1,14 @@
+ZRPATH=../../..
+include ${ZRPATH}/zoo-kernel/ZOOMakefile.opts
+CFLAGS=-I${INST_INCLUDE} ${ZOO_CFLAGS} ${XML2CFLAGS} ${GDAL_CFLAGS} ${PYTHONCFLAGS} -DLINUX_FREE_ISSUE #-DDEBUG
+
+cgi-env/wps_hpc.zo: service.c service2.c
+	g++ ${CFLAGS} -shared -fpic -o cgi-env/wps_hpc.zo service.c service2.c ${GDAL_LIBS} ${XML2LDFLAGS} ${MACOS_LD_FLAGS} ${ZOO_LDFLAGS} ${MACOS_LD_NET_FLAGS} ${XSLT_LDFLAGS} ${FCGI_LDFLAGS} -L${ZRPATH}/zoo-kernel/ -lzoo_service ${ZRPATH}/zoo-kernel/sshapi.o ${HPCLDFLAGS}
+
+install:
+	install -d ${CGI_DIR}
+	install cgi-env/*.zcfg ${CGI_DIR}/
+	install cgi-env/*.zo ${CGI_DIR}/
+
+clean:
+	rm -f cgi-env/wps_hpc.zo
Index: trunk/zoo-project/zoo-services/utils/hpc/cgi-env/DeleteData.zcfg
===================================================================
--- trunk/zoo-project/zoo-services/utils/hpc/cgi-env/DeleteData.zcfg	(revision 917)
+++ trunk/zoo-project/zoo-services/utils/hpc/cgi-env/DeleteData.zcfg	(revision 917)
@@ -0,0 +1,50 @@
+[DeleteData]
+ Title = Delete the data associated with an input or an output
+ Abstract = Delete the data associated with an input or an output
+ processVersion = 1
+ storeSupported = true
+ statusSupported = true
+ serviceProvider = wps_hpc.zo
+ serviceType = C
+ <DataInputs>
+  [jobid]
+   Title = the image
+   Abstract = The image to process
+   minOccurs = 1
+   maxOccurs = 1
+   <LiteralData>
+    dataType = string
+    <Default>
+    </Default>
+   </LiteralData>
+  [filename]
+   Title = the image
+   Abstract = The image to process
+   minOccurs = 1
+   maxOccurs = 1
+   <LiteralData>
+    dataType = string
+    <Default>
+    </Default>
+   </LiteralData>
+  [ioname]
+   Title = the input / output name
+   Abstract = the input / output name
+   minOccurs = 1
+   maxOccurs = 1
+   <LiteralData>
+    dataType = string
+    <Default>
+    </Default>
+   </LiteralData>
+ </DataInputs>
+ <DataOutputs>
+  [Result]
+   Title = The resulting string
+   Abstract = The resulting message string.
+   <LiteralOutput>
+    DataType = string
+    <Default>
+    </Default>
+   </LiteralOutput>
+ </DataOutputs>  
Index: trunk/zoo-project/zoo-services/utils/hpc/cgi-env/FinalizeHPC.zcfg
===================================================================
--- trunk/zoo-project/zoo-services/utils/hpc/cgi-env/FinalizeHPC.zcfg	(revision 917)
+++ trunk/zoo-project/zoo-services/utils/hpc/cgi-env/FinalizeHPC.zcfg	(revision 917)
@@ -0,0 +1,30 @@
+[FinalizeHPC]
+ Title = Start phase 3 of HPC execution
+ Abstract = Unblock the ZOO-Kernel awaiting for a remote job execution 
+ processVersion = 1
+ storeSupported = true
+ statusSupported = true
+ serviceProvider = wps_hpc.zo
+ serviceType = C
+ <DataInputs>
+  [JobId]
+   Title = the image
+   Abstract = The image to process
+   minOccurs = 1
+   maxOccurs = 1
+   <LiteralData>
+    dataType = string
+    <Default>
+    </Default>
+   </LiteralData>
+ </DataInputs>
+ <DataOutputs>
+  [Result]
+   Title = The hello string
+   Abstract = The Hello message string.
+   <LiteralOutput>
+    DataType = string
+    <Default>
+    </Default>
+   </LiteralOutput>
+ </DataOutputs>  
Index: trunk/zoo-project/zoo-services/utils/hpc/cgi-env/FinalizeHPC1.zcfg
===================================================================
--- trunk/zoo-project/zoo-services/utils/hpc/cgi-env/FinalizeHPC1.zcfg	(revision 917)
+++ trunk/zoo-project/zoo-services/utils/hpc/cgi-env/FinalizeHPC1.zcfg	(revision 917)
@@ -0,0 +1,30 @@
+[FinalizeHPC1]
+ Title = Start phase 3 of HPC execution
+ Abstract = Unblock the ZOO-Kernel awaiting for a remote job execution 
+ processVersion = 1
+ storeSupported = true
+ statusSupported = true
+ serviceProvider = wps_hpc.zo
+ serviceType = C
+ <DataInputs>
+  [JobId]
+   Title = the image
+   Abstract = The image to process
+   minOccurs = 1
+   maxOccurs = 1
+   <LiteralData>
+    dataType = string
+    <Default>
+    </Default>
+   </LiteralData>
+ </DataInputs>
+ <DataOutputs>
+  [Result]
+   Title = The resulting string
+   Abstract = The message returned by the service execution as a string.
+   <LiteralOutput>
+    DataType = string
+    <Default>
+    </Default>
+   </LiteralOutput>
+ </DataOutputs>  
Index: trunk/zoo-project/zoo-services/utils/hpc/service.c
===================================================================
--- trunk/zoo-project/zoo-services/utils/hpc/service.c	(revision 917)
+++ trunk/zoo-project/zoo-services/utils/hpc/service.c	(revision 917)
@@ -0,0 +1,363 @@
+/**
+ * Author : Gérald FENOY
+ *
+ * Copyright 2017 GeoLabs SARL. All rights reserved.
+ *
+ * This work was supported by public funds received in the framework of GEOSUD,
+ * a project (ANR-10-EQPX-20) of the program "Investissements d'Avenir" managed
+ * by the French National Research Agency
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+
+#include "service.h"
+#include "service_internal.h"
+#include "sshapi.h"
+#include "server_internal.h"
+
+#include <sys/socket.h>
+#include <sys/un.h>
+
+#include <libxml/tree.h>
+#include <libxml/parser.h>
+#include <libxml/xpath.h>
+#include <libxml/xpathInternals.h>
+
+#include <libxslt/xslt.h>
+#include <libxslt/xsltInternals.h>
+#include <libxslt/transform.h>
+#include <libxslt/xsltutils.h>
+
+#include <dirent.h>
+extern "C" {
+
+  /**
+   * FinalizeHPC ZOO Service :
+   * This service is used to inform a ZOO-Kernel waiting for the end of the
+   * execution of a HPC service
+   */
+  ZOO_DLL_EXPORT int FinalizeHPC(maps*& conf,maps*& inputs,maps*& outputs){
+    // Retrieve the jobid corresponding to the identifier generated by SLURM
+    // by reading the file generated when running the SBATCH file
+    map* jobid=getMapFromMaps(inputs,"jobid","value");
+    struct sockaddr_un addr;
+    char buf[100]="3";
+    int fd,rc=NULL;
+    int i=0;
+    map* usid=getMapFromMaps(conf,"lenv","usid");
+    map* tmpPath=getMapFromMaps(conf,"main","tmpPath");
+
+    char *flenv =
+      (char *) malloc ((strlen (tmpPath->value) + 
+			strlen (jobid->value) + 12) * sizeof (char));
+    sprintf (flenv, "%s/%s_lenv.cfg", tmpPath->value, jobid->value);
+    maps* m = (maps *) malloc (MAPS_SIZE);
+    m->child=NULL;
+    m->next=NULL;
+    map* configId=NULL;
+
+    
+    if(conf_read(flenv, m) != 2){
+      configId=getMapFromMaps(m,"lenv","configId");
+      setMapInMaps(conf,"lenv","configId",configId->value);
+    }else{
+      setMapInMaps(conf,"lenv","message",_("Unable to read the lenv section file of the requested jobid"));
+      return SERVICE_FAILED;
+    }
+    
+    SSHCON *test=ssh_connect(conf);
+    /*if(test==NULL){
+      setMapInMaps(conf,"lenv","message",_("Unable to connect using ssh."));
+      return SERVICE_FAILED;
+      }*/
+
+    char *logPath=(char*)malloc((strlen(tmpPath->value)+strlen(jobid->value)+12)*sizeof(char));
+    sprintf(logPath,"%s/exec_out_%s",tmpPath->value,jobid->value);
+    struct stat f_status;
+    int ts=stat(logPath, &f_status);
+    char* fcontent = NULL;
+    if(ts==0) {
+      fcontent=(char*)malloc(sizeof(char)*(f_status.st_size+1));
+      FILE* f=fopen(logPath,"rb");
+      fread(fcontent,f_status.st_size,1,f);
+      int fsize=f_status.st_size;
+      fcontent[fsize]=0;
+      fclose(f);
+    }else{
+      setMapInMaps(conf,"lenv","message",_("No service with this jobid can be found"));
+      return SERVICE_FAILED;
+    }
+    free(logPath);
+    // Run scontrol to check if the service execution ended.
+    // Store all the informations returned by scontrol command as a cfg file to
+    // be parsed back by the ZOO-Kernel waiting for the execution of the remote
+    // service
+    maps* tmpMaps=createMaps("henv");
+    char* command=(char*)malloc((126)*sizeof(char));
+    sprintf(command,"scontrol show jobid | grep -A24 JobId=%s",fcontent);    
+    if(ssh_exec(conf,command,ssh_get_cnt(conf))==0){
+      free(command);
+      setMapInMaps(conf,"lenv","message",_("Failed to run scontrol remotely"));
+      // TODO: check status in db and if available continue in other case return SERVICE_FAILED
+      return SERVICE_FAILED;
+    }else{
+      free(command);
+      logPath=(char*)malloc((strlen(tmpPath->value)+strlen(usid->value)+11)*sizeof(char));
+      sprintf(logPath,"%s/exec_out_%s",tmpPath->value,usid->value);
+      int ts=stat(logPath, &f_status);
+      if(ts==0) {
+	fcontent=(char*)malloc(sizeof(char)*(f_status.st_size+1));
+	FILE* f=fopen(logPath,"rb");
+	fread(fcontent,f_status.st_size,1,f);
+	int fsize=f_status.st_size;
+	fcontent[fsize]=0;
+	fclose(f);
+	free(logPath);
+	char *token, *saveptr;
+	token = strtok_r (fcontent, " ", &saveptr);
+	while (token != NULL)
+	  {
+	    char *token1, *saveptr1;
+	    char *tmpToken=strdup(token);
+	    token1 = strtok_r (tmpToken, "=", &saveptr1);
+	    int isNext=-1;
+	    int hasTwoElements=0;
+	    char *name=NULL;
+	    while (token1 != NULL)
+	      {
+		if(hasTwoElements==0)
+		  name=strdup(token1);
+		if(hasTwoElements<1)
+		  hasTwoElements+=1;
+		else{
+		  char *value=strdup(token1);
+		  if(value[strlen(value)-1]=='\n')
+		    value[strlen(value)-1]=0;
+		  if(strlen(name)>0 && strlen(value)>0){
+		    if(tmpMaps->content==NULL)
+		      tmpMaps->content=createMap(name,value);
+		    else
+		      addToMap(tmpMaps->content,name,value);
+		    free(value);
+		  }
+		  free(name);
+		  hasTwoElements=0;
+		}
+		token1 = strtok_r (NULL, "=", &saveptr1);
+	      }
+	    free(tmpToken);
+	    token = strtok_r (NULL, " ", &saveptr);
+	  }
+      }else{
+	setMapInMaps(conf,"lenv","message",_("Unable to access the downloaded execution log file"));
+	return SERVICE_FAILED;
+      }
+    }
+    logPath=(char*)malloc((strlen(tmpPath->value)+strlen(jobid->value)+15)*sizeof(char));
+    sprintf(logPath,"%s/exec_status_%s",tmpPath->value,jobid->value);
+    dumpMapsToFile(tmpMaps,logPath,0);
+    char *sname=(char*)malloc((strlen(tmpPath->value)+strlen(jobid->value)+21));
+    sprintf(sname,"%s/.wait_socket_%s.sock",tmpPath->value,jobid->value);
+    if ( (fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
+      perror("socket error");
+      setMapInMaps(conf,"lenv","message",_("Socket error"));
+      return SERVICE_FAILED;
+    }
+    memset(&addr, 0, sizeof(addr));
+    addr.sun_family = AF_UNIX;
+    strncpy(addr.sun_path, sname, sizeof(addr.sun_path)-1);
+    if (connect(fd, (struct sockaddr*)&addr, sizeof(addr)) == -1) {
+      perror("connect error");
+      setMapInMaps(conf,"lenv","message",_("Unable to connect"));
+      return SERVICE_FAILED;
+    }
+    if (write(fd, "3", 1) != rc) {
+      if (rc < 0) {
+	perror("write error");
+	setMapInMaps(conf,"lenv","message",_("Unable to announce the successful execution of the HPC service"));
+	close(fd);
+	return SERVICE_FAILED;
+      }
+    }
+    close(fd);
+    setOutputValue(outputs,"Result",(char*)"\"FinalizeHPC run successfully\"",32);
+    unlink(flenv);
+    free(flenv);
+
+    return SERVICE_SUCCEEDED;
+  }
+
+
+  /**
+   * FinalizeHPC1 ZOO Service :
+   * This service is used to inform a ZOO-Kernel waiting for the end of the
+   * execution of a HPC service
+   *
+   * format="AllocCPUS"; for i in $(sacct -e) ; do format="$format,$i"; done; format="$(echo $format | sed "s:AllocCPUS,::")" ; echo $format; sacct --format=$format -p | grep "997f-11e8-9f78-0050569320d2" 
+   *
+   * AllocCPUS,AllocGRES,AllocNodes,AllocTRES,Account,AssocID,AveCPU,AveCPUFreq,AveDiskRead,AveDiskWrite,AvePages,AveRSS,AveVMSize,BlockID,Cluster,Comment,ConsumedEnergy,ConsumedEnergyRaw,CPUTime,CPUTimeRAW,DerivedExitCode,Elapsed,Eligible,End,ExitCode,GID,Group,JobID,JobIDRaw,JobName,Layout,MaxDiskRead,MaxDiskReadNode,MaxDiskReadTask,MaxDiskWrite,MaxDiskWriteNode,MaxDiskWriteTask,MaxPages,MaxPagesNode,MaxPagesTask,MaxRSS,MaxRSSNode,MaxRSSTask,MaxVMSize,MaxVMSizeNode,MaxVMSizeTask,MinCPU,MinCPUNode,MinCPUTask,NCPUS,NNodes,NodeList,NTasks,Priority,Partition,QOS,QOSRAW,ReqCPUFreq,ReqCPUFreqMin,ReqCPUFreqMax,ReqCPUFreqGov,ReqCPUS,ReqGRES,ReqMem,ReqNodes,ReqTRES,Reservation,ReservationId,Reserved,ResvCPU,ResvCPURAW,Start,State,Submit,Suspended,SystemCPU,Timelimit,TotalCPU,UID,User,UserCPU,WCKey,WCKeyID
+   * 28||1|cpu=28,node=1|geosud|258|||||||||cluster||||00:00:56|56|0:0|00:00:02|2018-08-06T15:48:13|2018-08-06T15:48:16|0:0|1019|geosud|883299|883299|ZOO-Project_5bd1c32b-997f-11e8-9f78-0050569320d2_GSDBandMath_6_2_005||||||||||||||||||||28|1|muse044||4294360886|defq|qos_geosud|20|Unknown|Unknown|Unknown|Unknown|1||0n|1|cpu=1,node=1|||00:00:01|00:00:01|1|2018-08-06T15:48:14|COMPLETED|2018-08-06T15:48:13|00:00:00||UNLIMITED|00:00:00|1229|geosudwps|||0|
+   * 
+   */
+  ZOO_DLL_EXPORT int FinalizeHPC1(maps*& conf,maps*& inputs,maps*& outputs){
+    // Retrieve the jobid corresponding to the identifier generated by SLURM
+    // by reading the file generated when running the SBATCH file
+    map* jobid=getMapFromMaps(inputs,"jobid","value");
+    struct sockaddr_un addr;
+    char buf[100]="3";
+    int fd,rc=NULL;
+    int i=0;
+    map* usid=getMapFromMaps(conf,"lenv","usid");
+    map* tmpPath=getMapFromMaps(conf,"main","tmpPath");
+
+    char *flenv =
+      (char *) malloc ((strlen (tmpPath->value) + 
+			strlen (jobid->value) + 12) * sizeof (char));
+    sprintf (flenv, "%s/%s_lenv.cfg", tmpPath->value, jobid->value);
+    maps* m = (maps *) malloc (MAPS_SIZE);
+    m->child=NULL;
+    m->next=NULL;
+    map* configId=NULL;
+
+    
+    if(conf_read(flenv, m) != 2){
+      configId=getMapFromMaps(m,"lenv","configId");
+      setMapInMaps(conf,"lenv","configId",configId->value);
+    }else{
+      setMapInMaps(conf,"lenv","message",_("Unable to read the lenv section file of the requested jobid"));
+      return SERVICE_FAILED;
+    }
+
+    SSHCON *test=ssh_connect(conf);
+    /*if(test==NULL){
+      setMapInMaps(conf,"lenv","message",_("Unable to connect using ssh."));
+      return SERVICE_FAILED;
+      }*/
+
+    char *logPath=(char*)malloc((strlen(tmpPath->value)+strlen(jobid->value)+12)*sizeof(char));
+    sprintf(logPath,"%s/exec_out_%s",tmpPath->value,jobid->value);
+    struct stat f_status;
+    int ts=stat(logPath, &f_status);
+    char* fcontent = NULL;
+    if(ts==0) {
+      fcontent=(char*)malloc(sizeof(char)*(f_status.st_size+1));
+      FILE* f=fopen(logPath,"rb");
+      fread(fcontent,f_status.st_size,1,f);
+      int fsize=f_status.st_size;
+      fcontent[fsize]=0;
+      fclose(f);
+    }else{
+      setMapInMaps(conf,"lenv","message",_("No service with this jobid can be found"));
+      return SERVICE_FAILED;
+    }
+    free(logPath);
+    // Run sacct to check if the service execution ended.
+    // Store all the informations returned by scontrol command as a cfg file to
+    // be parsed back by the ZOO-Kernel waiting for the execution of the remote
+    // service
+    maps* tmpMaps=createMaps("henv");
+    
+    map* tmpMap=getMapFromMaps(conf,configId->value,"remote_command_opt");
+    char* command=(char*)malloc((126+strlen(tmpMap->value))*sizeof(char));
+    sprintf(command,"sacct --format=%s -p | grep \"%s\" | sed \"s:||:|None|:g;s:||:|None|:g\"",tmpMap->value,jobid->value);    
+    if(ssh_exec(conf,command,ssh_get_cnt(conf))==0){
+      free(command);
+      setMapInMaps(conf,"lenv","message",_("Failed to run sacct remotely"));
+      // TODO: check status in db and if available continue in other case return SERVICE_FAILED
+      return SERVICE_FAILED;
+    }else{
+      free(command);
+      logPath=(char*)malloc((strlen(tmpPath->value)+strlen(usid->value)+11)*sizeof(char));
+      sprintf(logPath,"%s/exec_out_%s",tmpPath->value,usid->value);
+      int ts=stat(logPath, &f_status);
+      if(ts==0) {
+	fcontent=(char*)malloc(sizeof(char)*(f_status.st_size+1));
+	FILE* f=fopen(logPath,"rb");
+	fread(fcontent,f_status.st_size,1,f);
+	int fsize=f_status.st_size;
+	fcontent[fsize]=0;
+	fclose(f);
+	free(logPath);
+	char *token, *saveptr;
+	char *token1, *saveptr1;
+	token = strtok_r (tmpMap->value, ",", &saveptr);
+	token1 = strtok_r (fcontent, "|", &saveptr1);
+	while (token != NULL) {
+	  fprintf(stderr,"%s %d %s \n",__FILE__,__LINE__,token);
+	  fflush(stderr);
+	  fprintf(stderr,"%s %d %s %s \n",__FILE__,__LINE__,token,token1);
+	  fflush(stderr);
+	  if(token1 != NULL){
+	    if(tmpMaps->content==NULL)
+	      tmpMaps->content=createMap(token,token1);
+	    else
+	      addToMap(tmpMaps->content,token,token1);
+	  }
+	  token = strtok_r (NULL, ",", &saveptr);
+	  token1 = strtok_r (NULL, "|", &saveptr1);
+	}
+      }else{
+	free(logPath);
+	setMapInMaps(conf,"lenv","message",_("Unable to access the downloaded execution log file"));
+	return SERVICE_FAILED;
+      }
+    }
+    tmpMap=getMapFromMaps(tmpMaps,"henv","JobId");
+    if(tmpMap!=NULL){
+      char* tmpStr=(char*)malloc((32)*sizeof(char));
+      sprintf(tmpStr,"slurm-%s.out",tmpMap->value);
+      addToMap(tmpMaps->content,"StdErr",tmpStr); 
+      free(tmpStr);
+    }
+    logPath=(char*)malloc((strlen(tmpPath->value)+strlen(jobid->value)+15)*sizeof(char));
+    sprintf(logPath,"%s/exec_status_%s",tmpPath->value,jobid->value);
+    dumpMapsToFile(tmpMaps,logPath,0);
+    char *sname=(char*)malloc((strlen(tmpPath->value)+strlen(jobid->value)+21));
+    sprintf(sname,"%s/.wait_socket_%s.sock",tmpPath->value,jobid->value);
+    if ( (fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
+      perror("socket error");
+      setMapInMaps(conf,"lenv","message",_("Socket error"));
+      return SERVICE_FAILED;
+    }
+    memset(&addr, 0, sizeof(addr));
+    addr.sun_family = AF_UNIX;
+    strncpy(addr.sun_path, sname, sizeof(addr.sun_path)-1);
+    if (connect(fd, (struct sockaddr*)&addr, sizeof(addr)) == -1) {
+      perror("connect error");
+      setMapInMaps(conf,"lenv","message",_("Unable to connect"));
+      return SERVICE_FAILED;
+    }
+    if (write(fd, "3", 1) != rc) {
+      if (rc < 0) {
+	perror("write error");
+	setMapInMaps(conf,"lenv","message",_("Unable to announce the successful execution of the HPC service"));
+	close(fd);
+	return SERVICE_FAILED;
+      }
+    }
+    close(fd);
+    unlink(flenv);
+    free(flenv);
+    setOutputValue(outputs,"Result",(char*)"\"FinalizeHPC run successfully\"",32);
+
+    return SERVICE_SUCCEEDED;
+  }
+  
+}
Index: trunk/zoo-project/zoo-services/utils/hpc/service2.c
===================================================================
--- trunk/zoo-project/zoo-services/utils/hpc/service2.c	(revision 917)
+++ trunk/zoo-project/zoo-services/utils/hpc/service2.c	(revision 917)
@@ -0,0 +1,270 @@
+/**
+ * Author : Gérald FENOY
+ *
+ * Copyright 2017 GeoLabs SARL. All rights reserved.
+ *
+ * This work was supported by public funds received in the framework of GEOSUD,
+ * a project (ANR-10-EQPX-20) of the program "Investissements d'Avenir" managed
+ * by the French National Research Agency
+ *
+ * This work was supported by public funds received in the framework of GEOSUD,
+ * a project (ANR-10-EQPX-20) of the program "Investissements d'Avenir" managed
+ * by the French National Research Agency
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+
+#include "service.h"
+#include "service_internal.h"
+
+#include <libxml/tree.h>
+#include <libxml/parser.h>
+#include <libxml/xpath.h>
+#include <libxml/xpathInternals.h>
+
+#include <libxslt/xslt.h>
+#include <libxslt/xsltInternals.h>
+#include <libxslt/transform.h>
+#include <libxslt/xsltutils.h>
+
+#include <dirent.h>
+#include <string.h>
+#include <cerrno>
+
+extern "C" {
+
+  /** 
+   * Retrieve the error message which occured when trying to remove a file
+   * (return values can be EACCES, EBUSY, EFAULT, EIO, EISDIR, ELOOP, 
+   * ENAMETOOLONG, ENOENT, ENOMEM, ENOTDIR, EPERM, EROFS, UNKNOWN).
+   *
+   * @param errn
+   * @result a string corresponding to the error number 
+   */ 
+  char* fetchErrno(int errn){
+   switch(errn){
+    case EACCES:
+	return "EACCES";
+    case EBUSY:
+	return "EBUSY";
+    case EFAULT:
+	return "EFAULT";
+    case EIO:
+	return "EIO";
+    case EISDIR:
+	return "EISDIR";
+    case ELOOP:
+	return "ELOOP";
+    case ENAMETOOLONG:
+	return "ENAMETOOLONG";
+    case ENOENT:
+	return "ENOENT";
+    case ENOMEM:
+	return "ENOMEM";
+    case ENOTDIR:
+	return "ENOTDIR";
+    case EPERM:
+	return "EPERM";
+    case EROFS:
+	return "EROFS";
+    default:
+	return "UNKNOWN";
+   }
+  }
+
+  /**
+   * Try to delete a cache file.
+   * 
+   * @param storage the full path to store the file
+   * @param filename the filename to store
+   * @param ext the extention of the file
+   * @return 0 in case of success
+   */
+  int tryDeleteCacheFile(const char* storage,const char* filename,const char* ext){
+    char *filename_noext=(char*)malloc((strlen(filename)-3)*sizeof(char));
+    snprintf(filename_noext,strlen(filename)-4,"%s",filename);
+    char* filename_full=(char*)malloc((strlen(filename)+1)*sizeof(char));
+    sprintf(filename_full,"%s.%s",filename_noext,ext);
+    char* fullpath=(char*)malloc((strlen(storage)+strlen(filename_full)+2)*sizeof(char));
+    sprintf(fullpath,"%s/%s",storage,filename_full);
+    if(unlink(fullpath)==0){
+      // TODO store the filename_full in the deletedfiles
+      fprintf(stderr,"#### DeleteData #### %s %d %s has been successfully deleted\n",__FILE__,__LINE__,filename_full);
+    }else{
+      fprintf(stderr,"#### DeleteData #### unable to delete %s \n",fullpath);
+    }
+    free(fullpath);
+    free(filename_full);
+    return 0;
+  }  
+
+  /**
+   * Try to delete a data file.
+   * 
+   * @param storage the full path to store the file
+   * @param filename the filename to store
+   * @return 0 in case of success
+   */
+  int tryDeleteDataFile(const char* storage,const char* filename){
+    char* fullpath=NULL;
+    if(filename!=NULL){
+      fullpath=(char*)malloc((strlen(storage)+strlen(filename)+2)*sizeof(char));
+      sprintf(fullpath,"%s/%s",storage,filename);
+    }
+    else
+      fullpath=zStrdup(storage);
+    if(unlink(fullpath)==0){
+      // TODO store the filename_full in the deletedfiles
+      fprintf(stderr,"#### DeleteData #### %s %d %s has been successfully deleted\n",__FILE__,__LINE__,(filename!=NULL && strlen(filename)>0?filename:fullpath));
+    }else{
+      fprintf(stderr,"#### DeleteData #### unable to delete %s %s \n",fullpath,fetchErrno(errno));
+    }
+    free(fullpath);
+    return 0;
+  }  
+  
+  
+  /**
+   * DeleteData ZOO-Service :
+   * This service is used in the ZOO-Project to delete the data file
+   * associated with input or output.
+   */
+  ZOO_DLL_EXPORT int DeleteData(maps*& conf,maps*& inputs,maps*& outputs){
+    map* dataPath=getMapFromMaps(conf,"main","dataPath");
+    map* tmpPath=getMapFromMaps(conf,"main","tmpPath");
+    map* cacheDir=getMapFromMaps(conf,"main","cacheDir");
+    map* jobid=getMapFromMaps(inputs,"jobid","value");
+    map* filename=getMapFromMaps(inputs,"filename","value");
+    map* ioname=getMapFromMaps(inputs,"ioname","value");
+    char tmp0[4];
+    sprintf(tmp0,"%c%c%c",filename->value[strlen(filename->value)-3],filename->value[strlen(filename->value)-2],filename->value[strlen(filename->value)-1]);
+    char *cfilename=NULL;
+    if(strcasecmp(tmp0,"zca")==0){
+      cfilename=(char*) malloc((strlen(filename->value)+strlen(cacheDir->value)+2)*sizeof(char));
+      sprintf(cfilename,"%s/%s",cacheDir->value,filename->value);
+    }
+    else{
+      cfilename=(char*) malloc((strlen(filename->value)+strlen(tmpPath->value)+2)*sizeof(char));
+      sprintf(cfilename,"%s/%s",tmpPath->value,filename->value);
+    }
+    zooLock* lck=lockFile(conf,cfilename,'w');
+    char** deletedfiles;
+    if(lck!=NULL){
+      if(strcasecmp(tmp0,"zca")==0){
+	// Read the zcp file to verify if it comes from a shared source
+	char *filename_noext=(char*)malloc((strlen(filename->value)-3)*sizeof(char));
+	snprintf(filename_noext,strlen(filename->value)-4,"%s",filename->value);
+	char* filename_full=(char*)malloc((strlen(filename->value)+1)*sizeof(char));
+	sprintf(filename_full,"%s.zcp",filename_noext);
+	char* fullpath=(char*)malloc((strlen(cacheDir->value)+strlen(filename_full)+2)*sizeof(char));
+	sprintf(fullpath,"%s/%s",cacheDir->value,filename_full);
+	FILE* f0=fopen(fullpath,"rb");
+	char *fcontent=NULL;
+	if(f0!=NULL){
+	  long flen;
+	  fseek (f0, 0, SEEK_END);
+	  flen = ftell (f0);
+	  fseek (f0, 0, SEEK_SET);
+	  fcontent = (char *) malloc ((flen + 1) * sizeof (char));
+	  fread(fcontent,flen,1,f0);
+	  fcontent[flen]=0;
+	  fclose(f0);
+	}
+	if(fcontent!=NULL && strcasecmp(fcontent,"SHARED")!=0){
+	  // Delete associated zcm, zcp and maps files
+	  tryDeleteCacheFile(cacheDir->value,filename->value,"zca");
+	  tryDeleteCacheFile(cacheDir->value,filename->value,"zcm");
+	  tryDeleteCacheFile(cacheDir->value,filename->value,"zcp");
+	  tryDeleteCacheFile(tmpPath->value,filename->value,"maps");
+	  // Delete <input>_<sid>.map
+	  char* datafile=(char*)malloc((strlen(jobid->value)+strlen(ioname->value)+19)*sizeof(char));
+	  sprintf(datafile,"%s_%s.map",ioname->value,jobid->value);
+	  tryDeleteDataFile(dataPath->value,datafile);
+	  free(datafile);
+	}else{
+	  setMapInMaps(conf,"lenv","message",_ss("The file you try to delete is a shared ressource and cannot be deleted by nature."));
+	  unlockFile(conf,lck);
+	  return SERVICE_FAILED;
+	}
+	setMapInMaps(outputs,"Result","value",_ss("The input data has been correclty removed"));
+      }else{
+	char tmp1[8];
+	snprintf(tmp1,7,"%s",filename->value);
+	if(strcasecmp(tmp1,"output")==0 || strstr(filename->value,".zca")!=NULL || strcasecmp(tmp1,"input_")==0){
+	  tryDeleteDataFile(tmpPath->value,filename->value);
+          char *tmp=zStrdup(filename->value);
+	  tmp[strlen(tmp)-strlen(strrchr(tmp,'.'))]=0;
+	  char *mapsfile=(char*)malloc((strlen(tmp)+6)*sizeof(char));
+	  sprintf(mapsfile,"%s.maps",tmp);
+          char* mapPath=(char*)malloc((strlen(tmpPath->value)+strlen(mapsfile)+2)*sizeof(char));
+          sprintf(mapPath,"%s/%s",tmpPath->value,mapsfile);
+	  FILE* myMapsfile=fopen(mapPath,"r");
+          if(myMapsfile!=NULL){
+	    char *buffer=(char*)malloc(1024*sizeof(char));
+	    while(fgets(buffer, 1024, myMapsfile) != NULL){
+	      buffer[strlen(buffer)-1]=0;
+	      tryDeleteDataFile(buffer,NULL);
+	    }
+	    free(buffer);
+	    fclose(myMapsfile);
+          }
+          tryDeleteDataFile(mapPath,NULL);
+          free(mapPath);
+          free(mapsfile);
+	  // Delete ZOO_DATA_<output>_<sid>.data and <output>_<sid>.map
+	  char* datafile=(char*)malloc((strlen(jobid->value)+strlen(ioname->value)+19)*sizeof(char));
+	  sprintf(datafile,"ZOO_DATA_%s_%s.data",ioname->value,jobid->value);
+	  tryDeleteDataFile(dataPath->value,datafile);
+	  free(datafile);
+	  datafile=(char*)malloc((strlen(jobid->value)+strlen(ioname->value)+19)*sizeof(char));
+	  sprintf(datafile,"%s_%s.map",ioname->value,jobid->value);
+	  tryDeleteDataFile(dataPath->value,datafile);
+	  free(datafile);
+	  char* webServices[3]={"wms","wfs","wcs"};
+	  int i=0;
+	  // Delete ZOO_DATA_<ws>_link_<sid>.data and <ws>_link_<sid>.map
+	  // with <ws> is the corresponding OGC web service (wms,wfs,wcs)
+	  for(i=0;i<3;i++){
+	    datafile=(char*)malloc((strlen(jobid->value)+24)*sizeof(char));
+	    sprintf(datafile,"ZOO_DATA_%s_link_%s.data",webServices[i],jobid->value);
+	    tryDeleteDataFile(dataPath->value,datafile);
+	    free(datafile);
+	    datafile=(char*)malloc((strlen(jobid->value)+14)*sizeof(char));
+	    sprintf(datafile,"%s_link_%s.map",webServices[i],jobid->value);
+	    tryDeleteDataFile(dataPath->value,datafile);
+	    free(datafile);
+	  }
+	  setMapInMaps(outputs,"Result","value",_ss("The output data has been correclty removed"));
+	}else{
+	  setMapInMaps(conf,"lenv","message",_ss("The file you try to delete is nor an input, nor an output."));
+	  unlockFile(conf,lck);
+	  return SERVICE_FAILED;
+	}
+      }
+      unlockFile(conf,lck);
+    }
+    else{
+      setMapInMaps(conf,"lenv","message",_ss("Failed to acquire lock for deletion, please try again later."));
+      return SERVICE_FAILED;
+    }
+    return SERVICE_SUCCEEDED;
+  }
+
+}
Index: trunk/zoo-project/zoo-services/utils/registry/Makefile
===================================================================
--- trunk/zoo-project/zoo-services/utils/registry/Makefile	(revision 889)
+++ trunk/zoo-project/zoo-services/utils/registry/Makefile	(revision 917)
@@ -1,5 +1,5 @@
 ZRPATH=../../..
 include ${ZRPATH}/zoo-kernel/ZOOMakefile.opts
-CFLAGS=${ZOO_CFLAGS} ${XML2CFLAGS} ${GDAL_CFLAGS} ${PYTHONCFLAGS} -DLINUX_FREE_ISSUE #-DDEBUG
+ZCFLAGS=-I${ZRPATH}/zoo-kernel/ ${CFLAGS} ${ZOO_CFLAGS} ${XML2CFLAGS} ${GDAL_CFLAGS} ${PYTHONCFLAGS} -DLINUX_FREE_ISSUE #-DDEBUG
 
 YAML_FILES=""
@@ -16,5 +16,5 @@
 
 cgi-env/wps_registry.zo: service.c
-	g++ ${CFLAGS} -shared -fpic -o cgi-env/wps_registry.zo ./service.c ${GDAL_LIBS} ${XML2LDFLAGS} ${MACOS_LD_FLAGS} ${ZOO_LDFLAGS} ${MACOS_LD_NET_FLAGS} ${XSLT_LDFLAGS} -lfcgi -L${ZRPATH}/zoo-kernel/ -lzoo_service ${ZRPATH}/zoo-kernel/server_internal.o ${ZRPATH}/zoo-kernel/lex.cr.o ${ZRPATH}/zoo-kernel/lex.sr.o ${ZRPATH}/zoo-kernel/service_conf.tab.o ${ZRPATH}/zoo-kernel/main_conf_read.tab.o ${ZRPATH}/zoo-kernel/response_print.o ${YAML_FILES} ${MS_FILES} ${MS_LDFLAGS} ${YAML_LDFLAGS}
+	g++ ${ZCFLAGS} -shared -fpic -o cgi-env/wps_registry.zo ./service.c ${GDAL_LIBS} ${XML2LDFLAGS} ${MACOS_LD_FLAGS} ${ZOO_LDFLAGS} ${MACOS_LD_NET_FLAGS} ${XSLT_LDFLAGS} -lfcgi -L${ZRPATH}/zoo-kernel/ -lzoo_service ${ZRPATH}/zoo-kernel/server_internal.o ${ZRPATH}/zoo-kernel/lex.cr.o ${ZRPATH}/zoo-kernel/lex.sr.o ${ZRPATH}/zoo-kernel/service_conf.tab.o ${ZRPATH}/zoo-kernel/main_conf_read.tab.o ${ZRPATH}/zoo-kernel/response_print.o ${YAML_FILES} ${MS_FILES} ${MS_LDFLAGS} ${YAML_LDFLAGS}
 
 install:
Index: trunk/zoo-project/zoo-services/utils/registry/service.c
===================================================================
--- trunk/zoo-project/zoo-services/utils/registry/service.c	(revision 889)
+++ trunk/zoo-project/zoo-services/utils/registry/service.c	(revision 917)
@@ -80,5 +80,5 @@
 				    root_nodes[1][1],"2.0.0",1);
       setMapInMaps(conf,"main","rversion","2.0.0");
-      printDescribeProcessForProcess(zooRegistry,conf,n,inherited);
+      printDescribeProcessForProcess(zooRegistry,conf,doc,n,inherited);
       setMapInMaps(conf,"main","rversion","1.0.0");
 
Index: trunk/zoo-project/zoo-services/utils/status/Makefile
===================================================================
--- trunk/zoo-project/zoo-services/utils/status/Makefile	(revision 889)
+++ trunk/zoo-project/zoo-services/utils/status/Makefile	(revision 917)
@@ -1,8 +1,8 @@
 ZRPATH=../../..
 include ${ZRPATH}/zoo-kernel/ZOOMakefile.opts
-CFLAGS=-I${INST_INCLUDE} ${ZOO_CFLAGS} ${XML2CFLAGS} ${GDAL_CFLAGS} ${PYTHONCFLAGS} -DLINUX_FREE_ISSUE #-DDEBUG
+CFLAGS1=${CFLAGS} -I${INST_INCLUDE} ${ZOO_CFLAGS} ${XML2CFLAGS} ${GDAL_CFLAGS} ${PYTHONCFLAGS} -DLINUX_FREE_ISSUE #-DDEBUG
 
 cgi-env/wps_status.zo: service.c
-	g++ ${CFLAGS} -shared -fpic -o cgi-env/wps_status.zo ./service.c ${GDAL_LIBS} ${XML2LDFLAGS} ${MACOS_LD_FLAGS} ${ZOO_LDFLAGS} ${MACOS_LD_NET_FLAGS} ${XSLT_LDFLAGS} ${FCGI_LDFLAGS} -L${ZRPATH}/zoo-kernel/ -lzoo_service
+	g++ ${CFLAGS1} -shared -fpic -o cgi-env/wps_status.zo ./service.c ${GDAL_LIBS} ${XML2LDFLAGS} ${MACOS_LD_FLAGS} ${ZOO_LDFLAGS} ${MACOS_LD_NET_FLAGS} ${XSLT_LDFLAGS} ${FCGI_LDFLAGS} -L${ZRPATH}/zoo-kernel/ -lzoo_service
 
 install:
Index: trunk/zoo-project/zoo-services/utils/status/service.c
===================================================================
--- trunk/zoo-project/zoo-services/utils/status/service.c	(revision 889)
+++ trunk/zoo-project/zoo-services/utils/status/service.c	(revision 917)
@@ -72,4 +72,7 @@
       return SERVICE_FAILED;
     }
+    map* tmpMap1=getMapFromMaps(conf,"lenv","semaphore");
+    if(tmpMap1!=NULL && strcasecmp(tmpMap1->value,"Created")==0)
+      removeShmLock(conf,1);
     sprintf(xslFileName,"%s/updateStatus.xsl",tmpMmap->value);
     xmlSubstituteEntitiesDefault(1);
@@ -85,7 +88,7 @@
        */
       char *tmpStr=_getStatus(conf,tmpMap->value);
-#ifdef DEBUG
+      //#ifdef DEBUG
       fprintf(stderr,"DEBUG: %s \n",tmpStr);
-#endif
+      //#endif
       if(tmpStr!=NULL && strncmp(tmpStr,"-1",2)!=0){
 	char *tmpStr1=strdup(tmpStr);
@@ -140,4 +143,6 @@
       char message[10];
       sprintf(message,"Step %d",i);
+      fprintf (stderr, "RUN IN BACKGROUND MODE %s %d \n",__FILE__,__LINE__);
+      fflush(stderr);
       updateStatus(conf,i,message);
 #ifndef WIN32
