Cloud Service Integration Platform

User Manual and Technical Documentation

Olaf David

Wesley Lloyd

Mazdak Arabi

Ken Rojas

This is a draft document. Service signatures, API details, URL references may change because of design refinements.

Apr 1 2016 (Version 2.1)

Abstract

Cloud infrastructures for modelling activities such as data processing, performing environmental simulations, or conducting model calibrations/optimizations provide a cost effective alternative to traditional high performance computing approaches. Cloud-based modelling examples has emerged into the more formal notion: “Model as a Service” (MaaS). This manual presents the Cloud Services Integration Platform (CSIP) as a software framework offering MaaS. It describes both the CSIP infrastructure and software architecture that manages computational resources for typical modelling tasks, and the use of CSIP's “ModelServices API” for a modelling application.

This document specifies the structure, programming interface, and usage of model and data services as provided by the Cloud Services Integration Platform (CSIP). A client can use those services to obtain data, such as soils, management, and climate, or to execute simulation models by providing a model parameterization and then retrieve the results. This service specification is fully based on RESTful principles using JSON as payload for transferred data. The services also contain support for service registration, lookup, and payload template specification.

TODO:

- Project template download,

- config UI, UI changes, screenshots

- MaaS text + figure,

- Nanoservices references

- compressed input files (gzip) Zipped folders.

- update API chapter

-update config (multicast?)

- public url setting (host,scheme,port)

- update with Array API for parameter

- default config bundling.

- archive, session with MongoDB, JDBC Pool resources,

- Zipped output @Options annotation, new properties,

- Resource inheritance, Repeatable, new jars, beanutiles, logging rewrite, cleanup in classes.


Preface
1. Naming
2. License
3. Resources
4. Acknowledgements
1. Introduction
1. Model-as-a-Service (MaaS)
2. Cloud Services Integration Platform
2. Getting Started
1. Install Docker
2. Create a Workspace
3. Create a Service
4. Build the Service
5. Deploy the Service
6. Query the Service
7. Execute the Service
8. Summary
9. Required Software
3. ModelService - Client RESTful API
1. ModelCatalog Service
2. ModelParameter Service
3. ModelExecution Service
3.1. Service Control Variables (Metainfo)
3.2. Service Execution
3.2.1. Synchronous Execution
3.2.2. Asynchronous Execution
3.3. Attaching Request Input Data
3.4. Download Result Data
3.5. Error Messages
3.6. Ensemble Execution
3.7. Service Testing
4. Invocation Examples
4.1. CURL
4.2. Java
4.2.1. Java HTTP client library
4.2.2. Java RX RS Client Library
4.2.3. Apache HTTPClient library
4.2.4. CSIP HTTPClient
4.3. C#
4.4. VB.Net
4.5. Python
4.6. C/C++
4.7. JavaScript
4.8. Groovy
4.9. Go
4.10. Ruby
4.11. Client - Best Practices
4. ModelServices - Server API
1. Model and Data Service (ModelDataService)
2. Workspace Management
3. Handling Service Input
3.1. JSON Input Data and Parameter
3.2. Reading Metainfo
3.3. File attachments
4. Providing Service Output
4.1. Report Generation
5. Resources
5.1. Architecture Variants
5.2. Automated Execution
6. Client Control
6.1. Service Polling
6.1.1. Example
7. Reporting Progress
8. Error handling and Error Propagation
8.1. Logging
5. CSIP Infrastructure
1. CSIP Configurations
1.1. Configuration properties
1.2. Changing the Configuration
2. Deployments
2.1. Simplest Single Server Deployment
2.2. Single Server Deployment with Archival
2.3. Single Server Deployment with Logging
2.4. Single Server Deployment with Archival and Logging
2.5. Multi-Server Deployment
2.6. Scalable Deployment (Multiple Server)
2.7. Validating the Configuration
2.8. Tips / Best Practices / FAQ
3. ModelServices User Interface
3.1. Session User Interface
3.2. Logging User Interface
3.3. Archive User Interface
A. ModelServices API
1. Executable
1.1. Synopsis
1.2. environment()
1.3. exec()
1.4. getArguments()
1.5. getName()
1.6. redirectError(String)
1.7. redirectOutput(String)
1.8. setArguments(Object...)
2. Model­Data­Service
2.1. Synopsis
2.2. createCallable()
2.3. createReport()
2.4. createResults()
2.5. describeJSON()
2.6. execute(UriInfo, HttpServletRequest, FormDataMultiPart)
2.7. execute(UriInfo, HttpServletRequest, String)
2.8. getBooleanMetainfo(String)
2.9. getBooleanParam(String)
2.10. getBooleanParam(String, boolean)
2.11. getCodebase()
2.12. getDoubleMetainfo(String)
2.13. getDoubleParam(String)
2.14. getDoubleParam(String, double)
2.15. getFileInput(String)
2.16. getFileInputs()
2.17. getFileInputsCount()
2.18. getFirstPoll()
2.19. getIntMetainfo(String)
2.20. getIntParam(String)
2.21. getIntParam(String, int)
2.22. getJSONParam(String)
2.23. getJSONParam(String, JSONObject)
2.24. getLongParam(String)
2.25. getLongParam(String, long)
2.26. getMetainfo()
2.27. getMetainfoCount()
2.28. getMetainfoNames()
2.29. getNextPoll()
2.30. getParam()
2.31. getParamCount()
2.32. getParamDescr(String)
2.33. getParamGeometry(String)
2.34. getParamMap()
2.35. getParamNames()
2.36. getParamUnit(String)
2.37. getRemoteAddr()
2.38. getRequest()
2.39. getRequestContext()
2.40. getRequestHost()
2.41. getRequestURL()
2.42. getResourceExe(String)
2.43. getResourceFile(String)
2.44. getServicePath()
2.45. getStringMetainfo(String)
2.46. getStringParam(String)
2.47. getStringParam(String, String)
2.48. getSUID()
2.49. getWorkspaceDir()
2.50. hasFileInput(String)
2.51. hasMetainfo(String)
2.52. hasParam(String)
2.53. hasWorkspaceDir()
2.54. postprocess()
2.55. postProcess()
2.56. preprocess()
2.57. preProcess()
2.58. process()
2.59. putReport(File...)
2.60. putReport(File)
2.61. putReport(File, String)
2.62. putReport(String, boolean)
2.63. putReport(String, boolean, String)
2.64. putReport(String, boolean, String, String)
2.65. putReport(String, double)
2.66. putReport(String, double, String)
2.67. putReport(String, double, String, String)
2.68. putReport(String, int)
2.69. putReport(String, int, String)
2.70. putReport(String, int, String, String)
2.71. putReport(String, JSONObject)
2.72. putReport(String, JSONObject, String)
2.73. putReport(String, JSONObject, String, String)
2.74. putReport(String, String)
2.75. putReport(String, String, String)
2.76. putReport(String, String, String, String)
2.77. putResult(File...)
2.78. putResult(File)
2.79. putResult(File, String)
2.80. putResult(String, boolean)
2.81. putResult(String, boolean, String)
2.82. putResult(String, boolean, String, String)
2.83. putResult(String, double)
2.84. putResult(String, double, String)
2.85. putResult(String, double, String, String)
2.86. putResult(String, int)
2.87. putResult(String, int, String)
2.88. putResult(String, int, String, String)
2.89. putResult(String, JSONObject)
2.90. putResult(String, JSONObject, String)
2.91. putResult(String, JSONObject, String, String)
2.92. putResult(String, String)
2.93. putResult(String, String, String)
2.94. putResult(String, String, String, String)
2.95. report()
2.96. setMetainfo(JSONObject)
2.97. setParam(JSONArray)
2.98. setParamMap(Map<String, JSONObject>)
2.99. setProgress(int)
2.100. setProgress(String)
2.101. setRequest(JSONObject)
3. Model­Data­Service.­Task
3.1. Synopsis
4. Service­Exception
4.1. Synopsis
4.2. ServiceException(String)
4.3. ServiceException(String, Throwable)
4.4. ServiceException(Throwable)
5. Resource
5.1. Synopsis
5.2. args
5.3. env
5.4. file
5.5. id
5.6. type
5.7. wine
6. Resource­Type
6.1. Synopsis
6.2. ARCHIVE
6.3. CLASSNAME
6.4. EXECUTABLE
6.5. FILE
6.6. JAR
6.7. OMS_DSL
6.8. OUTPUT
6.9. REFERENCE
7. Resources
7.1. Synopsis
7.2. value
B. ModelServices Constant field values
1. csip.*
Bibliography
Index

Preface

1. Naming

Throughout this manual the term 'CSIP' refers to the Cloud Services Integration Platform. This software originated as the product of a collaboration project with the goal to explore the usability of cloud computing and related technologies for service-oriented modeling and simulation. This manual will not reflect on cloud management aspects of CSIP, it only refers to the model services software architecture.

2. License

CSIP is free under the LGPL 2.1 License. The license is bundled with the distribution but can also be obtained from https://www.gnu.org/licenses/old-licenses/lgpl-2.1.html directly.

3. Resources

All source code, examples and this documentation is available at http://alm.engr.colostate.edu/cb/project/csip. This site lists CSIP services available for general consumption and use. Trackers are available at this site to manage bugs and feature requests. This manual among other documents and resources can be downloaded from there.

The CSIP core source code can be checked out using Mercurial VCS.

 $ hg clone http://alm.engr.colostate.edu/cb/hg/csip-core

The repository contains a file Readme.txt describing the structure and the process of building your custom services based on examples. This project site allows also the creation of CSIP repositories once you become a member as a developer.

4. Acknowledgements

CSIP research and development is being funded under a cooperative agreement 68-7482-13-518 between the USDA-Natural Resources Conservation Service and the Department of Civil and Environmental Engineering at Colorado State University.

Chapter 1. Introduction

The use of cloud computing for scientific computing and environmental modeling has gained substantial traction in recent years [Jha2011]. A cloud is a large pool of available and easily accessible virtual resources such as hardware, platforms, and software services. Such resources can be allocated and disposed in an ad-hoc manner. The dynamic configurability of cloud resources to various requirements makes it attractive for scientists, research groups, organizations, and agencies to explore their potential for research projects and operational use.

Appealing cloud features include: (1) the absence of in-house maintenance and administration of such resources, (2) the availability of a range of competing vendors offering different pricing models, (3) the flexibility in adjusting applications or operating systems rapidly on a large scale, (4) secure access and data protection, (5) governing the physical location of cloud-managed resources, and (6) guaranteed availability had to be addressed by commercial cloud vendors to make it a viable option for operational use within the modeling community and not just academia.

The Cloud Services Integration Platform (CSIP) project was established at Colorado State University (CSU) in collaboration with the USDA Natural Resources Conservation Service and Agricultural Research Service to explore the prospect of service oriented cloud computing for MaaS and related data management. As a result of this research, CSIP was developed as a scalable, modular, cost effective, and open deployment platform for simulation models while leveraging new and legacy research simulation models as cloud based web-services.

1. Model-as-a-Service (MaaS)

A Model as a Service (MaaS) [Zou2012] provides the capability to execute simulation models on demand as webservices. MaaS solely focuses on the application aspect of a model against data.

Model-as-a-Service has emerged as “a concept of being able to invoke re-usable, fine-grained software components across a network” [Roman2009], [Argent2004]. MaaS enables model service providers to lower the burden for model users by supporting autonomic model parameterization and in the service within a scalable execution environment. The MaaS concept has evolved as a merge of the Model Web and Software as a Service (SaaS), SaaS is defined as a model of software deployment whereby a provider licenses an application to customers for use as a service on demand. The Model Web is defined as an approach to manage models on the Web ([Roman2009]).

MaaS may harness the HTTP protocol as the interface to enable client/server communication. Data is exchanged as structured text, e.g. XML or JSON- JavaScript Object Notation, in a specified syntax. Data may also be passed to the service using file attachments in the model’s native format.

There are two main usage patterns: (i) The model is pre-deployed, has a well-known service endpoint, and may be supported by supplemental data services. This deployment is quite common for operational models used in a production environment; (ii) the model can be dynamically deployed from the client before execution. Model service development for research purposes requires this behavior. Both approaches address different workflows, need for availability and security. The model execution method may be specified in the service.

2. Cloud Services Integration Platform

The Cloud Services Integration Platform (CSIP) provides a simple and open framework to implement MaaS services. CSIP provides a software infrastructure for the development and deployment of modeling and data services [David2014].

CSIP is based on RESTful web services. REST stands for Representational State Transfer. It is an architectural approach enabling software systems to be built in where clients send requests to service end points [Fielding2002]. REST is a widely used method to implement client/server webservices. REST allows building software applications in which clients can make requests of services that are simple to use, easy to scale, and highly inter operable. REST requires an HTTP library to be available for most operations. REST relates resources to uniform resource identifier (URIs) and the uniform interface. Different URIs support accessing different resources similar to typing URLs in browser to access different website.

The CSIP REST-based Modeling and Data Services framework is an open source, production quality framework for developing RESTful Services in Java that is built on top of JAX-RS APIs (JSR 311 & JSR 339 Reference Implementation) as provided by J2EE 6 and the OMS3 modeling framework API [David2002]. CSIP provides it’s own API that extends the JAX-RS toolkit with additional features and utilities tailored for simulation models and data sources. CSIP also exposes various methods so that model developers may extend it to best suit their needs. Goals of the CSIP project can be summarized as follows:

  • Easy implementation of REST-based modelling and data service back-ends for rapid development of modeling services.

  • Standardized HTTP/JSON based protocol for client/server communication to support complex, large data structures as input and output by simulation models .

  • Support for short/long running models with synchronous and asynchronous service execution with logging and archival of model input/output data to account for traceability and provenance.

  • Ensemble execution of models and data services to speedup execution of models for parameter calibration and model optimization.

  • High scalability and flexibility of CSIP deployments that can adjust to various infrastructure settings. The CSIP environment can be deployed on a single computer or a cluster of hundreds or thousands of machines.

This manual is organized as follows. Chapter 3, ModelService - Client RESTful API introduces the use of CSIP ModelServices from a client perspective. The JSON protocol for model and data service interaction is introduced and examples are provided. Different usage patterns for model service clients are explained, examples are given in different programming languages and environments. Chapter 4, ModelServices - Server API discusses the development implementation of model and data services from a server perspective. The efficient implementation of services using native bundling of modeling resources, scalability aspects, and others is introduced. Chapter 5, CSIP Infrastructure introduces various approaches for implementing, configuring, and deploying a scalable CSIP architecture. Chapter 4 concludes with a detailed description of the server side API for CSIP.

Chapter 2. Getting Started

In this chapter we will develop, deploy, and exercise a simple CSIP temperature conversion service. The service will receive a value in Celsius and will provide it in Fahrenheit, a very simple operation. We will go through the steps from creating the source, compiling the service package, deploying it and executing the service with example data.

To simplify this process, Docker engine is used to develop, deploy, and execute a CSIP service in this chapter. Docker (https://docker.com) is a lightweight, container-based virtualization environment that is available for all operating systems. CSIP Docker images are stored on DockerHub (https://hub.docker.com). Instead of installing and configuring several software packages to compile and build the service package, we use a Docker image that is already setup and ready to be used.

The following sections in this chapter will use the bash command line syntax (Linux, OS X, Windows-Cygwin) to walk you through the process. You should be able to copy and paste the commands (without the '$') and reproduce the development workflow. Follow the steps below to develop the example CSIP service with minimal effort.

First, let's install Docker.

1. Install Docker

The Docker engine is supported on Linux, Cloud, Windows, and OS X. Install Docker according to the installations instructions found on: https://docs.docker.com/engine/installation . On Linux, all major distributions should have Docker in their repositories. Once installed you should be able to execute the docker command.

 $ docker -v                                                                    
 Docker version 1.10.3, build 20f81dd

2. Create a Workspace

First, we need a workspace that stores the source files and later the compiled packages. Create the workspace work/java in your home folder.

 $ mkdir -p $HOME/work/java/m/conv

Note: The '-p' option creates all sub-folders if not present.

We also created the folder m/conv, a Java package folder within the source structure.

3. Create a Service

The source code of the temperature conversion service is shown below. It will be stored as V1_0.java in the m/conv folder in java.

 $ cat > $HOME/work/java/m/conv/V1_0.java << END
 package m.conv;
 import javax.ws.rs.Path;
 import oms3.annotations.*;
 import csip.annotations.*;

 @Name("Temperature conversion.")
 @Path("m/conv/1.0")
 @Resource(type = ResourceType.OMS_COMP)
 public class V1_0 extends csip.ModelDataService {

     @Description("Temperature in C")
     @Unit("C")
     @In public double temp_c = 45.2;

     @Description("Temperature in F")
     @Unit("F")
     @Out public double temp_f;
     
     @Execute public void run() {
         temp_f = temp_c * 9 / 5 + 32;
     }
 }
END

Note: This cat command copies all content between the two END symbols into the file.

The service is using the JAX-RS, CSIP, and OMS3 API to mostly describe the service resources and elements with annotations and implement the conversion code. The @Path annotation (JAX-RS) specifies the service endpoint. The @Resource annotation (CSIP) indicates that this service is implemented as an OMS3 type component. This manual describes later also other @ResourceType definitions for external native executables, database connections, static data, archives, and others which are common in environmental data and model services. Using a OMS3 component ResourceType the most efficient approach for this simple example.

The service must subclass ModelDataService (CSIP) from the csip package. The fields are representing the input and output data, annotated with @In and @Out according to the OMS3 specification. The temp_c input does have a default value of 45.2, which is arbitrary and will be used to generate a service request template in addition to the field annotations. Finally, the OMS3 annotated run() method implements the logic, a simple temperature conversion, transforming temp_c from Celsius to temp_f in Fahrenheit.

4. Build the Service

DockerHub stores the image olafdavid/csip_dev (https://hub.docker.com/r/olafdavid/csip_dev) to build a CSIP service. It bundles all required software such as the correct JDK 8, Tomcat 8, Ant, JAX-RS, and the CSIP core libraries in order to compile and build a deployable service package, a *.war file. This Docker image lets you create a deployable CSIP service from the source above in one single step.

The docker command below runs the docker image olafdavid/csip_dev. If invoked for the first time, it will download the image from DockerHub and will then start the container. It compiles the sources found in $HOME/work/java and builds the war file in $HOME/work/dist. No other setup is needed, quite simple.

 $ sudo docker run --rm -it -v $HOME/work:/work olafdavid/csip_dev

Note: The option '-v $HOME/work:/work' makes the previously created local workspace available to the container. The '--rm' option will terminate the container at the end of the build.

Now, we should have our service package available for deployment.

 $ ls $HOME/work/dist 
 csip.war

The default package name is 'csip.war', which can be renamed to something more meaningful if needed.

5. Deploy the Service

The created service package can now be deployed to an application server. Of course, we are using Docker again. This time it is a different, vanilla Tomcat 8 image. The tomcat:8-jre8 image on DockerHub is sufficient for our job[1]. The command below starts a container of this image and will download it first if needed.

 $ sudo docker run -d --name csip_rt -p 8080:8080 tomcat:8-jre8

Note: The container will run as a daemon through the '-d' option. The docker command will return once the container is started. The container is named 'csip_rt' since we need to further interact with it using other commands. Having a name makes it easier. Its internal tomcat port 8080 is mapped to the host's port 8080 with the '-p 8080:8080' option so we can access the service from the host.

Next, we need to deploy our war file to the running container. Docker provides a copy (cp) command that allows to transfer files from the host to the container.

 $ sudo docker cp $HOME/work/dist/csip.war csip_rt:/usr/local/tomcat/webapps

The csip.war file is copied from the workspace dist folder to the csip-rt container's webapps folder. Tomcat will pickup that change and automatically loads and deploys the service.

6. Query the Service

Let's check if the csip.war file with our service is correctly deployed. CSIP offers an internal registry that lists all provided services within a given context. The listing is provided as a JSON array.

The curl command is used to issue a HTTP/GET to fetch the service registry. The URL is constructed as localhost, the exposed port 8080, and the name of the service package, csip: http://localhost:8080/csip.

 $ curl http://localhost:8080/csip
 [{
   "name": "Temperature conversion.",
   "description": "Temperature conversion.",
   "url": "http://localhost:8080/csip/m/conv/1.0"
 }]

Our temperature conversion service descriptor is returned, the only one in this package. Name and description are obtained "on-the-fly" from CSIP annotations in the service, the service URL is provided, too. If the package contains more than one service endpoint, they would all be listed in this JSON array.

Now we like to know how to call the conversion service. The service parameter and input signature can be queried by invoking a HTTP/GET against the service endpoint:

 $ curl http://localhost:8080/csip/m/conv/1.0
 {
   "metainfo": {},
   "parameter": [{
     "name": "temp_c",
     "value": "45.2",
     "unit": "C",
     "description": "Temperature in C"
   }]
 }

This call returns a JSON template that shows a valid service request for our conversion service. This is where service source annotations come to play. CSIP and OMS3 introspect the service annotations and construct an example JSON input payload. You recognize the mapping between the JSON elements and the annotations in the service source. CSIP services are self-describing. The Web Processing Services multi-level approach of cataloging services and service signature exploration is also used in CSIP as seen above. Those steps are optional but help to check for service availability.

Now we are ready get to the third level, finally executing the service.

7. Execute the Service

We can simply store the request template by redirecting the curl output of the previous command in a file 'req.json'.

 $ curl -s http://localhost:8080/csip/m/conv/1.0 >req.json

Note: The '-s' option puts curl into silent mode.

Since we have captured a valid request, we can just change the temperature input value in req.json to '5.123'.

 $ sed -i 's/45.2/5.123/' req.json

Note: The '-i' option will replace the numbers in-place. You can use any other text editor to achieve the same.

The stream editor allows this with a simple search and replace command.

A CSIP service will always be invoked with a HTTP/POST request, where the request JSON is the HTTP body. It will execute the service on the server (localhost) and return the result as JSON payload. The curl POST command below passes the content of the req.json file to the service URL as 'application/json'. The response is shown below.

 $ curl -X POST -H "content-type:application/json" \
       -d @req.json http://localhost:8080/csip/m/conv/1.0 
 {
  "metainfo": {
    "status": "Finished",
    "suid": "63eff3f9-ebeb-11e5-bb63-658e82f5a7a4",
    "tstamp": "2016-03-16 20:53:13",
    "service_url": "http://localhost:8080/csip-example/m/conv/1.0",
    "request_ip": "127.0.0.1",
    "csip.version": "$version: 2.1.1 a0d47e2e9e7d 2016-03-16 $",
    "cpu_time": 12,
    "expiration_date": "2016-03-16 20:53:33"
  },
 "parameter": [{
    "name": "temp_c",
    "value": "5.123",
    "unit": "C",
    "description": "Temperature in C"
  }],
  "result": [{
    "name": "temp_f",
    "value": "41.2214",
    "unit": "F",
    "description": "Temperature in F"
  }]
 }

Since this is all RESTful, the response JSON contains the input parameter as well as the result, the converted temperature. CSIP also used the annotations of the the temp_f field in the source to provide meaningful result info. The response contains also metainfo about the service with status information about the execution. All those JSON elements are further explained in this manual.

A client may now parse this JSON response and extract the result value for temp_f, the number 41.2214. This manual also shows this in various languages and platforms. In this chapter, we are happy with this curl output.

Once we are done with testing, the service can be shut down.

 $ sudo docker stop csip_rt

This will stop the running container and the deployed service with it. The container still exists and can be restarted later containing the conversion service:

 $ sudo docker restart csip_rt

However, it can be fully removed from the system by executing the docker rm command.

 $ sudo docker rm csip_rt

8. Summary

This brief tutorial exercised the development, deployment and use of a simple CSIP service. Docker helped making this a painless experience, mostly with respect to the build process. For serious CSIP development, one might want to setup your own software stack on a development machine and download and install the required software.

Temperature conversion is a simple one-line equation. However, this example shows the combined elegance of annotations in JAX-RS, CSIP, and OMS3 to easily put together a modeling service. CSIP is designed from the ground up to serve complex models in a scalable setup. It was tested on hundreds of service nodes. It takes into account failover and supports responsiveness of applications by providing asynchronous access to services of long running models.

CSIP is currently being used to serve (legacy) models for erosion, water quantity, water quality, rangeland hydrology, curve number hydrology, water supply forecasting, watershed delineation, detrended kriging, natural resource analysis and assessment, and more . CSIP services are also providing data for soils, climate, and agricultural land management information, etc. A comprehensive listing of available CSIP services can be found under https://alm.engr.colostate.edu/project/csip.

9. Required Software

Alternatively, you can install the required software on your development machine. Linux, Mac, or Windows machines can be used for CSIP service development. Install for your preferred OS using either the package manager, or use direct downloads:

  • JDK 1.8+ (Java Development Kit) (http://www.oracle.com/technetwork/java/javase/downloads/index.html)

    No earlier version will work, since 1.8 language features are used in csip-core.

  • Netbeans 8.1 Integrated Development Environment (http://netbeans.org/downloads)

    Sources are available in the NB project structure. The IDE is recommended although building from command line is possible, too. If using/downloading Netbeans, it is recommended to use the complete package that bundles Tomcat 8.x. Install Netbeans with tomcat as the application server, no external Tomcat installation would be needed in this case.

  • Tomcat 8.+ Application Server (http://tomcat.apache.org)

    Any Version 8.x of tomcat will be sufficient. (When installing Netbeans 8.1, this installation step will be not needed)

  • Ant 1.9+ Build tool

    Ant is a build management tool. (When installing Netbeans 8.1, this installation step will be not needed)



[1] Using different images for development and deployment makes good use of the 'separation of concerns' principle and follows best practices for isolating aspects. Development environments always differ from deployment infrastructures. Other tools such as Fig or Ansible may be used later for real world deployment.

Chapter 3. ModelService - Client RESTful API

The ModelServices REST web service resembles the schema of Web Processing Services (WPS) developed by the OpenGIS Consortium [OGC2007]. However, CSIP simplifies data definitions, data descriptions, and meta-data to allow easy use of the offered web services. The CSIP webservice interface defines three operations that can be requested by a client and performed by a CSIP implementation.

  1. Provide a list of available model and data services. This operation allows a client to request and receive back service meta-data describing the abilities of the specific implementation. Metadata includes the names and general descriptions of each of the processes offered by a CSIP instance. This operation also supports negotiation of the specification version being used for client-server interactions.

  2. Describe a specific operation in detail. This operation allows a client to request and receive back detailed metadata about specific model/data services including inputs required, their allowable formats, and the produced outputs.

  3. Execute the model or data service. This operation allows a client to run a specified process implemented by CSIP, using provided input parameter values and returning the outputs produced. Execution meta-data is returned to provide delayed retrieval of model results, if the model executes over a long period.

This section specifies the structure of the ModelServices, the (i) ModelCatalog service, the (ii) ModelParameter service, and (iii) ModelExecution service. The Figure below shows the purpose of the service calls in sequence.

Figure 3.1. ModelServices Exploration and Invocation Sequence

ModelServices Exploration and Invocation Sequence


Essential for application development is the knowledge of the ModelExecution service. A client application invokes ModelExecution services. The ModelCalalog and ModelParameter Service are used to verify service availability and input parameter requirements. They support exploration of services and service signatures "on-the-fly", the first two steps in the diagram (GET/GET). Given this information a client request can easily be crafted and submitted for execution.

1. ModelCatalog Service

The ModelCatalog service supports entry level exploration of available model services. Service descriptions are listed as an array of JSON objects with sufficient metadata to call an individual service.

JSON (JavaScript Object Notation) is a web focused data format. It is based on a subset of the JavaScript Programming Language, Standard ECMA-262 3rd Edition - December 1999. JSON is a text format that is completely language independent but uses conventions familiar to programmers of the C-family of languages, including C, C++, C#, Java, JavaScript, Perl, Python, and many others. These properties make JSON an ideal data-interchange format.

JSON is built on two structures:

  • A collection of name/value pairs. In various languages, this is realized as an object, record, structure, dictionary, hash table, keyed list, or associative array.

  • An ordered list of values. In most languages, this is realized as an array, vector, list, or sequence.

JSON format is used by the ModelSevices architecture for data exchange. Model parameter, execution results, meta-information, are all passed as JSON Objects from the client to the web-service. JSON provides support for catalog listing of models, exploration of model capabilities, and execution control.

Example request and response sequences are shown below. The catalog of services is requested by calling a http GET operation against a base URL.

Example 3.1. ModelCatalog Response Format

{ 
  "service-version": 
           <model services implementation version>,
  "services": [
    {
        "name": <model1 name>,
        "version": <model1 version>,
        "description": <model1 description>,
        "doc-ref": <model1 doc url>,
        "path": <model1 path>
    },
    {
        "name": <model2 name>,
        "version": <model2 version>,
        "description": <model2 description>,
        "doc-ref": <model2 doc url>,
        "path": <model2 path>
    },
    {
       ...
    }
  ]
}

Response elements:

services-version (optional)

ModelServices specification version.

services

Array of all model services available at this server. At least one service should be listed.

name

The name of a model service, usually a single word.

version (optional)

The version of this model service.

description (optional)

A brief, one-line description of the model service.

doc-ref (optional)

A reference to further documentation of the web service

path

The path for ModelParameter/ModelExecution Services. The path can be relative to the base URL or a full URL


An example request for a model catalog and its response is shown in the examples below.

Example 3.2. Example ModelCatalog Request

GET /csip-erosion HTTP/1.1
Host: localhost:8080
Accept: application/json

Example 3.3. Example ModelCatalog Response

"services" : [
  {
    "name": "Rusle2",
    "version": "1.1",
    "description": "Revised Universal Soil Loss Equation Rill and Sheet Erosion",
    "path": "http://localhost/csip-erosion/m/rusle2/1.1"
  },
  {
    "name": "EFH2",
    "version": "1.1",
    "description": "Storm runoff model (Engineering Field Handbook.)",
    "path": "http://localhost/csip-erosion/m/efh2/1.1"
  }
  ... 
]

The paths in this example are relative to the base URL used to obtain that catalog.


2. ModelParameter Service

The ModelParameter service provides detailed execution information for a specific ModelService. Input parameters are described including the name, default value, and physical unit. The generated ‘parameter’ JSON object can be used as a template for a client's ExecutionService call. Default parameter values are expected to produce valid ModelExecution results.

The ModelParameter Request is performed as an HTTP GET with the <path> and <version> obtained from the ModelCatalog result.

Example 3.4. ModelParameter Response Format

{
    "parameter": [
        {
            "name": "<parameter name>",
            "value": "<default value>",
            "unit": "<physical unit>",
            "min": "<minimum value>",
            "max": "<maximum value>",
            "description": "<parameter description>"
        },
        {
            "name": "<parameter name>",
            "value": "<default value>",
            "unit": "<physical unit>",
        },
        ..
    ],
    "metainfo": { }
}

Response elements:

name

parameter name.

description (optional)

brief parameter description.

value

default value

unit

the physical unit of the parameter value.

min (optional)

the minimum value.

max (optional)

the maximum value.


Example 3.5. Example ModelParameter Request

GET /csip-hydrotools/m/efh2/1.1 HTTP/1.1
Host: localhost:8080
Accept: application/json


Calling a ModelParameter request requires a URL that is being constructed from the ModelCatalog information. The host name of that URL is the base URL of the ModelCatalog call if the path catalog entry is relative. Note that the specific service version as provided in the catalog must be appended to the path, hence: GET /csip/m/efh2/1.1

Example 3.6. Example ModelParameter response for EFH2

{
    "parameter": [
        {
            "name": "precip",
            "value": 14,
            "unit": "inch",
            "min": 0,
            "max": 100
        },
        {
            "name": "runoffcurvenumber",
            "value": 90,
            "min": 0,
            "max": 100
        },
        {
            "name": "stormtype",
            "value": "I"
        },
        {
            "name": "watershedlength",
            "value": 1500,
            "unit": "ft",
            "min": 0,
            "max": 100000000
        },
        {
            "name": "watershedslope",
            "value": 0.5,
            "unit": "%",
            "min": 0,
            "max": 100
        }
    ],
    "metainfo": {}
}


3. ModelExecution Service

A ModelExecution Service runs the simulation model. It expects model parameters as input in a JSON object and optional metadata controlling the model execution. This service call provides the model output as a result JSON object.

Figure 3.2. Execution phases

Execution phases


The Figure above shows execution phases common for all model services. There are two main groups with respect to the actual model run and the management of model results. Since a model service can be submitted in two modes "sync" and "async" there are two variants for managing those phases (Further details below). A client sends a ModelExecution request to initiate a model run. After initialization the service enters a "Running" state. Model execution can successfully complete ("Finished"), it can fail ("Failed"), or be canceled by user request ("Cancelled"). Additional phases relate to output data management. Model output data can be kept available for retrieval until it expires ("Expired"). The time to keep output data available can be controlled via the request metainfo entry "keep_results". In addition, there can also be a meta info entry to decide what will happen next, deleting the output data "Delete" or archive it for long term storage "Archive"

Each ModelExecution request payload contains two sections, as shown below.

Example 3.7. ModelExecution Request

{ 
  "metainfo" : { 1  
   },
  "parameter" : [ 2
   ]
}


1

metainfo (optional), provides metadata to the service to control execution, and returned by the service to describe execution status, statistics, and other information.

2

parameter, provides input data for the model as an array of singe parameter JSON objects.

Each ModelExecution response payload contains three sections, as shown below.

Example 3.8. ModelExecution Response

{ 
  "metainfo" : {        
   },
  "parameter" : [
   ],
  "result" : [     1
   ]
}


1

result data after model execution as an array of JSON data objects

The metainfo and parameter entries are taken from the request, a basic requirement for RESTful service behavior. The metainfo section will be annotated with additional runtime information.

Example 3.9. ModelExecution request example

{
    "metainfo": {
          "mode":"sync",
          "keep_results: "200000"
    },
    "parameter": [
        {
            "name": "precip",
            "value": 14,
            "unit": "in"
        },
        {
            "name": "runoffcurvenumber",
            "value": 90
        },
        {
            "name": "stormtype",
            "value": "I"
        },
        {
            "name": "watershedlength",
            "value": 1500,
            "unit": "ft"
        },
        {
            "name": "watershedslope",
            "value": 0.5,
            "unit": "%"
        }
    ]
}


The example above shows a request JSON for calling the model service (EFH2).

Example 3.10. ModelExecution invocation

POST /csip-hydrotools/m/efh2/1.1 HTTP/1.1
Host: locahost:8080
Accept: application/json


Example 3.11. ModelExecution response example

{
  "metainfo": {}    
  "parameter": [
        {
            "name": "precip",
            "value": 14,
            "unit": "inch"
        },
        {
            "name": "runoffcurvenumber",
            "value": 90
        },
        {
            "name": "stormtype",
            "value": "I"
        },
        {
            "name": "watershedlength",
            "value": 1500,
            "unit": "ft"
        },
        {
            "name": "watershedslope",
            "value": 0.5,
            "unit": "%"
        }
    ],
   
}


3.1. Service Control Variables (Metainfo)

The metainfo JSON object contains variables that control model execution or provide feedback from the execution.

Figure 3.3. Variables

Variables


The result data (output JSON and output files) will be kept for a period of time after the model run successfully finished. If the model run failed or was cancelled no output will be stored. The time to keep results can be specified in the request using the "keep-results" entry within the "metadata" element.

In asynchronous execution mode, the returned metadata property "polling_interval" provides guidance for when the client should poll again for a status update. This value is model specific. Expect higher values for long running models and smaller values for models that run only for a short period. A client should not poll at intervals that are smaller than this value. Example: If a model takes on average 1 minute to finish, there is no need for the client to poll every 100 ms for a status update. The "polling_interval" in such case may be 5000 ms (5 seconds). There is no advantage for a client to use a shorter polling interval. The polling interval is provided by CSIP based on the average model runtime.

Table 3.1. Metainfo Elements

KeyDescriptionDefaultProvided ByExample
modeExecution mode of the service, "sync" or "async"syncrequest"mode":"async"
keep_resultsNumber of milliseconds to keep results after model finishes execution300000 ms (5 minutes)request"keep_results": 600000
timezonetimezoneUTCrequest"timezone": "America/Denver"
statusStatus of the model execution: "Submitted" | "Finished" | "Canceled" | "Failed" | "Running" | "Unknown"-response"status": "Finished"
cpu_timeTime in ms for service execution-response"cpu_time": "12324"
start_dateTime stamp for service execution-response"start_date": "2012-03-21T15:23:42-0700"
expiration_dateDate when the output date will expire.-response"expiration_date" : "2012-03-21T15:29:42-0700"
next_pollRecommended number of milliseconds between two client polls.-response"next_poll":2000
first_pollRecommended time in ms to wait before the first poll-response"first_poll":2000
suidSimulation unique identifier-response"suid": "8553567a-ee1f-4270-81fb-ec9e9a5676a6"

Notes:

  • All Dates are provided in ISO-8601 date format with timezone field (e.g. '2012-03-21T15:23:42-0700'). If a request provides timezone information all dates will be mapped to this timezone. If not, dates are UTC.

  • Time parameters are always described using milliseconds, for both, request and response metainfo values.

  • Suid's are Version 1 UUID's (see RFC 4122: A Universally Unique IDentifier (UUID) URN Namespace). Thus, the suid creation time can be retrieved using the suid. Suid stands for "simulation unique identifier".

3.2. Service Execution

A synchronous CSIP request returns when the service run finishes, thus blocking the calling client during service execution. CSIP services default to synchronous execution. Conversely asynchronous CSIP requests initiate a model/data service and return immediately to the client. Subsequent service calls must be made to query the service status to determine if execution is complete. Model requests service can be processed both ways, synchronously and asynchronously. The metainfo key "mode" controls the execution mode when submitting the initial request.

The example below demonstrates asynchronous service execution.

Example 3.12. ModelExecution response example

{
    "metainfo": {
            "mode": "async",
             ...
     }
   …
}


3.2.1. Synchronous Execution

The figure below shows the client calling sequence for synchronous execution. The server responds with a response JSON object which includes the client request input parameterization regardless if the model finished successfully or not. During execution the client thread is blocked. The client must account for issues like "call threading" to support a responsive user interface.

Figure 3.4. Synchronous Service Phases

Synchronous Service Phases


After service execution completes the output data and optional report output data can be fetched at anytime before expiration from the session backend datastore.

3.2.2. Asynchronous Execution

While synchronous execution may be acceptable for short running CSIP services (execution time < 10 sec) it is unpractical for long running requests. Such services may execute for minutes, hours, or even days. The figure below shows the principal flow of calls for such asynchronous execution. If mode is set to "async", the initial service call (POST) submits the JSON request for execution and returns immediately.

Figure 3.5. Asynchronous Service Phases

Asynchronous Service Phases


The response metainfo element contains the suid, a unique key, that uniquely identifies the service request. The service status indicates its state of execution. In addition, the metainfo contains "first_poll" and "next_poll" properties. The client should wait "first_poll" milliseconds before first querying for a service result.

Example 3.13. Result for submitted model execution

{
  "metainfo": {
    "status": "Submitted",
    "suid": "182b8505-7534-11e1-b93f-1d1c56c85325",
    "tstamp": "2012-03-23T22:04:00+0000",
    "next_poll": "2000",
    "first_poll": "25000",
  },
  "parameter": [
..
  ]
}


A REST query is being executed using the suid. The call shown below is constructed using the '/csip/q' path and the appended suid.

Example 3.14. Async Query

GET /csip/q/182b8505-7534-11e1-b93f-1d1c56c85325 HTTP/1.1
Host: csip.engr.colostate.edu:8083
Accept: application/json


The query result shows that the model is still running, and has not finished. Subsequent queries for the service status as in the example should be done after "polling_interval" milliseconds.

Example 3.15. Query Result

{
  "metainfo": {
    "status": "Running",
    "suid": "182b8505-7534-11e1-b93f-1d1c56c85325",
    "tstamp": "2012-03-23T22:04:00+0000",
    "polling_interval": "2000",
    "first_poll": "25000",
  },
  "parameter": [
..
  ]
}


Upon completion the service status indicates Finished and the service output is provided in the result JSON section as fetched from CSIP. The suid must be retained by the client during service execution as it serves as a token to query the service status and its results.

3.3. Attaching Request Input Data

CSIP services may require input files to execute. Not all service parameters can and should be mapped into JSON format. A service wrapping a legacy scientific model might consume input files directly with no modifications. In some cases, service input requirements may be so extensive their representation in JSON is impractical to implement.

CSIP services can easily consume client requests with files attached. Files are attached to CSIP HTTP/POST requests as multipart/form-data. See Example 3.16, “Input with multipart/form-data”.

Example 3.16. Input with multipart/form-data

POST /m/swat/1.0 HTTP/1.0
Host: localhost
Content-type: multipart/form-data, boundary=AaB03x
Content-Length: $requestlen

--AaB03x
content-disposition: form-data; name="param"; filename="req.json"  1
Content-Type: application/octet-stream

$param
--AaB03x
content-disposition: form-data; name="file1"; filename="hru.dat"   2
Content-Type: application/octed-stream
$file1
--AaB03x
content-disposition: form-data; name="file2"; filename="input.std" 3
Content-Type: application/octed-stream

$binarydata
--AaB03x--

1

The json request file that needs to be attached as "param". The name "param" is required.

2

The first file attachment, "hru.dat". The value of the name parameter is ignored.

3

The second file attachment, "input.std". The value of the name parameter is ignored.

Input file naming is flexible, except for the JSON parameter file. While the JSON file name can vary, the multi-part request parameter must be "param". The example below shows a request for Example 3.16, “Input with multipart/form-data” using the command line command CURL.


$ curl -X POST -H "Accept:application/json" \
        -F param=@/tmp/req.json \
        -F file1=@/tmp/hru.dat \
        -F file2=@/tmp/input.std \ 
        ...
          "http://localhost:8080/csip-swat/m/swat/1.0" 

More examples on how to attach files to the HTTP POST request using different clients and languages are shown in Section 4, “Invocation Examples”.

3.4. Download Result Data

Legacy scientific models typically produce data output files. CSIP streamlines providing model output as key value pairs in the results JSON array to the client. Such output can be obtained from the model directly, or parsed from model output files. In some cases it is beneficial for the client to access the native model output files. For this use case, CSIP provides a query service to obtain the files. An example is shown below.

A model finishes and provides in the result JSON array a list of file pointers. A client can fetch the files as referenced by the provided URLs. The file size is provided in bytes.

Example 3.17. Model response with data download

{
  "metainfo": {
    "status": "Finished",
    "suid": "182b8505-7534-11e1-b93f-1d1c56c85325",
    "tstamp": "2012-03-23T22:04:00+0000",
    "polling_interval": "2000",
    "first_poll": "25000",
    "cputime": "28155",
    "expiration_date": "2012-03-23T22:09:28+0000"
  },
  "parameter": [
    {
      "name": "wepsrun",
      "value": "weps.run"
    },
    {
      "name": "climate",
      "value": "cli_gen.cli"
    },
    {
      "name": "wind",
      "value": "win_gen.win"
    },
    {
      "name": "management",
      "value": "S Wheat-Beet-SB CMZ 1.man"
    },
    {
      "name": "soils",
      "value": "Heldt_48_90_CL.ifc"
    }
  ],
  "result": [
    {
      "name": "sci",
      "value": "http://localhost:8080/csip-erosion/q/182b8505-7534-11e1-b93f-1d1c56c85325/sci_energy.out"
      "size": "21729"
    },
    {
      "name": "stir",
      "value": "http://localhost:8080/csip-erosion/q/182b8505-7534-11e1-b93f-1d1c56c85325/stir_energy.out"
      "size": "91638"
    },
  ]

Clients must fetch temporarily stored server-side data before it expires. The expiration date is specified in the metainfo. In addition, the suid is used to identify the files of specific model runs, suid 182b8505-7534-11e1-b93f-1d1c56c85325 in the example above.


A client parses the result JSON to obtain the URLs for downloadable files. It can then issue an HTTP GET request to fetch the files.

Example 3.18. GET Request for result file download

GET /csip-erosion/q/182b8505-7534-11e1-b93f-1d1c56c85325/stir_energy.out HTTP/1.1
Host: localhost:8080
Accept: */*

Example 3.18, “GET Request for result file download” shows the GET request to download the stir_energy.out file.

3.5. Error Messages

When client data or model service requests fail the service provides an error message. This message is embedded into the metainfo section of the JSON response.

The figure below shows a response containing an error message. The presence of an error key in metainfo indicates an execution problem.

Example 3.19. Error Handling

{
    "metainfo": {   
        "status":"Failed",
        "error": "Insufficient input data"
    }
    "parameter":[
      ...
    ]
}

The JSON response containing the error contains the original service parameterization and request metainfo.


3.6. Ensemble Execution

The method of submitting multiple sets of parameters for model execution is called an ensemble run. Each individual parameter set represents an individual request. CSIP splits up parameter sets and executes a single run for each parameter set. Service requests will execute in parallel using the configured number of worker threads.

An ensemble run completes all individual requests runs finish. The result JSON contains the results of the entire ensemble request. Like the array of parameters, results are returned as an array of result sets in request order. The first result set relates to the first parameter set.

Example 3.20. Ensemble Execution

{
   "metainfo": {   
       "parametersets":25
   }
   "parameter":[
    }
     "name:"p1",
     "value":"23",
      ...
    {,
    {
     "name":"p1",
     "value:"24",
      ...
    }
    ...
   ]
}


Ensemble runs like single runs can be executed in asynchronous and synchronous mode.

3.7. Service Testing

CSIP services can be automatically tested. Unit tests can easily be set up to test individual services or collections. Tests may run at the command line or within unit test frameworks such as JUnit [2] or TestNG[3]. CSIP provides a separate library for testing (csip-test.jar). It can be directly executed or added to the JUnit test environment.

Service test setup follows simple naming conventions and is fully descriptive. Each service end point may be tested with one or more JSON requests files. Each JSON request may have file attachments as input for the service. The CSIP test environment automatically submits the JSON to the service endpoint and attaches all input. After successful service invocation the response is stored at the client. If the service produces result files they will be downloaded and stored on the client side. "Golden" response files can be used to automatically compare the retrieved response against known valid values.

All tests for one service endpoint reside in one folder. The folder contains the test descriptor, the JSON request(s), optional request input(s), and optional golden files.

The following directory structure is used for CSIP tests:

<folder>/

The test folder

<service-name1>/

The folder for testing "service-name1".

service.properties

The test descriptor, contains properties that control the test. (required)

<test1>-req.json

The test1 request for the service. (required)

<test1>-res.json

The service response for the test1 request (output)

<test1>-req/

The directory containing all input files to be attached to the service request. (optional)

<test1>-res/

The directory containing all output files from the service response. (output)

<test1>-ref.json

The golden service output reference file. (optional)

<test2>-req.json

The second test ...

...

(The same set op files for test 2)

<service-name2>/

The folder for testing "service-name2"

service.properties

Test descriptor "for service-name2"

...

The same set of request, response, input, output, and golden files.

Service test description follows a simple naming convention. A service test must have the "service.properties" file. Each service test consists of a base name and a set of suffixes for different aspects of the test (*-req.json, *-res.json, etc.). The CSIP test framework will recognize the file's bases and generate the service outputs accordingly.

The file service.properties contains property settings controlling service test execution. The url entry is the only required entry which specifies the service endpoint to test.

Example 3.21. service.properties

# service endpoint, required
url=http://localhost:8080/csip-rzwqm/m/rzwqm/1.0

# number of concurrent tests, optional, defaults to '1'
concurrency=4

# timeout for a single test, optional, defaults to '3000'
timeout=5000

# test method: "keysonly" | "keyvalue" | "keyvalueorder" | "none", 1
# defaults to 'none'
verify=keysonly

# should this service test be ignored? ,optional, defaults to 'false'  
ignore=false

# should result files be downloaded?, optional, defaults to 'true'
download_files=false

1

If the verify property is set to "keysonly", the presence of keys is checked against the golden reference file. The "keyvalue" property triggers a key/value comparison, the "keyvalueorder" considers even the order of the key/value pairs. If verify is set to none, the service is being executed, no verification of the results is performed.


Example: Service Test

A service for temperature conversion might be tested using the following setup. A test folder was created using the structure as seen in Example 3.22, “Service Test Example”. There are 2 tests defined within "tempservice_V1_0". Both are using a reference file.

Example 3.22. Service Test Example

work
+--csip
   +-- tests
       +-- tempservice_V1_0
       |    service.properties 
       |    tempconv1-req.json 
       |    tempconv1-ref.json
       |    tempconv2-req.json  
       |    tempconv2-ref.json
       |
       +-- otherservice_V2_0/
            service.properties  
            ...

The file service.properties in tempservice_V1_0 contains the test properties as shown in Example 3.23, “Test settings for 'tempconv' in service.properties”. The key/value pairs of the response results should be compared against the reference file.

Example 3.23. Test settings for 'tempconv' in service.properties

# service endpoint
url=http://localhost:8080/csip-example/m/tempconv/1.0
# verify the results
verify=keyvalue

The test can be executed with the command below. The command line argument '/work/csip/tests/tempservice_V1_0' is the path to the folder of the tempservice tests.

> java -jar csip-test.jar /work/csip/tests/tempservice_V1_0
=================
 Total:     2
 Failed:    0
 Succeeded: 2
 Skipped:   0
 Ignored:   0

>_

As a result, the two tests run successfully against the 'tempconv' endpoint. Upon completion, the output summary of the test command is provided.

Integration into existing unit testing frameworks is easy. The csip-test.jar file has to be added to the CLASSPATH used for testing. The Example 3.24, “JUnit based Service Testing” shows the use of service test example within a JUnit test. Similar to the command line interface, a service test is executed with the path to the test directory as an argument.

Example 3.24. JUnit based Service Testing

import csip.test.ServiceTest;
import junit.framework.Assert;
import org.junit.Test;

public class STest {
  @Test
  public void stest() throws Exception {
    ServiceTest.Results r = ServiceTest.run(
          "/work/csip/tests/tempservice_V1_0");
    Assert.assertTrue(r.getTotal() == r.getSucceeded());
  }
}

JUnit Assert methods can be used to validate the test result.

4. Invocation Examples

The ModelServices API is callable from various clients such as CURL, Java, or the RestClient browser plugin. CURL is a command line tool for HTTP requests. Java can be used with several libraries to perform Restful HTTP service calls. RestClient exists as a UI plugin for several web browsers and can be obtained online at: https://github.com/rest-client/rest-client.

This chapter provides several examples of how to implement a CSIP client for a variety of programming languages. Parameter and result elements may change during development because of requirement adjustments and service improvements.

All ModelService URLs provided by CSIP have a common structure. The service context path starts with 'csip', followed with an 'm' indicating the modeling services category. Other service categories in CSIP include: database services ('d'), the query service 'q' described earlier, and console services 'c'.

Example 3.25. CSIP Service URL

http://<host>:<port>/csip-<context>/{m|d}/<service>/<version>"

Description:

<host>

The service host name.

<port>

The service port, if not specified the port is 80.

<context>

The context of the CSIP service.

<service>

The name of the model service. It usually corresponds to a known simulation model.

<version>

The version of the model service. This can be an arbitrary string, it does not have to be a numerical value.


An example CSIP service URL is shown below for the temperature conversion service.

Example 3.26. CSIP URL example for the temperature conversion service.

http://localhost:8080/csip-example/m/temp/1.0


This URL represents the version 1.0 of the temperature conversion service at port 8080 on localhost.

4.1. CURL

For simple service usage, CURL is a useful tool to submit an http request and receive a response. CURL is a simple command line tool for Linux, Windows, OSX, and other operating systems. A typical usage of CURL for CSIP is shown below.

The example fetches the model parameterization requirements for the temperature conversion as a JSON object using an HTTP GET (default curl operation)

curl -H "Accept: application/json" 
    "http://localhost:8080/csip-example/m/temp/1.0"

The following example executes the temperature service by sending an HTTP POST request by submitting the request data.

The file temp.json contains the service request data, the parameter data "temp" with a value of 25.

{  
   metainfo: {},
   parameter: [ 
     { name: "temp",
       value: 25 
     }
   ]
}

The command below performs a POST request against the CSIP endpoint.

curl -X POST \
     -H "content-type: application/json" \
     -H "accept: application/json" \
     "http://localhost:8080/csip-example/m/temp/1.0" -d @temp.json

The "-X" flag selects the POST request method to use when communicating with the CSIP server. The header flag "-H" specifies the content type as "application/json" and the JSON request data is obtained from the file "temp.json" (using the "-d" flag).

4.2. Java

There are different methods for invoking CSIP services from Java. In the examples below we present four approaches to write CSIP REST clients, including an example using the CSIP library itself.

4.2.1. Java HTTP client library

Like almost all programming languages, Java has built-in support for HTTP allowing basic POST and GET requests. This API is built around two classes, java.net.URL and java.net.HttpURLConnection. The URL class is just a Java representation of a URL.

From a URL, one can create an HttpURLConnection that allows to invoke specific requests. Here is an example of doing a CSIP POST request:

Example 3.27. CSIP service execution in core Java

import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.io.BufferedReader;

...
URL url = new URL("http://localhost:8080/csip/m/temp/1.0");
HttpURLConnection con = (HttpURLConnection) url.openConnection();
conn.setDoOutput(true);
conn.setRequestMethod("POST");
conn.setRequestProperty("Content-Type", "application/json");
conn.setUseCaches(false);
conn.setDoInput(true);
conn.setDoOutput(true);
OutputStream os = conn.getOutputStream();
os.write(("{\n"
        + "    \"metainfo\": {\n"
        + "    },\n"
        + "    \"parameter\": [ \n"
        + "     {\n"
        + "      \"name\": \"temp\",\n"
        + "      \"value\": 25\n"
        + "     }\n"
        + "    ]\n"
        + "}").getBytes());
os.flush();
os.close();

if (conn.getResponseCode() != HttpURLConnection.HTTP_OK) {
    throw new RuntimeException("Failed.");
}

InputStream is = conn.getInputStream();
BufferedReader rd = new BufferedReader(new InputStreamReader(is));
StringBuilder response = new StringBuilder();
String line;
while ((line = rd.readLine()) != null) {
     response.append(line);
     response.append('\n');
}
connection.disconnect();

System.out.println("Response: " + response.toString());

By calling HttpURLConnection.setDoOutput(true) a body for the request can be written. We then call setRequestMethod() to tell the connection we’re making a POST request. The setRequestProperty() method is called to set the Content-Type of our request. We then get a java.io.OutputStream to write out the data to the CSIP endpoint. The output of the request is then obtained using the getInputStream() method and output o of the call is stored in the response String. Finally, disconnect() is called to clean up the HTTP connection.

4.2.2. Java RX RS Client Library

The following client exercises the Java API for RESTful Web Services (JAX-RS). JAX-RS Client API is another Java based API for communication with RESTful Web services[4]. It is also part of Java EE 7 and it is designed to make it very easy to consume a Web service exposed via HTTP protocol to enable developers to concisely and efficiently implement portable client-side solutions.

The ClientBuilder is a JAX-RS API used to create new instances of Client. In a slightly more advanced scenarios, ClientBuilder can be used to configure additional client instance properties, such as a SSL transport settings.

Example 3.28. CSIP service execution using Java RX RS Client

import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.client.Entity;
import javax.ws.rs.client.WebTarget;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.UriBuilder;

...
String req = new String("{\n"
      + "    \"metainfo\": {\n"
      + "    },\n"
      + "    \"parameter\": [ \n"
      + "     {\n"
      + "      \"name\": \"temp\",\n"
      + "      \"value\": 25\n"
      + "     }\n"
      + "    ]\n"
      + "}");

String url = "http://localhost:8080/csip/m/temp/1.0";

String resp = ClientBuilder.newClient()
         .target(UriBuilder.fromUri(url).build())
         .service.request(MediaType.APPLICATION_JSON)
         .post(Entity.entity(req, MediaType.APPLICATION_JSON_TYPE), String.class);

System.out.println(resp);

Once there is a Client instance created, a WebTarget object can be obtained from it. A Client contains several target(...) methods that allow for creation of WebTarget instance. In this case we're using target(String uri) version. The uri passed to the method as a String is the URI of the targeted web resource.

This compact example demonstrates another advantage of the JAX-RS client API. The fluency of JAX-RS Client API is convenient especially with simple use cases like CSIP.

4.2.3. Apache HTTPClient library

The following client harnesses the Apache HTTPClient library[5]. The Apache foundation is providing an extensible HTTP client library called HttpClient. Although it is not JAX-RS-aware, it does have facilities for preemptive authentication and APIs for dealing with a few different media types like forms and multipart which is essential for calling a CSIP service. Some of its other features are a full interceptor model, automatic cookie handling between requests, or pluggable authentication.

Example 3.29. CSIP service execution in Java

import java.io.BufferedReader;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.HttpClientBuilder;

...
StringEntity e = new StringEntity(
              "{\n"
            + "    \"metainfo\": {\n"
            + "    },\n"
            + "    \"parameter\": [ \n"
            + "     {\n"
            + "      \"name\": \"temp\",\n"
            + "      \"value\": 25\n"
            + "     }\n"
            + "    ]\n"
            + "}", ContentType.APPLICATION_JSON);

String url = "http://localhost:8080/csip/m/temp/1.0";

// create the client and post the request:
HttpPost post = new HttpPost(url);
post.setEntity(e);
HttpClient client = HttpClientBuilder.create().build();
HttpResponse response = client.execute(post);
 
BufferedReader rd = new BufferedReader(
       new InputStreamReader(response.getEntity().getContent()));
 
StringBuilder result = new StringBuilder();
String line;
while ((line = rd.readLine()) != null) {
    result.append(line);
    result.append('\n');
}
System.out.println("Response: " + result.toString());


In Apache HttpClient 4, the org.apache.http.client.DefaultHttpClient class is responsible for managing HTTP connections. It handles the default authentication settings, pools and manages persistent HTTP connections (keepalive), and any other default configuration settings. It is also responsible for executing requests.

There are related classes in the org.apache.http.client.methods package for performing GET, POST, PUT, and DELETE invocations. To push service input data to the CSIP server via a POST operation, one needs to encapsulate the data within an instance of the org.apache.http.HttpEntity interface. The framework has some simple prebuilt ones for sending strings, forms, byte arrays, and input streams. A org.apache.http.entity.StringEntity encapsulates the JSON that a client wants to send across the network. The correct Content-Type is set by calling StringEntity.setContentType(), the entity is passed to the request by calling HttpPost.setEntity().

Once a request is built, it is executed by passing and calling DefaultHttpClient.execute(). This returns an org.apache.http.HttpResponse object. The HttpResponse.getEntity() method returns an org.apache.http.HttpEntity object, which represents the message body of the response. From it the client can get the Content-Type by executing HttpEntity.getContentType() as well as a java.io.InputStream to read the response. Finally, connections require cleanup by calling HttpClient.getConnectionManager().shutdown().

4.2.4. CSIP HTTPClient

The CSIP distribution provides its own HTTP client which is internally based on the Apache HTTPClient library. However, the CSIP client offers a more concise API to invoke CSIP service endpoints with only a single line of code.

The CSIP client library is entitled csip-client.jar within the distribution. Add this to the CLASSPATH of any Java CSIP client application. The example CSIP call is shown below:

Example 3.30. CSIP service execution in Java (CSIP client)

import org.codehaus.jettison.json.JSONObject;
import csip.Client;
...

String req = "{\n"
           + "    \"metainfo\": {\n"
           + "    },\n"
           + "    \"parameter\": [ \n"
           + "     {\n"
           + "      \"name\": \"temp\",\n"
           + "      \"value\": 25\n"
           + "     }\n"
           + "    ]\n"
           + "}";
String url = "http://localhost:8080/csip/m/temp/1.0";
JSONObject res = new Client().doPOST(url, new JSONObject(req));

System.out.println(res.toString(4));


The CSIP service gets executed via the doPOST() method. A variant of this method allows also the attachment of files to the HTTP/POST CSIP request, ensuring proper setting of headers and mime types.

Using the CSIP client jar is the recommended method for calling CSIP services in Java.

4.3. C#

The Microsoft .NET Framework provides a layered, extensible, and managed implementation of Internet services that can be quickly and easily integrated into your applications. Both examples, C# and VB.NET use the same .NET Framework classes for performing a CSIP service call.

The following example describes the steps used to execute send input data to a CSIP service and fetch its response.

The .NET Framework provides protocol-specific classes derived from WebRequest and WebResponse for "http:" URIs. Both classes are the core if this example.

The following example shows the CSIP client in C# for the .NET platform.

Example 3.31. CSIP service call in C#

using System;
using System.Net;
using System.IO;
using System.Text;

namespace httpclient
{
 class MainClass
 {
  public static void Main(string[] args)
  {
   string json = "{ " +
    "  metainfo: {}," +
    "  parameter: [ " +
    "    { name: \"temp\"," +
    "      value: 25 " +
    "    } " +
    "  ] " +
    "}";

   // Create a request using a URL that can receive a post. 
   WebRequest request = WebRequest.Create(            1
              "http://localhost:8080/csip/m/temp/1.0");
   request.Method = "POST";                           2

   // Create POST data and convert it to a byte array.
   byte[] byteArray = Encoding.UTF8.GetBytes(json);
   // Set the ContentType property of the WebRequest.
   request.ContentType = "application/json";
   request.ContentLength = byteArray.Length;          3
   // Get the request stream.
   Stream dataStream = request.GetRequestStream();
   dataStream.Write(byteArray, 0, byteArray.Length);  4
   dataStream.Close();     

   // Get the response.
   WebResponse response = request.GetResponse();      5

   StreamReader reader = new StreamReader(response.GetResponseStream());
   string responseFromServer = reader.ReadToEnd();    6

   Console.WriteLine(((HttpWebResponse)response).StatusDescription);
   Console.WriteLine(responseFromServer);             7

   reader.Close();
   response.Close();
  }
 }
}

1

Create a WebRequest instance by calling Create() with the URI of the CSIP service resource.

2

Specify a protocol method that permits data to be sent with a request, such as the HTTP POST method.

3

Set the content type and length

4

Write the JSON data to the Stream object returned by the GetRequestStream() method.

5

Send the request to the CSIP server by calling GetResponse(). This method returns an object containing the server's response.

6

Read the JSON response into a string.

7

Print out the response.

4.4. VB.Net

This example explain the use of VB.NET for posting a a CSIP model request to a server using the .NET framework classes WebRequest and WebResponse as is was shown in the previous section for C#. Because the .NET framework classes being used are the same, the examples only differ with respect to language constructs.

Example 3.32. CSIP service call in VB .Net

Imports System.Net
Imports System.IO

Public Class Application
 Public Shared Sub Main()
  
  Dim URL As String = 
    "http://localhost:8080/csip/m/temp/1.0"
  
  Dim req As String = "{ " +
    "  metainfo: {}," +     "  parameter: [ " +
    "    { name: ""temp""," +
    "      value: 25 " +
    "    } " +
    "  ] " +
    "}"
  Dim res As String = ""
  
  Try
    Dim client As HttpWebRequest = Webrequest.Create(URL)
    client.Method =  "POST"
    client.ContentType = "application/json"
    Dim encoding As New Text.ASCIIEncoding() 
    Dim postByteArray() As Byte = encoding.GetBytes(req)
    
    client.ContentLength = postByteArray.Length
    Dim postStream As Stream = client.GetRequestStream()
    postStream.Write(postByteArray, 0, postByteArray.Length)
    postStream.Close()

    Dim clentResponse As HttpWebResponse = client.GetResponse()
    
    If clentResponse.StatusCode = HttpStatusCode.OK Then
      Dim responseStream As StreamReader = _
        New StreamReader(clentResponse.GetResponseStream())
      res = responseStream.ReadToEnd()
    End If
    clentResponse.Close()
     
  Catch e As Exception
    res = "CSIP error occurred: " & e.Message
  End Try
     
  System.Console.WriteLine(res)
 End Sub
End Class

The VB.NET example employs exception handling for error management in tis example.

4.5. Python

Python is an object-oriented, interactive, general purpose programming language that has characteristics such as high level dynamic data types, dynamic typing and a very clear syntax [6]. The httplib2 python library[7] is a comprehensive HTTP client library that handles caching, keep-alive, compression, redirects, and many kinds of authentication. The httplib2.py library supports many features left out of other Python HTTP libraries. This library is installed using the pip command.

#pip install httplib2

CSIP model execution using the Python/httplib2 is shown below. The http2 library and the json library must be imported.

Example 3.33. CSIP service call in Python

import httplib2, json

req = json.dumps(
 { 'metainfo': {}, 
   'parameter' : [ 
   { 
    'name' : 'temp', 
    'value': 25
   }]
 })

headers = {"content-type": "application/json", 
           "accept": "application/json"}
url = "http://localhost:8080/csip/m/temp/1.0"

http = httplib2.Http()
res, content = http.request(url, 'POST', 
                            headers=headers, body=req.encode())

print res.status, res.reason
print content

The json.dumps() method serializes the argument to a JSON formatted string. Note that we have to use the encode() function from json to encode the string before using it as the POST body.

4.6. C/C++

C is a general-purpose, imperative computer programming language, while C++ adds object-orientation to C. The most complete library for C/C++ programs is libcurl[8], a free and easy-to-use client-side URL transfer library. Curl builds and works identically on all operating systems. libcurl is the most used C-based highly portable transfer library in the world.

libcurl is often pre-installed on linux and unix based systems. However, package managers such as apt, yum, rpm, etc. can be used to fetch and install the binary packages as needed.

libcurl introduces the "easy" interface. All operations in the easy interface are prefixed with 'curl_easy'. The easy interface provides for single transfers with a synchronous and blocking function call. The example CSIP client program below can be compiled using gcc and must be linked against the libcurl library by using the -lcurl flag.

Example 3.34. CSIP service call in C/C++

// install libcurl
// compile: gcc Call.c -lcurl

#include <string.h>
#include <curl/curl.h>

int main() {
  CURL *curl;
  CURLcode res;
  struct curl_slist *headers = NULL;

  curl = curl_easy_init();
  if (curl) {
    const char *req = 
        "{ "
        "  metainfo: {},"
        "  parameter: [ "
        "    { name: \"temp\","
        "      value: 25 "
        "    } "
        "  ] "
        "}";
    
    const char *url = "http://localhost:8080/csip/m/temp/1.0";

    headers = curl_slist_append(headers, "content-type:application/json");
    headers = curl_slist_append(headers, "accept:application/json");

    curl_easy_setopt(curl, CURLOPT_URL, url);
    curl_easy_setopt(curl, CURLOPT_POST, 1L);
    curl_easy_setopt(curl, CURLOPT_POSTFIELDS, req);
    curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, strlen(req));
    curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);

    res = curl_easy_perform(curl);
    if (CURLE_OK != res) {
      printf("Error: %s\n", strerror(res));
      return 1;
    }
    curl_easy_cleanup(curl);
    curl_slist_free_all(headers);
  }
  return 0;
}

The program initializes curl, creates header information, sets various options, and performs the POST request. Finally, all resources are released.

The code above will also compile with a C++ compiler (e.g. g++), which uses the same library.

4.7. JavaScript

JavaScript is an object-oriented programming language commonly used to create interactive effects within web browsers. The presented JavaScript CSIP example uses jQuery, a fast, small, and feature-rich JavaScript library[9]. JQuery simplifies HTML document traversal and manipulation, event handling, animation, and Ajax with an easy-to-use API that works across a multitude of browsers.

Example 3.35. CSIP service call in JavaScript

<script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
...

var reqData = 
 '{' +
  '"metainfo": {},'+
  '"parameter": [' +
    '{' +
    '  "name": "temp",' +
    '  "value": 25' +
    '}' +
  ']' +
 '}';

// ajax call to the service
$.ajax({
  type: "POST",
  headers:{'accept': 'application/json'},
  contentType: "application/json",
  url: "http://localhost:8080/csip/m/temp/1.0",
  data: reqData,
  success: function (data, textStatus, xhr) { 
      success(data);
  },
  error: function(jqXHR, textStatus, errorThrown){
      alert("Error! " + errorThrown);
  }
});
...


Simple AJAX calls in JavaScript can be performed to invoke CSIP services as shown in Example 3.35, “CSIP service call in JavaScript”. This fragment constitutes population of a request object (reqData) and the client service invocation.

The success callback function is passed the returned data, which will be a JSON string depending on the MIME type of the response. It is also passed in the text status of the response.

Tomcat application server security defaults permit Javascript REST clients to only invoke services on the originating web server that provides the Javascript content to the user. Ajax requests are subject to the same origin policy; the request can not successfully retrieve data from a different domain, subdomain, port, or protocol. The CORS (Cross-origin resource sharing) setting in tomcat can be enabled to overcome this limitation.

4.8. Groovy

Groovy is a dynamic language with features similar to those of Python, Ruby, Perl, and Smalltalk. It can be used as a scripting language for the Java Platform, is dynamically compiled to Java Virtual Machine (JVM) bytecode, and interoperates with other Java code and libraries.

Groovy's HTTPBuilder [10]is the easiest way to manipulate HTTP-based resources in a Java VM. HTTPBuilder is a wrapper for Apache's HttpClient with some Groovy syntactical extensions. The request/response model is also inspired by Prototype.js.

HTTPBuilder is the main API class used to make requests and parse responses as shown below.

Example 3.36. CSIP service call in Groovy

@Grab(group='org.codehaus.groovy.modules.http-builder', 
      module='http-builder', version='0.7' )

import groovyx.net.http.HTTPBuilder
import static groovyx.net.http.ContentType.JSON
import static groovyx.net.http.Method.POST
  
def http = new HTTPBuilder('http://localhost:8080')
http.request(POST) {
    uri.path = '/csip/m/temp/1.0'
    requestContentType = JSON
    body = [metainfo:[dummy:0], parameter:[[name: 'temp', value: 25]]]

    response.success = { resp, json ->
        println "Success! ${resp.status}"
        println "Response: ${json}"
    }

    response.failure = { resp ->
        println "Request failed with status ${resp.status}"
    }
}


The @Grab command manages installation of the http-builder library using the Grape tool. HttpBuilder is not part of the Groovy distribution. The request content type is set to JSON, while the JSON content is provided in Groovy syntax. The response handler is a closure which prints out the response body on successful execution.

4.9. Go

Go is an open source programming language developed by Google and many other contributors from the open source community [11]. It is a fast, statically typed, compiled language with support for garbage collection and run-time reflection.

The Go package "GoRequest" [12]provides a simplified HTTP client library for HTTP client implementations. In the example, this library is used for exercising the CSIP service call for temperature conversion. The library is installed using the go get command. The gorequest library simplifies the submission of JSON request data compared to standard Go libraries. JSON data can be provided directly.

Example 3.37. CSIP service call in Go

package main

// install go get github.com/parnurzeal/gorequest
// go run Call.go

import (
  "fmt"
  "github.com/parnurzeal/gorequest"
)

func main() {
  request := gorequest.New()
  resp, body, errs := request.Post(
        "http://localhost:8080/csip/m/temp/1.0").
  Set("accept","application/json").
  Set("content-type","application/json").
  Send(`{
    "metainfo": {},
    "parameter": [ 
       {
         "name": "temp",
         "value": 25
       }
      ]
     }`).
   End()
   fmt.Println("response Status:", resp.Status)
   fmt.Println("result:", body)
   fmt.Println("errors:", errs)  
}

The Go client source code shown above creates a CSIP POST request and sends the JSON parameter request to the simpleservice endpoint. The response status, body, and errors are printed out.

4.10. Ruby

Ruby is a dynamic, reflective, object-oriented, general-purpose programming language. Most Ruby distributions contain 'Net::HTTP' [13]classes which are part of the Ruby Standard Library. Net::HTTP provides a rich library which can be used to build HTTP user-agents. Net::HTTP is designed to work closely with URI. URI::HTTP#host, URI::HTTP#port and URI::HTTP#request_uri are used within Net::HTTP.

Example 3.38. CSIP service call in Ruby

require 'net/http'
require 'json'

def do_csip
    uri  = URI('http://localhost:8080/csip/m/temp/1.0')
    http = Net::HTTP.new(uri. host)
    req  = Net::HTTP::Post.new(uri.path, initheader = 
                   {'content-type' =>'application/json',
                    'accept' =>'application/json'})
    req.body = { 
                metainfo: {},  
                parameter: [
                    { name: "temp", 
                      value: 25 } 
                ] 
               }.to_json
    res = http.request(req)
    puts "response #{res.body}"
rescue => e
    puts "failed #{e}"
end

do_csip

A POST request can be made using the Net::HTTP::Post class. The example above creates a JSON encoded request body containing the temperature conversion input. The function do_csip performs the request and prints out the response.

4.11. Client - Best Practices

It is recommended for the client to follow some rules when executing CSIP Services:

  • For asynchronous requests, if service execution is expected to take a significant time (>2 sec), the returned metadata property "next_poll" and "first_poll" should be respected by the client. A client should start polling after "first_poll" milliseconds, and then in subsequent "next_poll" milliseconds. There is no advantage for a client to use a shorter polling interval.

  • All timestamps are given in ISO-8601 format with timezone. In Java the pattern "yyyy-MM-dd'T'HH:mm:ssZ" can be used to parse such information into a 'java.util.Date' object and further process it into Calendar or other representations.

  • For all CSIP service requests the JSON payload may contain embedded JSON objects in addition to metainfo and parameter. The service will retain those entries and will send them back untouched in the response. This enables the client to use the service payload to carry additional (state) information with the service, such as user interface controls or database data.



[2] http://www.junit.org

[3] http://www.testng.org

[4] https://jersey.java.net

[5] http://hc.apache.org

[6] https://www.python.org

[7] https://github.com/jcgregorio/httplib2

[8] http://curl.haxx.se/libcurl

[9] http://jquery.org

[10] http://groovy.codehaus.org/modules/http-builder

[11] https://golang.org

[12] https://github.com/parnurzeal/gorequest

[13] http://ruby-doc.org

Chapter 4. ModelServices - Server API

The CSIP server API allows the implementation of custom model services. There are various approaches implementing such services. The most generic method is by directly sub-classing the ModelDataService and implementing the required methods. This approach (see Section 1, “Model and Data Service (ModelDataService)”) provides maximum flexibility and can be used for all kind of service implementations.

If the primary purpose is to provide a service endpoint to host external native executables (e.g. wrapper), the ModelDataService class should be simply annotated. This is explained in detail in Section 1, “Model and Data Service (ModelDataService)”. As a second option, an OMS based model can be easily turned into a CSIP service by using the ModelDataService class with the annotation for OMS_DSL resources(Section 1, “Model and Data Service (ModelDataService)”).

1. Model and Data Service (ModelDataService)

The ModelDataService class is the base class for all CSIP modeling services. Service implementations usually subclass ModelDataService to offer a custom service endpoint. Concrete service implementations must subclass ModelDataService. Example 4.1, “General Service Structure” shows the generic service structure.

Example 4.1. General Service Structure

import javax.ws.rs.*;                                 1
import oms3.annotations.*;
import csip.*;

@Name("Energy")                                       2
@Description("Energy calculations")                   3
@Path("m/energy/1.0")                                 4
public class EnergyService extends ModelDataService { 5
   // service implementation
}

1

Required package imports

2

Name annotation, identifies the service by name in catalog listing. (optional)

3

Brief service description. (optional)

4

Service endpoint. (required)

5

Subclassing ModelDataService for the EnergyService.

The listing above shows the core skeleton of a CSIP service. The new service class is named EnergyService which can be invoked using the specified endpoint "<host>/m/energy/1.0". The class name can be seen as the internal representation of the service whereas the endpoint serves as the publicly accessible interface. The name and description of the service are optional, since they are only being used for catalog listing of available service endpoints within the same context.

A custom service may implement ModelDataService methods to facilitate preparation, execution, and results generation. These methods are invoked throughout the lifecycle of a service request. Figure 4.1, “Server-side Service Life-cycle” shows the sequence of method invocations.

Figure 4.1. Server-side Service Life-cycle

Server-side Service Life-cycle

JSON HTTP/POST requests are received by the server from the client. The CSIP framework will initially handles this content. It parses the payload, verifies its structural integrity, extracts attached input files from the payload, and creates a workspace on the server for this session. The workspace is initialized and identified with an SHA-1 hash. The ModelDataService method getSUID() can be used to obtain that UUID for the session. This hash is guaranteed to be unique across all active modeling service sessions and CSIP workers for a given CSIP deployment.

Four framework methods are provided to implement service specific handling of business logic as indicated with the blue box in Figure 4.1, “Server-side Service Life-cycle”. At a bare minimum, the process() method must be implemented to realize the custom logic.

The processing methods are:

void preProcess()

Implement to verify and obtain service request parameters (this is optional). Use the methods as described in Section 3, “Handling Service Input” to fetch the request input and service metadata. All retrieved inputs should be stored as service instance data.

String process()

This method is used to provide the core computational function of the service. Implementing this method is required. The computation may be executed within process() directly, or it can be performed as an external process. Further information about how to bundle native executable and other resources can be found in Section 5, “Resources”. Upon conclusion, this method must return a status indicator describing the outcome of execution (e.g. success, failure) Returning null indicates success, a String return signals an error, where the content of the String is the error message.

void postProcess()

The postProcess() method prepares the output of the service (this is optional). Use the methods described in Section 4, “Providing Service Output” to bundle result values, files, and other content to be returned.

void report()

This method can be implemented to provide optional reporting output for the service. Reports can detail additional output data that can optionally be fetched by the client on demand. An HTTP/GET client request is required to fetch report output. Implementation of the report() method is optional.

The final step of the service life-cycle wraps up the service response, manages the workspace and stores results and report files into the session datastore for the specified period of time before being archived and purged.

Example: A custom Service

An example of a simple service that implements the life-cycle methods is shown in Example 4.2, “Service life-cycle example”.

Example 4.2. Service life-cycle example

@Name("EFH2")
@Description("Storm runoff model based on " +
             "conventions in Engineering Field Handbook.")
@Path("m/efh2/1.0")
public class V1_0 extends ModelDataService {

    EFH2HydrologyModel efh2 = new EFH2HydrologyModel(); 1

    @Override
    protected void preProcess() throws Exception {  
        efh2.setPrecip(getDoubleParam("precip"));       2
        efh2.setRunoffCurveNumber(getIntParam("runoffcurvenumber"));
        efh2.setStormType(getStringParam("stormtype")); 
        efh2.setWatershedLength(getDoubleParam("watershedlength")); 
        efh2.setWatershedSlope(getDoubleParam("watershedslope")); 
    }

    @Override
    protected String process() throws Exception {
        return efh2.simulate() == 0 ? null ? "error";   3
    }

    @Override
    protected void postProcess() throws Exception {
        putResult("runoff", efh2.getRunoffQ());         4
        putResult("timeofconcentration", efh2.getTimeOfConcentration());
        putResult("unitpeakdischarge", efh2.getUnitPeakDischarge());
    }
} 


1

The model (EFH2) is instantiated as a service field.

2

In preProcess(), all service inputs are fetched (e.g. getDoubleParam()) and passed to the model EFH2.

3

in process(), the external model is executed and the result returned.

4

in postProcess(), model results are obtained from EFH2 and prepared for the service response using the putResult() method.

Further discussion on methods for service request parameterization can be found in Section 3, “Handling Service Input”, output generation is explained in Section 4, “Providing Service Output”.

During service processing it is sometimes necessary to access the context of the service. ModelDataService offers various methods that can be used to access information such as the current ID of this session (SUID), find out more about the origin of the request (getRequestURL(), getRequestHost(), getRequestContext(), getRemoteAddr()), and to retrieve the current codebase of the service context Example 4.3, “Service Context Methods”.

Example 4.3. Service Context Methods

String getSUID() 
String getRemoteAddr() 
String getCodebase() 
String getServicePath() 
String getRequestURL() 
String getRequestHost() 
String getRequestContext() 

All CSIP framework methods are further described in the appendix of this document.

2. Workspace Management

CSIP creates a workspace for each model session. This is a temporary directory residing within the CSIP work directory (configuration string "csip.work" Table 5.1, “CSIP System Properties”). This temporary directory will be named with the simulation id (SUID). The SUID is a time and network address based universally unique identifier that uniquely identifies the modeling session and its associated resources.

The workspace is created and managed by CSIP and the methods listed in Example 4.4, “Workspace Management Methods”. These methods enable accessing the current workspace and the results directory. Both directories are named using the SUID.

Example 4.4. Workspace Management Methods

boolean hasWorkspaceDir()   1
File getWorkspaceDir()      2

1

The workspace methods allow checking the existence of a workspace directory and obtaining a File reference.

2

This method gets the workspace directory (provided by CSIP).

Some general notes about workspace and result directories and their management in CSIP:

  1. A workspace is created by CSIP if: (1) there are files attached to the HTTP/POST call to invoke the service, or (2) the service calls getWorkspaceDir(). The getWorkspace() returns a valid, existing workspace folder, whereas the hasWorkspace() method just probes for its existence.

  2. CSIP only provisions required resources for a service. If a service implementation includes no input or external executable files or generates no output, then the workspace folder is not created. This improves server side resource management.

  3. The workspace is deleted after successful service execution. Only the files tagged using putRestult(..) (see Example 4.8, “Service Output Generation”) are preserved for download in the session datastore.

Example: Workspace usage:

If a service needs to generate an output file within the workspace it can be accomplished by accessing the getWorkspace() method. If the workspace does not exist, it will be created.

..
File dbg_out = new File(getWorkspaceDir(), "dbg.txt");
..

CSIP ensures that the workspace has proper file permissions for the workspace folder.

3. Handling Service Input

Each custom service must handle input. Service input must be provided in two forms:

  1. JSON model services payload as the body of an HTTP/POST request according to the specification in Section 3, “ModelExecution Service”, and

  2. Input files as an HTTP/POST multipart attachment. One of the files must be the JSON model services payload.

A service might only have a JSON model service payload, if all the inputs can be provided in this form. In other cases, modeling services need multiple input files to run the model. A mixture of JSON input data and file attachments is common for model simulations.

3.1. JSON Input Data and Parameter

A CSIP client call provides input to the service using JSON content. The 'parameter' section of the JSON file contains all literal input. The custom CSIP service, however, does not have to process, parse, and extract the data from JSON directly. This is accomplished from within CSIP infrastructure (ModelDataService). A service should always use the methods as shown in Example 4.5, “Parameter Input Methods” to obtain parameter and metadata. ModelDataService methods handle the correct conversion of data types and validation of values as applicable.

Example 4.5. Parameter Input Methods

boolean hasParam(String name)                       1
int getParamCount() 
Set<String> getParamNames() 

String getStringParam(String name)                   2
String getStringParam(String name, String def)   
int getIntParam(String name)   
int getIntParam(String name, int def)   
double getDoubleParam(String name)   
double getDoubleParam(String name, double def)   
boolean getBooleanParam(String name)   
boolean getBooleanParam(String name, boolean def)  
long getLongParam(String name)   
long getLongParam(String name, long def)   
JSONOjetct getJSONParam(String name)   
JSONOjetct getJSONParam(String name, JSONOjetct def)   

String getParamUnit(String name)                     3
String getParamDescr(String name)   
JSONObject getParamGeometry(String name)

1

Reports on the existence, number, and list of parameters.

2

Returns the parameter value as a specific data type. If conversion is not possible, a ServiceException is thrown. All methods have variants that allow specification of default values if the parameter is not present.

3

Get the parameter metadata. A custom service may want to fetch the parameter's unit description or the geometry. If a metadata element is not present, a ServiceException is thrown.

All parameter input should be obtained in the preProcess() or process() method of a service call. Usually, the request parameter data is placed into service fields or passed to the service's internal data structures.

A detailed listing of parameter methods can be found in ???.

Example: Accessing Model Parameter

A ModelDataService receives a JSON request that contains a parameter called "precip". This parameter has a value "14.4" and unit "inches".

{
    "parameter" : [
      ...
      {
         "name" : "precip",
         "value": 14.9
         "unit" : "inch"
      },
      ...
    ]
}

The above "precip" request parameter of a request can be read in by the service using the getDoubleParam() and getParamUnit() methods.

@Override
protected void preProcess() throws Exception {  
    ...
    double precip = getDoubleParam("precip"));   
    String precip_unit = getParamUnit("precip"));   
    ...
}

If a JSON parameter cannot be converted into the desired type, a ServiceException is thrown.

3.2. Reading Metainfo

Service metainfo is a part of every service request. This is not direct input to the model, it rather provides context data to the service. As an example, a flag controlling the verbosity of service output, or requesting the use of a certain model backend would be part of the metainfo section and not parameter.

The Example 4.6, “Metainfo methods” shows all methods available in CSIP to fetch metainfo content. It is not needed to parse the JSON request directly.

Example 4.6. Metainfo methods

Set<String> getMetainfoNames()           1
int getMetainfoCount()
boolean hasMetainfo(String name)

String getStringMetainfo(String name)    2
int getIntMetainfo(String name) 
double getDoubleMetainfo(String name) 
boolean getBooleanMetainfo(String name) 

1

Get available metainfo parameter names and quantity. Check if a metainfo entry is present.

2

Get a metainfo value by name. If a metainfo element is not present, a ServiceException is thrown

Metainfo is typically processed in the preProcess() or the process() method of a service call to control service behavior. A detailed listing of all metainfo methods can be found in ???.

Example: Accessing MetaInfo

Within the metainfo section of a service request there can be any number of custom key/value entries. As an example, the metainfo section contains a verbosity flag, that controls the level of output for the service.

{ 
    "metainfo": {
        "verbose": true,
        ...
    }
    ...
}

Metainfo parameters are obtained from the JSON request object using the get???MetaInfo() methods as shown below.

if (hasMetainfo("verbose") {
    boolean verbose = getBooleanMetainfo("verbose")
}  

If a metainfo element does not exist or has the wrong type, a ServiceException is thrown.

The use of custom metainfo content should be carefully considered. Metainfo is not input data to parameterize the service- rather it provides context and configuration data to direct HOW the service should run. Metainfo should be considered optional, as service defaults should enable the service to run when metainfo is absent.

Client provided metainfo is read-only in CSIP. The CSIP infrastructure appends useful metainfo to describe status information, execution time, compute node, etc. which is sent back to the client in the response JSON .

3.3. File attachments

CSIP Model service requests support file attachments as service input. Files are attached as FormDataMultiPart in the POST request. The CSIP infrastructure manages files by extracting them from the request, storing them on the workspace of the service session, and publishing URIs to make them available. Example 4.7, “File input methods” lists the service methods supporting file access.

Example 4.7. File input methods

Set<File> getFileInputs()        1
int getFileInputsCount()         2
File getFileInput(String name)   3
boolean hasFileInput(String name)4

1

Get all service request input files.

2

Get the total number of input files.

3

Get a single file by name. The name must be the file name or the relative path. This method returns the File object containing the full path name within the workspace.

4

Check if a file exists in the workspace.

All files that are part of the request are copied unchanged into the session workspace. If the incoming file is an archive (*.zip, *.gz, *.tar, *tgz, ...) CSIP automatically uncompresses and extracts it into the workspace. It is good practice to compress large files to reduce network I/O requirements.

Example: File attachment

Files are included in the CSIP client request as HTTP mulitpart attachments. The CSIP service infrastructure automatically handles recognition and extraction of input files into the service session workspace. Input files are unpacked from the request and stored in their original form. Using the process() methods of a service the files can referenced by name.

The curl call below invokes a CSIP service and attaches a file. The file "scott.kmz" is attached in this example.

curl -X POST -H "Accept:application/json" \
  "http://localhost/csip-lamps/m/lamps/1.0" -F file1=@c:/scott.kmz

The submitted file can now be referenced in the service implementation.

protected void preProcess() {
    ...
    File gem = getFileInput("scott.kmz")
    ...
}

If the getFileInput() method returns a reference to the file, it is guaranteed to exist.

4. Providing Service Output

Service output is usually constructed in the postProcess() method of a service. Similar to processing parameter input and metainfo, it is not necessary to manually generate the JSON data structure of the response. A family of putResult(...) helper methods are provided to add result values with metainfo to the result section of the response in the proper form.

The Example 4.8, “Service Output Generation” shows methods available for output generation.

Example 4.8. Service Output Generation

void putResult(String name, String val, String unit, String descr)  1
void putResult(String name, String val, String unit)                  
void putResult(String name, String val)                               
void putResult(String name, int val, String unit, String descr) 
void putResult(String name, int val, String unit) 
void putResult(String name, int val) 
void putResult(String name, double val, String unit, String descr) 
void putResult(String name, double val, String unit) 
void putResult(String name, double val) 
void putResult(String name, boolean val, String unit, String descr) 
void putResult(String name, boolean val, String unit) 
void putResult(String name, boolean val) 
void putResult(String name, JSONObject val, String unit, String descr) 
void putResult(String name, JSONObject val, String unit) 
void putResult(String name, JSONObject val) 

void putResult(File file)                                           2
void putResult(File file, String descr) 
void putResult(File... file) 

1

The putResult(...) methods have variants to add a result entry with value, unit, and description. Different value types are supported.

2

The putResult(File ...) method adds a file to the result section. A URL is provided to the client in the response JSON to support retrieving the file in a separate HTTP/GET request.

Example: Result Generation

Results are generated in the postProcess() method. Result entries are added using putResult() helper methods. The Example 4.9, “Example Results” shows a service code fragment creating result entries.

Example 4.9. Example Results

...
    @Override
    protected void postProcess() throws Exception {
        putResult("runoff", model.getRunoffQ(), "cfs", "Runoff value");
        putResult("timeofconcentration", model.getTimeOfConcentration());
        putResult("unitpeakdischarge", model.getUnitPeakDischarge());
    }
...

The example above creates three result entries for a service response, runoff, timeofconcentration, and unitpeakdischarge. The resulting response is shown below.

...
  "result": [
    {
      "name": "runoff",
      "value": 12.75,
      "unit": "cfs",
      "description":"Runoff value"
    },
    {
      "name": "timeofconcentration",
      "value": 0.727178
    },
    {
      "name": "unitpeakdischarge",
      "value": 0.370022
    }
  ]
...

No JSON structure management is required. The putResult() methods manage proper JSON creation for the response.

4.1. Report Generation

Report generation can optionally be incorporated in post processing. It allows sever-side preparation of additional service output that can optionally be fetched by the client. The report typically contains secondary output that has lower significance than the primary service result output. Reports are generated in the report() method of a service.

The list of all putReport() methods is shown in Example 4.10, “Report generation API”.

Example 4.10. Report generation API

    void putReport(String name, String val, String unit, String descr) 
    void putReport(String name, String val, String unit) 
    void putReport(String name, String val) 
    void putReport(String name, int val, String unit, String descr) 
    void putReport(String name, int val, String unit) 
    void putReport(String name, int val) 
    void putReport(String name, double val, String unit, String descr) 
    void putReport(String name, double val, String unit) 
    void putReport(String name, double val) 
    void putReport(String name, boolean val, String unit, String descr) 
    void putReport(String name, boolean val, String unit) 
    void putReport(String name, boolean val) 
    void putReport(String name, JSONObject val, String unit, String descr) 
    void putReport(String name, JSONObject val, String unit) 
    void putReport(String name, JSONObject val) 
    void putReport(File file) 

    void putReport(File file, String descr) 
    void putReport(File... file)  

The putReport() helper methods have semantics similar to the putResult() methods.

Example: Report Generation

Report generation must be implemented within the report() method. Report entries are added using the putReport() family of helper methods. The example shows a service code fragment creating report entries.

Example 4.11. Example Reports

...
double runoff;

public void report() {
   putReport("peakrunoff", 2.34, "cfs");
   putReport(new File("summary-report.pdf"), "summary");
}
...

5. Resources

Every service requires resources, such as static data files, lookup tables, or native executables that contribute to service execution. Resources can be bundled with the service and extracted and referenced at service run time.

CSIP provides flexible bundling at development time and referencing at runtime of all supplemental resources. CSIP Service annotations provide a means to describe resources. Resource annotations can be found in the package csip.annotations.

Resource annotation elements are shown in Example 4.12, “Resource Annotations”. Resource annotations can be used to describe artifacts such as data archives, executable files, configuration files, references to existing resources, java classes, or output files to capture.

Example 4.12. Resource Annotations

public @interface Resource {

    /** The path to the file within the war file or file system.
     */
    String file();

    /** The type of the resource.
     */
    ResourceType type();

    /** The id of that resource. 
     */
    String id() default "";

    /** Should the file be executed via wine.
     */
    boolean wine() default false;

    /** Default executable arguments, separated by space
     */
    String args() default "";

    /** Default environment variables to be used for execution. 
     */
    String env() default "";
}

The specification above lists all annotation methods within the Resource interface. The methods may be applicable for different ResourceTypes, as they are listed in Example 4.13, “Resource types categories”. The methods wine(), args(), and env() can only be used if the resource to described is an executable (EXECUTABLE), an OMS DSL element (OMS_DSL), or a Java class name (CLASSNAME). In these cases, additional information about the execution environment can be provided. Most importantly, the file() method specifies the resource bundled in the service WAR file, the type() method categorizes it, and the id() method allows referencing from the service implementation code. The Example 4.13, “Resource types categories” shows supported resource types in CSIP.

Example 4.13. Resource types categories

public enum ResourceType {
    OUTPUT,      // The resource describes output of the model service.
    ARCHIVE,     // This resource is a zip file and it will be unpacked.
    FILE,        // This resource is a file.
    EXECUTABLE,  // This resource is an executable file.
    REFERENCE,   // This resource is a file reference. 
    JAR,         // This resource is a jar file.
    OMS_DSL,     // This resource is an OMS DSL file.
    CLASSNAME    // This resource is a java class name.
}

Within a service implementation, resources can be accessed by their ID. The CSIP infrastructure ensures that the resource is extracted from the service package and mapped to the ID as provided in the annotation. Two methods are shown in Example 4.14, “Resource access by ID”.

Example 4.14. Resource access by ID

File getResourceFile(String id)         1
Executable getResourceExe(String id)    2

1

Provides a reference to the resource on the local file system. The reference can be to a file or directory if the resource description refers to an archive or directory.

2

Provides an executable for a given ID. The resource is expected to be a native executable. CSIP unpacks the file and maps it into an executable interface to allow the service to control its execution.

The following are example applications of resource annotations.

Example: Defining File Resources

Resource definitions are included in the service implementation as annotations. Annotations prefix the service class as shown in Example 4.15, “Resource definition and access by ID”. Here, a data file that serves as a lookup table for a service is used.

Example 4.15. Resource definition and access by ID

import static csip.annotations.ResourceType.*;

@Resource(file="/data/lookup.txt", type=FILE, id="lkp")   1
public class V_1 extends ModelDataService {

    public void process() {
         // ...
         File f = getResourceFile("lkp");                 2
         // do something with f.
    }
}


1

The resource annotation identifies the file "/data/lookup.txt" with the ID "lkp".

2

Within any service implementation method, the file can be accessed by its ID.

The file "/data/lookup.txt" has to be bundled with the service war using the specified path.

Example: Bundling Archives

Data archives (compressed folders with sub-folders) can be bundled with a service. If a resource type is set to ARCHIVE, the file will be uncompressed/unpacked. Looking up the archive resource by ID will return the unpacked root folder of the archive (Example 4.16, “Resource definition of data archives”).

Example 4.16. Resource definition of data archives

import static csip.annotations.ResourceType.*;

@Resource(file="/data/arcdems.zip", type=ARCHIVE, id="dems")   
public class V_1 extends ModelDataService {

    public void process() {
         // ...
         File f = getResourceFile("dems");                 
         // do something with f.
    }
}


Example: Bundling Executables

Like any other file, executable files can be bundled with the service. The EXECUTABLE type denotes such a resource. The getResourceExe() method fetches the unbundled exe by ID and returns an Executable interface for it. The interface methods support interaction, such as redirecting output, setting command line arguments and environment variables, and execution.

Example 4.17, “Resource definition of Executables” show the use of the resource annotations for an executable. The resource annotations allow multiple resource definitions to be attached to the same service.

Note

In Java 8, resource annotations are not needed since annotations of the same type are repeatable.

Example 4.17. Resource definition of Executables

import static csip.annotations.ResourceType.*;

@Resource({
  @Resource(file="/bin/tr20.exe", type=EXECUTABLE, id="tr20"),  1
  @Resource(file="*.out *.dbg", type=OUTPUT)                    2
})
public class V_1 extends ModelDataService {

    public void process() {
         // ... 
         Executable e = getResourceExe("tr20");                 3
         e.exec();                
         // do something with f.
    }
}


1

This annotation describes the 'tr20.exe' executable which is mapped to the "tr20" ID.

2

The OUTPUT annotation lists files that should be captured as output for a service. It may contain wildcards to specify groups of files. An id is not required here.

3

The reference to the resource is obtained via the Executable interface, and the program gets invoked in the following line.

5.1. Architecture Variants

CSIP services can bundle executables for different architectures to enable flexible deployment to different operating systems. The variable ${arch} can be used in the string referencing the resource to resolve the actual architecture at service runtime. This is shown below.

  @Resource(file="/bin/${arch}/tr20.exe", type=EXECUTABLE, id="tr20")

When the executable is requested using the getResourceExe() method, the "arch" variable will be replaced with the host machine's actual architecture fingerprint:

"win-x86"

Windows, 32bit

"win-amd64"

Windows, 64bit

"lin-x86"

Linux, 32bit

"lin-amd64"

Linux, 64bit

"mac-amd64"

Mac OSX, 64bit

Example: To deploy the same service to various architectures, a tr20.exe native binary must exist as /bin/win-amd64/tr20.exe and /bin/lin-amd64/tr20.exe, respectively. The executable must be compiled for both architectures. Only one resource definition is sufficient to reference the executable. At service runtime, the correct executable is selected based on the service hosting architecture.

5.2. Automated Execution

Automated execution of a model within a service simplifies the integration of existing executables into services. Annotation-only based services should be sufficient for most external models requiring a fixed set of inputs.

The executable is annotated with the ID "auto". An example of a ModelDataService is shown in Example 4.18, “SWAT External Executable Service”. Here, no custom service code is needed.

An external model data service must subclass ModelDataService. All service annotations should be added to this subclass. In addition to @Resource, the @Name, @Description, @Path, and @Polling annotations should be used. @Path is required.

Example 4.18. SWAT External Executable Service

import csip.ModelDataService;
import csip.annotations.*;
import static csip.annotations.ResourceType.*;
import javax.ws.rs.Path;
import oms3.annotations.*;

/**
 * SWAT Service. Plain execution of the original executable.
 *
 * @author od
 */
@Name("SWAT")
@Description("Soil Water Assessment Tool model service. (SWAT2012 Rev. 627)")
@Path("m/swat/1.0")
@Polling(first = 5000, next = 2000)
@Resources({
  @Resource(file = "/bin/lin-amd64/swat2012_627.exe", type = EXECUTABLE, id = "auto"),1
  @Resource(file = "output.* *.out chan.deg fin.fin " + 
                   "watout.dat input.std stdout.txt stderr.txt", type = OUTPUT)       2 
})
public class V1_0 extends ModelDataService {
  // done.
}


1

The "auto" identifier tags the resource for simple auto-execution when the service is invoked. There is no need to explicitly fetch the resource in the process() method of the service and programmatically execute it there.

2

The resource definition lists all files (wildcards allowed) that should be returned as references for download as part of the response. The file entry lists names and patterns of those files separated by whitespaces.

The same auto-execution approach can be applied to Java and OMS models.

6. Client Control

6.1. Service Polling

Model services may require significant time to execute, based on the underlying model and logic. It is not uncommon that services run for seconds, minutes or hours per service call. Asynchronous service invocations for longer running services allow clients to stay responsive during service execution. Clients must periodically check the status of the service completion as described in Section 3.2.2, “Asynchronous Execution”.

To support a reasonable polling frequency for clients, the service should describe when and how often a client should poll. The @Polling annotation, or the methods listed in the examples provide two alternatives to indicate:

  1. the first time that a client should query the service for model results,

  2. and a subsequent polling interval.

A custom model service can either overwrite the methods in Example 4.19, “Polling methods” , or use the annotations in Example 4.20, “Polling Annotations” to specify the desired polling frequency. An accurate polling indication by the model service and its respectful handling at the client side avoids flooding the network with unnecessary requests. For example: If a model runs for 10 minutes, it is not necessary to query the execution status every second after asynchronous submission.

Example 4.19. Polling methods

    long getNextPoll() 
    long getFirstPoll()

Polling methods are preferred if the service execution time varies based on the size of the input data or other factors. In this case the service can provide a dynamic estimate for a polling frequency based on the size or nature of the inputs.

Example 4.20. Polling Annotations

public @interface Polling {
    long first() default -1;
    long next() default -1;
}

Polling annotation are preferred if service execution time is mostly constant, it does not depend on the size of the inputs.

The long return values for first/next polling should be specified in milliseconds.

6.1.1. Example

A model service is expected to run for at least 3 minutes. After that, the service status may be queried every 2 seconds. A polling annotation based service configuration is shown in Example 4.21, “Polling Annotation Example”.

Example 4.21. Polling Annotation Example

@Polling(first = 180000, next = 2000)
public class MService1 extends ModelDataService {
...
}

For a more dynamic setup a computed polling interval can provide better accuracy and reduce unnecessary network traffic.

Example 4.22. Polling Method Example

public class MService1 extends ModelDataService {

  //....

  protected long getFirstPoll() {
     return no_years_in_data * 100;
  }

  protected long getNextPoll() {
     return 1000;
  }
}

In the example Example 4.22, “Polling Method Example”, model execution requires approximately 100 ms per simulation year. Therefore, the first poll can be computed as shown; the next poll is constant.

7. Reporting Progress

If a service is executed asynchronously because of expected long execution time, the service may communicate its completion status to the client to give meaningful feedback. Such feedback can be numerical to indicate a percent completeness, or text can describe the current state of service execution.

Example 4.23. Progress Reporting

    void setProgress(String progress)  
    void setProgress(int progress)

The first method allows reporting of simple messages, the second variant takes a numerical value between 0 and 100.

Example: Progress Reporting

Anytime during service execution progress can be reported. If a client queries the service status, the most recent message is returned.

    setProgress("Fetching landuse data ...");
    // more processing
    setProgress("Parsing polygon information ...");
    // more processing

    // -or-
    setProgress(10);   // means 10% completed ..

8. Error handling and Error Propagation

If a service fails the custom service implementation can throw a ServiceException (Example 4.24, “ServiceException”). The message passed into a ServiceException is propagated back to the client as a part of the metainfo of the response.

Example 4.24. ServiceException

public class ServiceException extends Exception {
    public ServiceException(String message);
    public ServiceException(String message, Throwable cause);
    public ServiceException(Throwable cause);
}

The ServiceException class is a checked exception.

Example: Throwing a ServiceException

The example below shows the use of a ServiceException within the process() method. The presence of an input file is checked and if it is missing an exception is thrown.

import csip.*;

public class V_1 extends ModelDataService {

    public void process() throws Exception {
        //..
        File f = getResourceFile("dem.asc");
        if (f==null) {
           throw new ServiceException("Missing input DEM input file");
        }
        // ...
    }
}

The exception appears in the client response in the response metainfo as an exception message. This is shown below.

{
   "metainfo" : {
       status: "Failed",
       error: "Missing input DEM input file"
       ...
   }
   "parameter" : [
       ...
   ]
}

If the status of a service run is "Failed", an error message can always be found. A client can check the status code and the content of the "error" entry.

If an unchecked exception occurs during service execution, the error value will be the full stack trace.

8.1. Logging

Logging is enabled and configured by default for each CSIP session. The session ID (suid) is used to identify the logging output. This support separation and filtering of logging by session. The CSIP configuration property "csip.logging.enabled" is a boolean that can modified at any time to disable or enable logging.

The ModelDataService class provides a protected logger called "LOG" that can be accessed in a custom service implementation Example 4.25, “Logging Example”. The LOG field is final, thus it cannot be altered. The default log level is set to "INFO", however it can be set using the configuration property "csip.logging.level". Table 5.1, “CSIP System Properties” describes all logging related properties in detail.

Example 4.25. Logging Example

public void process() throws Exception {
    //...
    if (LOG.isLoggable(Level.INFO) {
        LOG.info("connecting do database ...");
    }
    // ..


CSIP uses standard Java logging. Predefined log levels include: OFF, ALL, SEVERE, WARNING, INFO, CONFIG, FINE, FINER, FINEST.

Logging information can be captured using a separate server as it is described in Section 2.5, “Multi-Server Deployment”. The session user interface provides a link to the log record for each individual session. This way logging information can be obtained from any client for debugging and tracing purposes without having direct access to the application server. Logging for a CSIP deployment is centrally configured. Each CSIP deployment can specify its own logging infrastructure configuration.

Chapter 5. CSIP Infrastructure

This chapter provides an overview of different deployment alternatives for the CSIP infrastructure. CSIP infrastructure requirements depend on development preferences and service hosting requirements (e.g. service compute, disk, and network I/O requirements) CSIP may be deployed for development using Linux, Windows, or Mac OS X. For production deployment Linux or Windows are preferred.

The following components are required to run CSIP

For a highly scalable CSIP environment it is recommended to use a software or hardware load balancer. Load balancers serve as an HTTP proxy to distribute requests across multiple CSIP servers. HAProxy is a popular software load balancer.

1. CSIP Configurations

CSIP configuration is property based. Properties control the internal behavior of CSIP and allow administrator(s) to adjust configuration according to infrastructure constraints, scalability, fail-over requirements, development needs, and architecture partitioning strategies.

1.1. Configuration properties

The table below lists CSIP properties that can be customized for specific CSIP deployments .

Table 5.1. CSIP System Properties

KeyDefault ValueDescription
Session  
csip.session.backendhazelcastThe backend to use for session management. Valid choices are hazelcast or redis. If set to hazelcast no further configuration is needed. If set to redis the properties csip.session.redis.server and csip.redis.session.port can be used to control the redis connectivity for session management.
csip.session.redis.serverlocalhostThe hostname or address of the redis server for session management. The property csip.session.backend has to be set to redis to use this setting.
csip.session.redis.port6379The port of the redis server for session management. The property csip.session.backend has to be set to redis to use this setting.
csip.session.ttl300The default time in seconds for a session to stay active after the model finishes. All model results will be available for that period. After this period expires the session will be removed and the model results will be removed or archived. This value can be altered using the "keep_results" metainfo value of a request.
Archive  
csip.archive.enabledfalseIf this property is set to true, the model request/results session data will be archived to a redis server. If set to false the model results are removed only. Only redis is supported for session archival.
csip.archive.serverlocalhostThe hostname/ipadress for the redis archive server. The property csip.archive.enabled has to be set to true to use this setting.
csip.archive.port6379The port for the redis archive server. The property "csip.archive.enabled" has to be set to true to use this setting.
csip.archive.ttl86400The default time in seconds for an entry to stay in the archive. All archived model results will be retained for the TTL period after the session expired. After expiration the archive will be removed, a value of -1 specifies no expiration, the archive entry stays forever. 3600 - one hour, 86400 - one day, 604800 - one week 2592000 - one month, etc.
Logging  
csip.logging.enabledfalseIf set to true remote service logging will be enabled and a specific log handler submits the log for each session to a redis server instance. Only redis is supported as the remote logging server. Log records are always sent to Tomcat (local) regardless of the setting of this property.
csip.logging.levelINFOThe log level for remote service logging. This is only used if csip.logging.enabled is set to true. All java.util.logging.Level log levels are usable.
csip.logging.serverlocalhostThe remote logging server hostname or ip address. This is only used if csip.logging.enabled is set to true.
csip.logging.port6379The remote logging server port. This is only used if csip.logging.enabled is set to true.
csip.logging.ttl86400The time to live for a log entry within the remote logging server in seconds. A value of "-1" indicates no expiration.
csip.logging.keepseverefalseIf set to true, a LOG will never expire in the log store for that session if it contains a "SEVERE" log entry regardless of the "csip.logging.ttl" value.
Directories  
csip.dir/tmp/csipThe CSIP home directory
csip.bin.dir/tmp/csip/binThe CSIP directories for executable.
csip.work.dir/tmp/csip/workThe CSIP directory for sessions.
csip.results.dir/tmp/csip/resultsThe CSIP directory to store results.
csip.cache.dir/tmp/csip/cacheThe CSIP cache file directory.
csip.data.dir/tmp/csip/dataThe CSIP data directory.
Miscellaneous  
csip.timezoneMST7MDTThe default CSIP timezone to be used for all time management.
csip.ui.enabledtrueIf set to false, no service UI for sessions, logging, and archives are provided.
csip.redis.timeout0The connection timeout for all redis connections.
csip.hazelcast.attempt.period10000The period between two Hazelcast connection attempts in milliseconds
csip.hazelcast.attempt.limit10The max number of Hazelcast connection attempts.
csip.hazelcast.group.namecsipThe Hazelcast group configuration name to use.
csip.hazelcast.group.passwordcsip-passThe Hazelcast group password to use.
csip.hazelcast.serverfalseIf set to true, this CSIP instance will start and use its own internal hazelcast server. The csip.hazelcast.group.password and csip.hazelcast.group.name setting for Hazelcast are used for the group configuration. The network configuration defaults to multicast.


1.2. Changing the Configuration

It is recommended to perform configuration changes right after context loading and before any the first CSIP service request is made. Changes of the session backend are only supported at initialization to avoid inconsistencies for session management.

Property changes should be described in a JSON file containing proper key/value pairs, according to Example 5.1, “Example CSIP configuration file (service-conf.json)”. An HTTP/POST request is used to load the JSON config file and apply the settings to the CSIP server.

Example 5.1. Example CSIP configuration file (service-conf.json)

{     
    "csip.session.backend" : "redis",
    "csip.session.redis.server" : "192.168.1.100",
    "csip.session.ttl" : 600
}


All property values can be passed in as native types or as a string. The entry csip.session.ttl can be set with 600 or "600".

The curl command below performs the configuration update by issuing the HTTP POST request with the file service-conf.json. The service path to be used is always "../c/conf".

$ curl -X POST -d @service-conf.json http://localhost:8080/csip-test/c/conf

The configuration service returns the current configuration or an error message.

2. Deployments

This section shows typical configurations for different CSIP deployments highlighting development and deployment of CSIP services using various environments. If a single server deployment is chosen, all packages have to be installed on the same machine. A multi-server deployment should be used for production level deployments to support separation of infrastructure components to ensure redundancy, fail over, and scalability. Infrastructure components are partitioned to reside on separate machines to eliminate resource contention.

2.1. Simplest Single Server Deployment

On a single server deployment all CSIP components run on the same server. Sessions are managed using the Hazelcast backend and remain available for 10 minutes after compleition. Session archival and logging are not enabled. This is the default CSIP deployment configuration.

Figure 5.1. Singe server deployment

Singe server deployment


Example 5.2. Single Server Deployment

{     
    "csip.session.backend" : "hazelcast",
    "csip.session.ttl" : "600",
    "csip.logging.enabled" : false,
    "csip.archive.enabled" : false,
    "csip.hazelcast.server" : true
}

This CSIP instance uses an internal hazelcast server for session management. There is no need to start and manage it manually.

Server Configuration

Server A (localhost)

Tomcat, Hazelcast

2.2. Single Server Deployment with Archival

In this single server configuration all sessions are managed using the redis backend and will stay available for 5 minutes after finish. Session are archived to the redis server after 5 minutes. Logging is disabled.

Figure 5.2. Singe server deployment

Singe server deployment

The configuration is shown below.

Example 5.3. Single Server Deployment (ii)

{     
    "csip.session.backend" : "redis",
    "csip.session.redis.server" : "10.0.1.100",
    "csip.session.ttl" : "300",
    "csip.archive.enabled" : true,
    "csip.archive.server" : "10.0.1.100"
    "csip.archive.ttl" : 604800
}

Archived session data is retained for a week (604800 sec) before deletion.

Server Configuration

Server A (10.0.1.100)

tomcat, Redis

2.3. Single Server Deployment with Logging

In this single server configuration all sessions are managed using the redis backend and will stay available for 5 minutes. Session data is deleted afterwards. Logging is enabled.

Figure 5.3. Singe-Server Deployment for Development

Singe-Server Deployment for Development


Example 5.4. Single-Server Deployment for Development

{     
    "csip.session.backend" : "redis",
    "csip.session.redis.server" : "10.0.1.100",
    "csip.session.ttl" : "600"
    "csip.archive.enabled" : false,
    "csip.logging.enabled" : true
    "csip.logging.server" : 10.0.1.100,
    "csip.logging.level" : ALL,
}

This single server configuration is suitable for local development of CSIP services since archives are not required. The log level is set to ALL to capture all logging output. If development occurs on the local machine, the ~.server properties can be set to localhost.

Server Configuration

Server A (10.0.1.100)

Tomcat CSIP , Redis

2.4. Single Server Deployment with Archival and Logging

In this single server configuration all sessions are managed using the Redis backend and stay available for 10 minutes after completion. Sessions are archived to the local Redis server. Logging is enabled.

Figure 5.4. Single-Server Deployment with Archival

Single-Server Deployment with Archival

The CSIP configuration is shown below.

Example 5.5. Single-Server Deployment with Archival

{     
    "csip.session.backend" : "redis",
    "csip.session.redis.server" : "10.0.1.100",
    "csip.session.ttl" : "600"
    "csip.archive.enabled" : true,
    "csip.archive.server" : 10.0.1.100,
    "csip.archive.ttl" : -1,
    "csip.logging.enabled" : true,
    "csip.logging.server" : 10.0.1.100,
    "csip.logging.level" : WARNING,
}

This single server configuration is most suitable for local deployment of CSIP services. The log level is set to WARNING to capture only relevant logging output. Note that the same Redis instance is used for session management, archival, and logging. This simplifies data management but may represent a bottleneck when service traffic is high. Redis memory resources should be carefully monitored since archive entries will not expire.

Server Configuration

Server A (10.0.1.100)

Tomcat CSIP, Redis

2.5. Multi-Server Deployment

Multi-server deployment addresses production needs such as scalability and fail over. Infrastructure components are partitioned so that they reside on separate machines to eliminate resource contention.

Figure 5.5. Multi-Server Deployment: separate Logging and Archival

Multi-Server Deployment: separate Logging and Archival

Typically multiple CSIP servers are used to service modeling and data service requests. The configuration below uses one Tomcat and two Redis servers for session management, archival, and logging.

Example 5.6. Multi-Server Deployment: separate Logging and Archival

{     
    "csip.session.backend" : "redis",
    "csip.session.redis.server" : "10.0.1.101",
    "csip.session.ttl" : "600"
    "csip.archive.enabled" : true,
    "csip.archive.server" : 10.0.1.101,
    "csip.archive.ttl" : -1,
    "csip.logging.enabled" : true,
    "csip.logging.server" : 10.0.1.102,
    "csip.logging.level" : WARNING,
}


The archive entries never expire, only warning messages are logged.

Server Configuration

Server A (10.0.1.100)

Tomcat CSIP

Server B (10.0.1.101)

Redis (session, archive)

Server C (10.0.1.102)

Redis (logging)

2.6. Scalable Deployment (Multiple Server)

A typical production level deployment accounts for scalability, fail over, and redundancy of resources. CSIP can be configured to cover all of those aspects.

Figure 5.6. Multi Server Deployment in Production

Multi Server Deployment in Production

2.7. Validating the Configuration

[TBD]

2.8. Tips / Best Practices / FAQ

Do I have to restart CSIP when I restart hazelcast?

No, hazelcast will reconnect to a running CSIP instance.

How do I delete keys for all logging entries in Redis?
# This operation erases log entries from Redis
$ redis-cli keys "log:*" | xargs redis-cli DEL
How do I list all archive keys in Redis?
$ redis-cli keys "archive:*"
How do I flush all keys?
# This operation erases all redis server content
$ redis-cli flushall

3. ModelServices User Interface

CSIP provides a web-based user interface to monitor services. This includes: (i) current session status, (ii) a view to explore logging and exception information for debugging purposes, (iii) a user interface for managing archives of session data, and (iv) a configuration query which describes the current CSIP configuration.

The session, logging, and archive GUI are always bound to the context of a web application. Only services that are part of that context can be explored here. If logging or archival are disabled for a context, no GUI can be used.

The CSIP property "csip.ui.enabled" controls the general accessibility of the UI for a CSIP context. It defaults to true.

There are three URLs available to access the user interfaces:

http://<host>/<context>/c/session

Shows the current session status for the service context.

http://<host>/<context>/c/logging

Shows all the logging records by session for the given service context.

http://<host>/<context>/c/archive

Shows all archived sessions.

The "c" path element delineates CSIP console requests and actions.

3.1. Session User Interface

The CSIP session UI for a given context can be accessed using the following URL:

GET http://<host>/<context>/c/session

The session UI is shown in Figure 5.7, “Session User Interface”. The table shows all relevant information for a session.

Figure 5.7. Session User Interface

Session User Interface

The first column lists the simulation id (suid) for a given service session with request and response JSON links. The response JSON is available once the session is completes. The status, client IP, and worker node IP is provided followed by the time of the request, the time when the service session (and its output data) will expire, the execution time of the service, and the service end point. Finally, request attachment filenames are listed and the session log is provided.

The rows in this view are colored according to the status. Color changes with the status.

For the request, response, requesting IP address, and log, hyperlinks provide additional information to the user when clicked (e.g. IP geolocation [15], or log listing).

Query parameters can be appended to the session URL to control the appearance of the table. As a default the most recent session is shown on top of this table.

col

The column to sort the table on, e.g. ... ?col=5..., default is 5

order

The direction for sorting, ascending ("a") or descending ("d"), e.g. ..?order=d.., default is "d"

Note that the session view is not updated on a periodic basis. Users van harness browser extensions to refresh the content so often (e.g. every 5 seconds).

3.2. Logging User Interface

The Logging user interface allows access to log records on a "per-session" basis. Sessions are listed with their session id and a link to the log record Figure 5.8, “Logging User Interface”. Note that those sessions are not ordered. A user search for sessions by id can fetch the associated log entry.

Figure 5.8. Logging User Interface

Logging User Interface

The logging UI link is identical to the session UI link. Logging entries do not expire with the session. They remain in the logging server until they are expired based on the value in "csip.logging.ttl", which defaults to 24 hours. Alternatively, they can be deleted explicitly.

3.3. Archive User Interface

The Archive UI provides a complete listing of all archived sessions Figure 5.9, “Archive User Interface”. It shows a table, where each row represents a session archive. The session id (suid), the completion status at the end of service execution, the originating request IP address, the time of archival, the service endpoint, the session files, and a link to the log are provided in each session row.

Figure 5.9. Archive User Interface

Archive User Interface

The archive table can be sorted similar to the session UI using the previously described col/order query parameter in the URL. As a default, archived sessions are sorted by archival date with the most recent archive shown on top.



[14] http://www.redis.io

[15] http://freegeoip.net

Appendix A. ModelServices API

1. Executable

Interface to manage an executable.

1.1. Synopsis

 public interface Executable {
// Public Methods  public abstract Map<String, String> environment();
  public abstract int exec()
    throws IOException;

  public abstract Object[] getArguments();
  public abstract String getName();
  public abstract void redirectError(StringWriter w)
    throws IOException;

  public abstract void redirectError(String filename)
    throws IOException;

  public abstract void redirectOutput(StringWriter w)
    throws IOException;

  public abstract void redirectOutput(String filename)
    throws IOException;

  public abstract void setArguments(Object[] args);
}
Author

od

1.2. environment()

public abstract Map<String, String> environment();

Get the current environment map

Parameters

return

the environment.

1.3. exec()

public abstract int exec()
    throws IOException;

run it.

Parameters

return

0 if successful, !=0 otherwise

Exceptions

java.­io.­IOException

1.4. getArguments()

public abstract Object[] getArguments();

Get the executables arguments

Parameters

return

the arguments

1.5. getName()

public abstract String getName();

Get the name of the executable.

Parameters

return

the name of the executable

1.6. redirectError(String)

public abstract void redirectError(String filename)
    throws IOException;

Redirect stderr to a file in the workspace.

Parameters

filename

the filename to use relative to the workspace.

Exceptions

java.­io.­IOException

1.7. redirectOutput(String)

public abstract void redirectOutput(String filename)
    throws IOException;

Redirect stdout to a file in the workspace.

Parameters

filename

the filename to use relative to the workspace.

Exceptions

java.­io.­IOException

1.8. setArguments(Object...)

public abstract void setArguments(Object[] args);

Set the executable arguments.

Parameters

args

the executable arguments

2. Model­Data­Service

Base class for all modeling and data services. A service implementation will subclass ModelDataService.

2.1. Synopsis

 public abstract class ModelDataService {
// Public Static Fields  public static final String ASYNC = "async";
  public static final String CANCELED = "Canceled";
  public static final String DESCR = "descr";
  public static final String ERROR = "error";
  public static final String EXEC_FAILED = "Error";
  public static final String EXEC_OK ;
  public static final String FAILED = "Failed";
  public static final String FINISHED = "Finished";
  public static final String FORM_PARAM = "param";
  public static final String GEOMETRY = "geometry";
  public static final String IN = "in";
  public static final String INTENT = "intent";
  public static final String KEY_CLOUD_NODE = "cloud_node";
  public static final String KEY_CPU_TIME = "cpu_time";
  public static final String KEY_DESC = "description";
  public static final String KEY_EXPIRATION_DATE = "expiration_date";
  public static final String KEY_FIRST_POLL = "first_poll";
  public static final String KEY_KEEP_RESULTS = "keep_results";
  public static final String KEY_METAINFO = "metainfo";
  public static final String KEY_MODE = "mode";
  public static final String KEY_NAME = "name";
  public static final String KEY_NEXT_POLL = "next_poll";
  public static final String KEY_PARAMETER = "parameter";
  public static final String KEY_PARAMETERSETS = "parametersets";
  public static final String KEY_PROGRESS = "progress";
  public static final String KEY_REPORT = "report";
  public static final String KEY_REQUEST_RESULTS = "request-results";
  public static final String KEY_REQ_IP = "request_ip";
  public static final String KEY_RESULT = "result";
  public static final String KEY_SERVICE_URL = "service_url";
  public static final String KEY_STATUS = "status";
  public static final String KEY_SUUID = "suid";
  public static final String KEY_TIME_CLIMATE_QUERY = "timeClimateQuery";
  public static final String KEY_TIME_FILEIO = "timeFileIO";
  public static final String KEY_TIME_LOGGING = "timeLogging";
  public static final String KEY_TIME_MODEL = "timeModel";
  public static final String KEY_TIME_SOIL_QUERY = "timeSoilQuery";
  public static final String KEY_TIME_TOTAL = "timeTotal";
  public static final String KEY_TSTAMP = "tstamp";
  public static final String KEY_TZ = "tz";
  public static final String KEY_UNIT = "unit";
  public static final String KEY_URL = "url";
  public static final String MAX = "max";
  public static final String MIN = "min";
  public static final String OUT = "out";
  public static final String RANGE = "range";
  public static final String REPORT_DESC = "description";
  public static final String REPORT_DIM = "dim";
  public static final String REPORT_DIM0 = "dimension0";
  public static final String REPORT_FILE = "report.json";
  public static final String REPORT_NAME = "name";
  public static final String REPORT_TYPE = "type";
  public static final String REPORT_UNITS = "units";
  public static final String REPORT_VALUE = "value";
  public static final String RUNNING = "Running";
  public static final String SUBMITTED = "Submitted";
  public static final String SYNC = "sync";
  public static final String UNIT = "unit";
  public static final String UNKNOWN = "Unknown";
  public static final String VALUE = "value";
// Public Fields  public Task mt ;
// Protected Fields  protected final Logger LOG ;
  protected String tz ;
// Public Constructors  public ModelDataService();
// Public Methods  @GET @Produces(value="application/json") public final String describeJSON();
  @POST @Produces(value="application/json") @Consumes(value="application/json") public final String execute(UriInfo uriInfo,
                                                                                                            HttpServletRequest req,
                                                                                                            String requestStr);

  @POST @Produces(value="application/json") @Consumes(value="multipart/form-data") public final String execute(UriInfo uriInfo,
                                                                                                               HttpServletRequest httpReq,
                                                                                                               FormDataMultiPart multipart);

  public final void setMetainfo(JSONObject mi);
  public void setParam(JSONArray parameter);
  public final void setParamMap(Map<String, JSONObject> pm);
  public final void setRequest(JSONObject req);
// Protected Methods  @Deprecated protected Callable<String> createCallable()
    throws Exception;

  @Deprecated protected JSONArray createReport()
    throws Exception;

  @Deprecated protected JSONArray createResults()
    throws Exception;

  protected boolean getBooleanMetainfo(String name)
    throws ServiceException;

  protected boolean getBooleanParam(String name)
    throws ServiceException;

  protected boolean getBooleanParam(String name,
                                    boolean def)
    throws ServiceException;

  protected final String getCodebase();
  protected double getDoubleMetainfo(String name)
    throws ServiceException;

  protected double getDoubleParam(String name)
    throws ServiceException;

  protected double getDoubleParam(String name,
                                  double def)
    throws ServiceException;

  protected File getFileInput(String name)
    throws ServiceException;

  protected Set<File> getFileInputs();
  protected int getFileInputsCount();
  protected long getFirstPoll();
  protected int getIntMetainfo(String name)
    throws ServiceException;

  protected int getIntParam(String name)
    throws ServiceException;

  protected int getIntParam(String name,
                            int def)
    throws ServiceException;

  protected JSONObject getJSONParam(String name)
    throws ServiceException;

  protected JSONObject getJSONParam(String name,
                                    JSONObject def)
    throws ServiceException;

  protected long getLongParam(String name)
    throws ServiceException;

  protected long getLongParam(String name,
                              long def)
    throws ServiceException;

  protected final JSONObject getMetainfo();
  protected int getMetainfoCount();
  protected Set<String> getMetainfoNames();
  protected long getNextPoll();
  protected final JSONArray getParam();
  protected int getParamCount();
  protected String getParamDescr(String name)
    throws ServiceException;

  protected JSONObject getParamGeometry(String name)
    throws ServiceException;

  protected final Map<String, JSONObject> getParamMap();
  protected Set<String> getParamNames();
  protected String getParamUnit(String name)
    throws ServiceException;

  protected final String getRemoteAddr();
  protected final JSONObject getRequest();
  protected final String getRequestContext();
  protected final String getRequestHost();
  protected final String getRequestURL();
  protected Executable getResourceExe(String id)
    throws ServiceException;

  protected File getResourceFile(String id)
    throws ServiceException;

  protected final String getSUID();
  protected final String getServicePath();
  protected String getStringMetainfo(String name)
    throws ServiceException;

  protected String getStringParam(String name)
    throws ServiceException;

  protected String getStringParam(String name,
                                  String def)
    throws ServiceException;

  protected final File getWorkspaceDir();
  protected boolean hasFileInput(String name)
    throws ServiceException;

  protected boolean hasMetainfo(String name);
  protected boolean hasParam(String name);
  protected final boolean hasWorkspaceDir();
  protected void postProcess()
    throws Exception;

  @Deprecated protected File[] postprocess()
    throws Exception;

  protected void preProcess()
    throws Exception;

  @Deprecated protected void preprocess()
    throws Exception;

  protected String process()
    throws Exception;

  protected void putReport(File file);
  protected void putReport(File file,
                           String descr);

  protected void putReport(File[] file);
  protected void putReport(String name,
                           boolean val);

  protected void putReport(String name,
                           boolean val,
                           String unit);

  protected void putReport(String name,
                           boolean val,
                           String unit,
                           String descr);

  protected void putReport(String name,
                           double val);

  protected void putReport(String name,
                           double val,
                           String unit);

  protected void putReport(String name,
                           double val,
                           String unit,
                           String descr);

  protected void putReport(String name,
                           int val);

  protected void putReport(String name,
                           int val,
                           String unit);

  protected void putReport(String name,
                           int val,
                           String unit,
                           String descr);

  protected void putReport(String name,
                           String val);

  protected void putReport(String name,
                           String val,
                           String unit);

  protected void putReport(String name,
                           String val,
                           String unit,
                           String descr);

  protected void putReport(String name,
                           JSONObject val);

  protected void putReport(String name,
                           JSONObject val,
                           String unit);

  protected void putReport(String name,
                           JSONObject val,
                           String unit,
                           String descr);

  protected void putResult(File file);
  protected void putResult(File file,
                           String descr);

  protected void putResult(File[] file);
  protected void putResult(String name,
                           boolean val);

  protected void putResult(String name,
                           boolean val,
                           String unit);

  protected void putResult(String name,
                           boolean val,
                           String unit,
                           String descr);

  protected void putResult(String name,
                           double val);

  protected void putResult(String name,
                           double val,
                           String unit);

  protected void putResult(String name,
                           double val,
                           String unit,
                           String descr);

  protected void putResult(String name,
                           int val);

  protected void putResult(String name,
                           int val,
                           String unit);

  protected void putResult(String name,
                           int val,
                           String unit,
                           String descr);

  protected void putResult(String name,
                           String val);

  protected void putResult(String name,
                           String val,
                           String unit);

  protected void putResult(String name,
                           String val,
                           String unit,
                           String descr);

  protected void putResult(String name,
                           JSONObject val);

  protected void putResult(String name,
                           JSONObject val,
                           String unit);

  protected void putResult(String name,
                           JSONObject val,
                           String unit,
                           String descr);

  protected void report()
    throws Exception;

  protected void setProgress(int progress)
    throws ServiceException;

  protected void setProgress(String progress)
    throws ServiceException;

}

Methods inherited from java.lang.Object: clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait

Author

Olaf David

2.2. createCallable()

@Deprecated protected Callable<String> createCallable()
    throws Exception;

Create a callable model run. The callable is returning a string result. The string is 'null' if the model execution succeeded. It is not 'null' if there is an error and the string may contain the error message.

Parameters

return

a callable

Exceptions

Exception

if an error occurred during execution.

Deprecated

overwrite csip.­ModelDataService.­process() instead.

2.3. createReport()

@Deprecated protected JSONArray createReport()
    throws Exception;

Create a report.

Parameters

return

The report content as JSONArray

Exceptions

Exception

2.4. createResults()

@Deprecated protected JSONArray createResults()
    throws Exception;

Step 4: Create the results as JSON, (deprecated)

Parameters

return

the results as an array of JSON objects.

Exceptions

Exception

2.5. describeJSON()

@GET @Produces(value="application/json") public final String describeJSON();

Describe the service as JSON. (Service endpoint only)

Parameters

return

The service signature as JSON

2.6. execute(UriInfo, HttpServletRequest, FormDataMultiPart)

@POST @Produces(value="application/json") @Consumes(value="multipart/form-data") public final String execute(UriInfo uriInfo,
                                                                                                             HttpServletRequest httpReq,
                                                                                                             FormDataMultiPart multipart);

Handler for model services. Multi-part handling. (Service endpoint only)

Parameters

uriInfo

the context info

httpReq

the servlet request

multipart

multi part input.

return

the JSON response as String.

2.7. execute(UriInfo, HttpServletRequest, String)

@POST @Produces(value="application/json") @Consumes(value="application/json") public final String execute(UriInfo uriInfo,
                                                                                                          HttpServletRequest req,
                                                                                                          String requestStr);

Service Handler for non-multipart requests. There are no form parameter, everything is in the body. (Service endpoint only)

Parameters

uriInfo

The UriInfo context

req

tye servlet request

requestStr

the request string

return

the JSON response of the service.

2.8. getBooleanMetainfo(String)

protected boolean getBooleanMetainfo(String name)
    throws ServiceException;

Get a metainfo value as boolean

Parameters

name

the name of the metainfo entry

return

the metaifo value

Exceptions

ServiceException

General Service Exception.

2.9. getBooleanParam(String)

protected boolean getBooleanParam(String name)
    throws ServiceException;

Get a boolean parameter.

Parameters

name

the parameter name.

return

the parameter value as boolean.

Exceptions

ServiceException

General Service Exception.

2.10. getBooleanParam(String, boolean)

protected boolean getBooleanParam(String name,
                                  boolean def)
    throws ServiceException;

Get a Boolean parameter.

Parameters

name

the name of the parameter

def

the default value.

return

the boolean value of the parameter.

Exceptions

ServiceException

General Service Exception.

2.11. getCodebase()

protected final String getCodebase();

Get the codebase without the model service path

Parameters

return

the codebase of the URL as String

2.12. getDoubleMetainfo(String)

protected double getDoubleMetainfo(String name)
    throws ServiceException;

Get the metainfo value as double.

Parameters

name

the name of the metainfo entry

return

the metainfo value.

Exceptions

ServiceException

General Service Exception.

2.13. getDoubleParam(String)

protected double getDoubleParam(String name)
    throws ServiceException;

Get an double parameter

Parameters

name

the parameter name

return

the parameter value as double

Exceptions

ServiceException

General Service Exception.

2.14. getDoubleParam(String, double)

protected double getDoubleParam(String name,
                                double def)
    throws ServiceException;

Get a double parameter.

Parameters

name

the name of the parameter

def

the default value if parameter does not exist

return

the double value of the parameter

Exceptions

ServiceException

General Service Exception.

2.15. getFileInput(String)

protected File getFileInput(String name)
    throws ServiceException;

Get a file object for a given file name.

Parameters

name

the file name (no path)

return

the file object with its absolute file path within the workspace. It returns null if the file is not input or does not exist.

Exceptions

csip.­ServiceException

General Service Exception.

2.16. getFileInputs()

protected Set<File> getFileInputs();

Get the attached files for this request. This includes the request.

Parameters

return

The set of files.

2.17. getFileInputsCount()

protected int getFileInputsCount();

Get the number of attachments. This includes the request.

Parameters

return

the number of files attached.

2.18. getFirstPoll()

protected long getFirstPoll();

Get the time until first poll for async calls in milliseconds.

Parameters

return

time to first poll in milliseconds

2.19. getIntMetainfo(String)

protected int getIntMetainfo(String name)
    throws ServiceException;

Get metainfo value as int.

Parameters

name

the name of the metainfo entry

return

the int value of a metainfo entry.

Exceptions

ServiceException

General Service Exception.

2.20. getIntParam(String)

protected int getIntParam(String name)
    throws ServiceException;

Get an int parameter.

Parameters

name

the parameter name

return

the parameter value as int

Exceptions

ServiceException

General Service Exception.

2.21. getIntParam(String, int)

protected int getIntParam(String name,
                          int def)
    throws ServiceException;

Get a int parameter.

Parameters

name

the name of the parameter

def

the default value if parameter does not exist

return

the int value of the parameter.

Exceptions

ServiceException

General Service Exception.

2.22. getJSONParam(String)

protected JSONObject getJSONParam(String name)
    throws ServiceException;

Get a JSONObject parameter.

Parameters

name

the parameter name.

return

the parameter value as JSONObject.

Exceptions

ServiceException

General Service Exception.

2.23. getJSONParam(String, JSONObject)

protected JSONObject getJSONParam(String name,
                                  JSONObject def)
    throws ServiceException;

Get a Long parameter.

Parameters

name

the name of the parameter

def

the default value if parameter does not exist

return

the JSONObject of the parameter

Exceptions

ServiceException

General Service Exception.

2.24. getLongParam(String)

protected long getLongParam(String name)
    throws ServiceException;

Get a long parameter.

Parameters

name

the parameter name.

return

the parameter value as long.

Exceptions

ServiceException

General Service Exception.

2.25. getLongParam(String, long)

protected long getLongParam(String name,
                            long def)
    throws ServiceException;

Get a Long parameter.

Parameters

name

the name of the parameter

def

the default value if parameter does not exist

return

the long value of the parameter

Exceptions

ServiceException

General Service Exception.

2.26. getMetainfo()

protected final JSONObject getMetainfo();

Get the request metainfo.

Parameters

return

the metainfo

2.27. getMetainfoCount()

protected int getMetainfoCount();

Get the number of metainfo entries.

Parameters

return

the number of entries.

2.28. getMetainfoNames()

protected Set<String> getMetainfoNames();

Get all metainfo names.

Parameters

return

the set of metainfo names.

2.29. getNextPoll()

protected long getNextPoll();

Return the recommended polling interval for async calls in milliseconds.

Parameters

return

the polling interval value in milliseconds

2.30. getParam()

protected final JSONArray getParam();

Get the request parameter

Parameters

return

request parameter

2.31. getParamCount()

protected int getParamCount();

Get the number of parameter.

Parameters

return

the number of parameter

2.32. getParamDescr(String)

protected String getParamDescr(String name)
    throws ServiceException;

Get the description of a parameter.

Parameters

name

the parameter name

return

the description as string, 'null' if there is none.

Exceptions

ServiceException

General Service Exception.

2.33. getParamGeometry(String)

protected JSONObject getParamGeometry(String name)
    throws ServiceException;

Get the geometry of a parameter

Parameters

name

the name if the parameter

return

the geometry of a parameter

Exceptions

ServiceException

General Service Exception.

2.34. getParamMap()

protected final Map<String, JSONObject> getParamMap();

Get the Parameter as map "name" -> JSONObject

Parameters

return

the parameter map

2.35. getParamNames()

protected Set<String> getParamNames();

Get all parameter names.

Parameters

return

the set of names.

2.36. getParamUnit(String)

protected String getParamUnit(String name)
    throws ServiceException;

Get the unit of a parameter.

Parameters

name

the parameter name

return

the unit as string, 'null' if there is none.

Exceptions

ServiceException

General Service Exception.

2.37. getRemoteAddr()

protected final String getRemoteAddr();

The request ip

Parameters

return

the request ip

2.38. getRequest()

protected final JSONObject getRequest();

Get the original JSOn request object.

Parameters

return

the request object.

2.39. getRequestContext()

protected final String getRequestContext();

Get the webapp context name.

Parameters

return

the context name

2.40. getRequestHost()

protected final String getRequestHost();

Get the complete request URL

Parameters

return

the full request URL

2.41. getRequestURL()

protected final String getRequestURL();

Get the complete request URL

Parameters

return

the full request URL

2.42. getResourceExe(String)

protected Executable getResourceExe(String id)
    throws ServiceException;

Get an service executable from a resource definition. Resources are defined as service annotations.

Parameters

id

the id of the resource

return

the ProcessExecution for that executable

Exceptions

ServiceException

General Service Exception.

2.43. getResourceFile(String)

protected File getResourceFile(String id)
    throws ServiceException;

Get a service resource file. Resources are defined as service annotations.

Parameters

id

the id of the resource.

return

the extracted file within the local file system.

Exceptions

ServiceException

General Service Exception.

2.44. getServicePath()

protected final String getServicePath();

Provide the service path name, e.­g. 'weps/1.­0'

Parameters

return

the model service path

2.45. getStringMetainfo(String)

protected String getStringMetainfo(String name)
    throws ServiceException;

Get the metainfo value as String.

Parameters

name

the name of the metainfo entry

return

the value of a metainfo entry

Exceptions

ServiceException

General Service Exception.

2.46. getStringParam(String)

protected String getStringParam(String name)
    throws ServiceException;

Get a String parameter

Parameters

name

the parameter name

return

the parameter value as String

Exceptions

ServiceException

General Service Exception.

2.47. getStringParam(String, String)

protected String getStringParam(String name,
                                String def)
    throws ServiceException;

Get a String parameter.

Parameters

name

the name of the parameter

def

the default value if the parameter is missing

return

the value of the parameter

Exceptions

ServiceException

General Service Exception.

2.48. getSUID()

protected final String getSUID();

Get the simulation unique identifier (128 byte UUID)

Parameters

return

the suid string

2.49. getWorkspaceDir()

protected final File getWorkspaceDir();

Get a new Workspace folder for this model run. returns null if it has no simulation folder.

Parameters

return

the workspace or null if there should be none.

2.50. hasFileInput(String)

protected boolean hasFileInput(String name)
    throws ServiceException;

Check is a input file exists in the workspace.

Parameters

name

the file name

return

true if the file exist, false otherwise

Exceptions

ServiceException

General Service Exception.

2.51. hasMetainfo(String)

protected boolean hasMetainfo(String name);

Check if a metainfo entry exists.

Parameters

name

the name of a metainfo name.

return

true if a metainfo entry exists, false otherwise

2.52. hasParam(String)

protected boolean hasParam(String name);

Check if a parameter exists.

Parameters

name

the name of the parameter entry

return

true if present false otherwise.

2.53. hasWorkspaceDir()

protected final boolean hasWorkspaceDir();

Indicate if the service needs a workspace folder (as sandbox)

Parameters

return

true if it is needed, false otherwise.

2.54. postprocess()

@Deprecated protected File[] postprocess()
    throws Exception;

workflow step 3: Postprocess the data.

Parameters

return

The filenames that should be transferred into the results folder

Exceptions

Exception

Deprecated

overwrite csip.­ModelDataService.­postProcess() instead.

2.55. postProcess()

protected void postProcess()
    throws Exception;

workflow step 3: create the response the data.

Exceptions

Exception

2.56. preprocess()

@Deprecated protected void preprocess()
    throws Exception;

workflow step 1: Preprocess the data.

Exceptions

Exception

2.57. preProcess()

protected void preProcess()
    throws Exception;

workflow step 1: process the request data.

Exceptions

Exception

2.58. process()

protected String process()
    throws Exception;

Process logic of the service.

Parameters

return

null if the process ended successfully, the error message otherwise.

Exceptions

Exception

2.59. putReport(File...)

protected void putReport(File[] file);

Put Files into a report.

Parameters

file

the files to report

2.60. putReport(File)

protected void putReport(File file);

Put a File into a report.

Parameters

file

the file to report

2.61. putReport(File, String)

protected void putReport(File file,
                         String descr);

Put a File into a report.

Parameters

file

the file

descr

a description

2.62. putReport(String, boolean)

protected void putReport(String name,
                         boolean val);

Put a boolean value into a report.

Parameters

name

the result name

val

the value to store

2.63. putReport(String, boolean, String)

protected void putReport(String name,
                         boolean val,
                         String unit);

Put a boolean value into a report.

Parameters

name

the result name

val

the value to store

unit

the physical unit

2.64. putReport(String, boolean, String, String)

protected void putReport(String name,
                         boolean val,
                         String unit,
                         String descr);

Put a boolean value into a report.

Parameters

name

the result name

val

the value to store

unit

the physical unit

descr

a description

2.65. putReport(String, double)

protected void putReport(String name,
                         double val);

Put a double value into a report.

Parameters

name

the result name

val

the value to store

2.66. putReport(String, double, String)

protected void putReport(String name,
                         double val,
                         String unit);

Put a double value into a report.

Parameters

name

the result name

val

the value to store

unit

the physical unit

2.67. putReport(String, double, String, String)

protected void putReport(String name,
                         double val,
                         String unit,
                         String descr);

Put a double value into a report.

Parameters

name

the result name

val

the value to store

unit

the physical unit

descr

a description

2.68. putReport(String, int)

protected void putReport(String name,
                         int val);

Put a int value into a report.

Parameters

name

the result name

val

the value to store

2.69. putReport(String, int, String)

protected void putReport(String name,
                         int val,
                         String unit);

Put a int value into a report.

Parameters

name

the result name

val

the value to store

unit

the physical unit

2.70. putReport(String, int, String, String)

protected void putReport(String name,
                         int val,
                         String unit,
                         String descr);

Put a int value into a report.

Parameters

name

the result name

val

the value to store

unit

the physical unit

descr

a description

2.71. putReport(String, JSONObject)

protected void putReport(String name,
                         JSONObject val);

Put a JSONObject value into a report.

Parameters

name

the result name

val

the value to store

2.72. putReport(String, JSONObject, String)

protected void putReport(String name,
                         JSONObject val,
                         String unit);

Put a JSONObject value into a report.

Parameters

name

the result name

val

the value to store

unit

the physical unit

2.73. putReport(String, JSONObject, String, String)

protected void putReport(String name,
                         JSONObject val,
                         String unit,
                         String descr);

Put a JSONObject value into a report.

Parameters

name

the result name

val

the value to store

unit

the physical unit

descr

a description

2.74. putReport(String, String)

protected void putReport(String name,
                         String val);

Put a String value into a report.

Parameters

name

the result name

val

the value to store

2.75. putReport(String, String, String)

protected void putReport(String name,
                         String val,
                         String unit);

Put a String value into a report.

Parameters

name

the result name

val

the value to store

unit

the physical unit

2.76. putReport(String, String, String, String)

protected void putReport(String name,
                         String val,
                         String unit,
                         String descr);

Put a String value into a report.

Parameters

name

the result name

val

the value to store

unit

the physical unit

descr

a description

2.77. putResult(File...)

protected void putResult(File[] file);

Provide multiple files as a result.

Parameters

file

the files to add as a result

2.78. putResult(File)

protected void putResult(File file);

Provide a file as a result.

Parameters

file

the file result

2.79. putResult(File, String)

protected void putResult(File file,
                         String descr);

Provide a file with description as a result.

Parameters

file

descr

2.80. putResult(String, boolean)

protected void putResult(String name,
                         boolean val);

Provide a boolean as a result.

Parameters

name

the result name

val

the value to store

2.81. putResult(String, boolean, String)

protected void putResult(String name,
                         boolean val,
                         String unit);

Provide a boolean as a result.

Parameters

name

the result name

val

the value to store

unit

the physical unit

2.82. putResult(String, boolean, String, String)

protected void putResult(String name,
                         boolean val,
                         String unit,
                         String descr);

Provide a boolean as a result.

Parameters

name

the result name

val

the value to store

unit

the physical unit

descr

a description

2.83. putResult(String, double)

protected void putResult(String name,
                         double val);

Provide a double as a result.

Parameters

name

the result name

val

the value to store

2.84. putResult(String, double, String)

protected void putResult(String name,
                         double val,
                         String unit);

Provide a double as a result.

Parameters

name

the result name

val

the value to store

unit

the physical unit

2.85. putResult(String, double, String, String)

protected void putResult(String name,
                         double val,
                         String unit,
                         String descr);

Provide a double as a result.

Parameters

name

the result name

val

the value to store

unit

the physical unit

descr

a description

2.86. putResult(String, int)

protected void putResult(String name,
                         int val);

Provide an int as a result.

Parameters

name

the result name

val

the value to store

2.87. putResult(String, int, String)

protected void putResult(String name,
                         int val,
                         String unit);

Provide an int as a result.

Parameters

name

the result name

val

the value to store

unit

the physical unit

2.88. putResult(String, int, String, String)

protected void putResult(String name,
                         int val,
                         String unit,
                         String descr);

Provide an int as a result.

Parameters

name

the result name

val

the value to store

unit

the physical unit

descr

a description

2.89. putResult(String, JSONObject)

protected void putResult(String name,
                         JSONObject val);

Provide a JSONObject as a result.

Parameters

name

the result name

val

the value to store

2.90. putResult(String, JSONObject, String)

protected void putResult(String name,
                         JSONObject val,
                         String unit);

Provide a JSONObject as a result.

Parameters

name

the result name

val

the value to store

unit

the physical unit

2.91. putResult(String, JSONObject, String, String)

protected void putResult(String name,
                         JSONObject val,
                         String unit,
                         String descr);

Provide a JSONObject as a result.

Parameters

name

the result name

val

the value to store

unit

the physical unit

descr

a description

2.92. putResult(String, String)

protected void putResult(String name,
                         String val);

Provide a string as a result.

Parameters

name

the result name

val

the value to store

2.93. putResult(String, String, String)

protected void putResult(String name,
                         String val,
                         String unit);

Provide a string as a result.

Parameters

name

the result name

val

the value to store

unit

the physical unit

2.94. putResult(String, String, String, String)

protected void putResult(String name,
                         String val,
                         String unit,
                         String descr);

Provide a string as a result.

Parameters

name

the result name

val

the value to store

unit

the physical unit

descr

a description

2.95. report()

protected void report()
    throws Exception;

Create a report.

Exceptions

Exception

2.96. setMetainfo(JSONObject)

public final void setMetainfo(JSONObject mi);

Set the request metainfo.

Deprecated

Deprecated

2.97. setParam(JSONArray)

public void setParam(JSONArray parameter);

Set the request parameter.

Deprecated

Deprecated

2.98. setParamMap(Map<String, JSONObject>)

public final void setParamMap(Map<String, JSONObject> pm);

Set the Parameter map

Deprecated

Deprecated

2.99. setProgress(int)

protected void setProgress(int progress)
    throws ServiceException;

Set the progress as a numerical value (0.­.100)

Parameters

progress

a value between 0 and 100;

Exceptions

ServiceException

General Service Exception.

2.100. setProgress(String)

protected void setProgress(String progress)
    throws ServiceException;

Set the progress as a string message. Call this message during process() to indicate progress for long running models. If the service is called asynchronously the message will be reported in the metainfo part of the rest call as the 'progress' entry.

Parameters

progress

a meaningful message

Exceptions

ServiceException

General Service Exception.

2.101. setRequest(JSONObject)

public final void setRequest(JSONObject req);

Set the request

Deprecated

Deprecated

3. Model­Data­Service.­Task

Model execution Task.

3.1. Synopsis

 public final class ModelDataService.Task extends, Thread {
// Public Constructors  public Task(Callable<String> call);
// Public Methods  public void run();
  public String toString();
}

Methods inherited from java.lang.Thread: activeCount, checkAccess, clone, countStackFrames, currentThread, destroy, dumpStack, enumerate, getAllStackTraces, getContextClassLoader, getDefaultUncaughtExceptionHandler, getId, getName, getPriority, getStackTrace, getState, getThreadGroup, getUncaughtExceptionHandler, holdsLock, interrupt, interrupted, isAlive, isDaemon, isInterrupted, join, resume, run, setContextClassLoader, setDaemon, setDefaultUncaughtExceptionHandler, setName, setPriority, setUncaughtExceptionHandler, sleep, start, stop, suspend, toString, yield

Methods inherited from java.lang.Object: equals, finalize, getClass, hashCode, notify, notifyAll, wait

Fields inherited from java.lang.Thread: MAX_PRIORITY, MIN_PRIORITY, NORM_PRIORITY

4. Service­Exception

1. Resource

Resource definition.

1.1. Synopsis

 @Retention(value=java.lang.annotation.RetentionPolicy.RUNTIME) @Target(value=java.lang.annotation.ElementType.TYPE) public @interface Resource {
  public String file ;
  public ResourceType type ;
  public String id ;
  public boolean wine ;
  public String args ;
  public String env ;
}
Author

od

1.2. args

Default executable arguments, separated by space

Parameters

return

the executable arguments

1.3. env

Default environment variables to be used for execution. ("env1=abc env2=def"}

Parameters

return

the environment variables for execution.

1.4. file

The path to the file within the war file or file system.

Parameters

return

the relative path to the file in the war or on the absolute path in the file system.

1.5. id

The id of that resource. Set it only if you want to access the resource.

Parameters

return

the id of that resource

See Also

csip.­AbstractModelService#getResourceExe(java.­lang.­String)

,

csip.­AbstractModelService#getResourceFile(java.­lang.­String)

1.6. type

The type of the resource. F

Parameters

return

the specific type of the resource.

1.7. wine

Should the file executed via wine.

Parameters

return

true if executed via wine, false otherwise.

General Service Exception.

4.1. Synopsis

 public class ServiceException extends, Exception {
// Public Constructors  public ServiceException(String message);
  public ServiceException(String message,
                          Throwable cause);

  public ServiceException(Throwable cause);
}

Methods inherited from java.lang.Throwable: addSuppressed, fillInStackTrace, getCause, getLocalizedMessage, getMessage, getStackTrace, getSuppressed, initCause, printStackTrace, setStackTrace, toString

Methods inherited from java.lang.Object: clone, equals, finalize, getClass, hashCode, notify, notifyAll, wait

Author

Olaf David

4.2. ServiceException(String)

public ServiceException(String message);

Exception Constructor

Parameters

message

the exception message

4.3. ServiceException(String, Throwable)

public ServiceException(String message,
                        Throwable cause);

Exception Constructor

Parameters

message

cause

4.4. ServiceException(Throwable)

public ServiceException(Throwable cause);

exception Constructor.

Parameters

cause

5. Resource

Resource definition.

5.1. Synopsis

 @Retention(value=java.lang.annotation.RetentionPolicy.RUNTIME) @Target(value=java.lang.annotation.ElementType.TYPE) public @interface Resource {
  public String file ;
  public ResourceType type ;
  public String id ;
  public boolean wine ;
  public String args ;
  public String env ;
}
Author

od

5.2. args

Default executable arguments, separated by space

Parameters

return

the executable arguments

5.3. env

Default environment variables to be used for execution. ("env1=abc env2=def"}

Parameters

return

the environment variables for execution.

5.4. file

The path to the file within the war file or file system.

Parameters

return

the relative path to the file in the war or on the absolute path in the file system.

5.5. id

The id of that resource. Set it only if you want to access the resource.

Parameters

return

the id of that resource

See Also

csip.­AbstractModelService#getResourceExe(java.­lang.­String)

,

csip.­AbstractModelService#getResourceFile(java.­lang.­String)

5.6. type

The type of the resource. F

Parameters

return

the specific type of the resource.

5.7. wine

Should the file executed via wine.

Parameters

return

true if executed via wine, false otherwise.

6. Resource­Type

Resource types.

6.1. Synopsis

 public final class ResourceType extends, Enum<ResourceType> {
// Public Static Fields  public static final ResourceType ARCHIVE ;
  public static final ResourceType CLASSNAME ;
  public static final ResourceType EXECUTABLE ;
  public static final ResourceType FILE ;
  public static final ResourceType JAR ;
  public static final ResourceType OMS_DSL ;
  public static final ResourceType OUTPUT ;
  public static final ResourceType REFERENCE ;
// Public Static Methods  public static ResourceType valueOf(String name);
  public static ResourceType[] values();
}

Methods inherited from java.lang.Enum: clone, compareTo, equals, finalize, getDeclaringClass, hashCode, name, ordinal, toString, valueOf

Methods inherited from java.lang.Object: getClass, notify, notifyAll, wait

Author

od

6.2. ARCHIVE

public static final ResourceType ARCHIVE ;

This resource is a zip file and it should be unpacked.

6.3. CLASSNAME

public static final ResourceType CLASSNAME ;

This is a file is a java class name.

6.4. EXECUTABLE

public static final ResourceType EXECUTABLE ;

This resource is a executable.

6.5. FILE

public static final ResourceType FILE ;

This resource is a file.

6.6. JAR

public static final ResourceType JAR ;

This is a file is a jar file.

6.7. OMS_DSL

public static final ResourceType OMS_DSL ;

This is a file is a OMS DSL file.

6.8. OUTPUT

public static final ResourceType OUTPUT ;

The resource describes output of the model service.

6.9. REFERENCE

public static final ResourceType REFERENCE ;

This is a file reference to an existing file. Nothing should be extracted.

7. Resources

Describe the resources bundled with the service.

7.1. Synopsis

 @Retention(value=java.lang.annotation.RetentionPolicy.RUNTIME) @Target(value=java.lang.annotation.ElementType.TYPE) public @interface Resources {
  public Resource[] value ;
}
Author

od

7.2. value

List of resources.

Parameters

return

the array of resources.

Appendix B. ModelServices Constant field values

1. csip.*

Table B.1. ModelDataService

ASYNC

"async"

CANCELED

"Canceled"

DESCR

"descr"

ERROR

"error"

EXEC_FAILED

"Error"

FAILED

"Failed"

FINISHED

"Finished"

FORM_PARAM

"param"

GEOMETRY

"geometry"

IN

"in"

INTENT

"intent"

KEY_CLOUD_NODE

"cloud_node"

KEY_CPU_TIME

"cpu_time"

KEY_DESC

"description"

KEY_EXPIRATION_DATE

"expiration_date"

KEY_FIRST_POLL

"first_poll"

KEY_KEEP_RESULTS

"keep_results"

KEY_METAINFO

"metainfo"

KEY_MODE

"mode"

KEY_NAME

"name"

KEY_NEXT_POLL

"next_poll"

KEY_PARAMETER

"parameter"

KEY_PARAMETERSETS

"parametersets"

KEY_PROGRESS

"progress"

KEY_REPORT

"report"

KEY_REQUEST_RESULTS

"request-results"

KEY_REQ_IP

"request_ip"

KEY_RESULT

"result"

KEY_SERVICE_URL

"service_url"

KEY_STATUS

"status"

KEY_SUUID

"suid"

KEY_TIME_CLIMATE_QUERY

"timeClimateQuery"

KEY_TIME_FILEIO

"timeFileIO"

KEY_TIME_LOGGING

"timeLogging"

KEY_TIME_MODEL

"timeModel"

KEY_TIME_SOIL_QUERY

"timeSoilQuery"

KEY_TIME_TOTAL

"timeTotal"

KEY_TSTAMP

"tstamp"

KEY_TZ

"tz"

KEY_UNIT

"unit"

KEY_URL

"url"

MAX

"max"

MIN

"min"

OUT

"out"

RANGE

"range"

REPORT_DESC

"description"

REPORT_DIM

"dim"

REPORT_DIM0

"dimension0"

REPORT_FILE

"report.json"

REPORT_NAME

"name"

REPORT_TYPE

"type"

REPORT_UNITS

"units"

REPORT_VALUE

"value"

RUNNING

"Running"

SUBMITTED

"Submitted"

SYNC

"sync"

UNIT

"unit"

UNKNOWN

"Unknown"

VALUE

"value"


Bibliography

[Argent2004] Argent, R.M. An overview of model integration for environmental applications—components, frameworks and semantics Environmental Modelling & Software, Volume 19, Issue 3, Pages 219-234, Mar 2004

[David2002] David O., S.L. Markstrom, K.W. Rojas, L.R. Ahuja and I.W. Schneider, The Object Modeling System. In: L.R. Ahuja, L. Ma and T.A. Howell, Editors, Agricultural System Models in Field Research and Technology Transfer, Lewis Publishers, Boca Raton (2002), pp. 317–330.

[David2014] David, O., Lloyd, W., Rojas, K., Arabi, M., Geter, F., Ascough II, J., Green, T., Leavesley, G. and J. Carlson (2014), Model-as-a-Service (MaaS) using the Cloud Services Innovation Platform (CSIP), In: Ames, D.P., Quinn, N.W.T., Rizzoli, A.E. (Eds.), Proceedings of the 7th International Congress on Environmental Modelling and Software, June 15-19, San Diego, California, USA. ISBN: 978-88-9035-744-2

[Fielding2002] Fielding, R.; Taylor, R., 2002, "Principled Design of the Modern Web Architecture", ACM Transactions on Internet Technology (TOIT) (New York: Association for Computing Machinery) 2 (2): 115–150.

[GeoServices2010] GeoServices REST Specification Version 1.0, ESRI White Paper, 380 New York Street Redlands, California 92373-8100, September 2010

[ISO8601] ISO 8601:2004, Data elements and interchange formats -- Information interchange -- Representation of dates and times. http://www.iso.org/iso/catalogue_detail?csnumber=40874

[Jha2011] Jha, S, D. S. Katz, A. Luckow, A. Merzky, and K. Stamou, 2011, Understanding Scientific Applications for Cloud Environments, in Cloud Computing: Principles and Paradigms, R. Buyya, J. Broberg, and A. Goscinski, Eds. Hoboken, NJ, USA: John Wiley & Sons, Inc., 2011, pp. 345-371

[OGC2007] Open Geospatial Consortium, Inc. OpenGIS® Web Processing Service (WPS) Specification. WWW document, http://portal.opengeospatial.org/files/?artifact_id=24151, 2007.

[RFC4122] RFC 4122: A Universally Unique IDentifier (UUID) URN Namespace, http://www.ietf.org/rfc/rfc4122.txt

[Roman2009] Roman, D; Schade S.; Berre, A. J.; Bodsberg, N. R.; Langlois, J., 2009, Model as a Service (MaaS). In Grid Technologies for Geospatial Applications Workshop, Hannover, Germany, 2009.

[Zou2012] Zou G., Zhang B., Zheng J., Li Y.; Ma J., 2012, MaaS: Model as a Service in Cloud Computing and Cyber-I Space, Computer and Information Technology (CIT), 2012 IEEE 12th International Conference on , vol., no., pp.1125,1130, 27-29 Oct. 2012.

Index

A

Annotations
Resource, Resource, Resource
Resources, Resources
ARCHIVE, ARCHIVE
args, args, args

C

Classes
ModelDataService, Model­Data­Service
ModelDataService.Task, Model­Data­Service.­Task
ResourceType, Resource­Type
CLASSNAME, CLASSNAME
createCallable, createCallable()
createReport, createReport()
createResults, createResults()

D

describeJSON, describeJSON()

E

Elements
args, args, args
env, env, env
file, file, file
id, id, id
type, type, type
value, value
wine, wine, wine
env, env, env
environment, environment()
Exceptions
ServiceException, Service­Exception
exec, exec()
Executable, Executable
EXECUTABLE, EXECUTABLE
execute, execute(UriInfo, HttpServletRequest, FormDataMultiPart), execute(UriInfo, HttpServletRequest, String)

F

Fields
ARCHIVE, ARCHIVE
CLASSNAME, CLASSNAME
EXECUTABLE, EXECUTABLE
FILE, FILE
JAR, JAR
OMS_DSL, OMS_DSL
OUTPUT, OUTPUT
REFERENCE, REFERENCE
file, file, file
FILE, FILE

G

getArguments, getArguments()
getBooleanMetainfo, getBooleanMetainfo(String)
getBooleanParam, getBooleanParam(String), getBooleanParam(String, boolean)
getCodebase, getCodebase()
getDoubleMetainfo, getDoubleMetainfo(String)
getDoubleParam, getDoubleParam(String), getDoubleParam(String, double)
getFileInput, getFileInput(String)
getFileInputs, getFileInputs()
getFileInputsCount, getFileInputsCount()
getFirstPoll, getFirstPoll()
getIntMetainfo, getIntMetainfo(String)
getIntParam, getIntParam(String), getIntParam(String, int)
getJSONParam, getJSONParam(String), getJSONParam(String, JSONObject)
getLongParam, getLongParam(String), getLongParam(String, long)
getMetainfo, getMetainfo()
getMetainfoCount, getMetainfoCount()
getMetainfoNames, getMetainfoNames()
getName, getName()
getNextPoll, getNextPoll()
getParam, getParam()
getParamCount, getParamCount()
getParamDescr, getParamDescr(String)
getParamGeometry, getParamGeometry(String)
getParamMap, getParamMap()
getParamNames, getParamNames()
getParamUnit, getParamUnit(String)
getRemoteAddr, getRemoteAddr()
getRequest, getRequest()
getRequestContext, getRequestContext()
getRequestHost, getRequestHost()
getRequestURL, getRequestURL()
getResourceExe, getResourceExe(String)
getResourceFile, getResourceFile(String)
getServicePath, getServicePath()
getStringMetainfo, getStringMetainfo(String)
getStringParam, getStringParam(String), getStringParam(String, String)
getSUID, getSUID()
getWorkspaceDir, getWorkspaceDir()

H

hasFileInput, hasFileInput(String)
hasMetainfo, hasMetainfo(String)
hasParam, hasParam(String)
hasWorkspaceDir, hasWorkspaceDir()

I

id, id, id
Interfaces
Executable, Executable

J

JAR, JAR

M

Methods
createCallable, createCallable()
createReport, createReport()
createResults, createResults()
describeJSON, describeJSON()
environment, environment()
exec, exec()
execute, execute(UriInfo, HttpServletRequest, FormDataMultiPart), execute(UriInfo, HttpServletRequest, String)
getArguments, getArguments()
getBooleanMetainfo, getBooleanMetainfo(String)
getBooleanParam, getBooleanParam(String), getBooleanParam(String, boolean)
getCodebase, getCodebase()
getDoubleMetainfo, getDoubleMetainfo(String)
getDoubleParam, getDoubleParam(String), getDoubleParam(String, double)
getFileInput, getFileInput(String)
getFileInputs, getFileInputs()
getFileInputsCount, getFileInputsCount()
getFirstPoll, getFirstPoll()
getIntMetainfo, getIntMetainfo(String)
getIntParam, getIntParam(String), getIntParam(String, int)
getJSONParam, getJSONParam(String), getJSONParam(String, JSONObject)
getLongParam, getLongParam(String), getLongParam(String, long)
getMetainfo, getMetainfo()
getMetainfoCount, getMetainfoCount()
getMetainfoNames, getMetainfoNames()
getName, getName()
getNextPoll, getNextPoll()
getParam, getParam()
getParamCount, getParamCount()
getParamDescr, getParamDescr(String)
getParamGeometry, getParamGeometry(String)
getParamMap, getParamMap()
getParamNames, getParamNames()
getParamUnit, getParamUnit(String)
getRemoteAddr, getRemoteAddr()
getRequest, getRequest()
getRequestContext, getRequestContext()
getRequestHost, getRequestHost()
getRequestURL, getRequestURL()
getResourceExe, getResourceExe(String)
getResourceFile, getResourceFile(String)
getServicePath, getServicePath()
getStringMetainfo, getStringMetainfo(String)
getStringParam, getStringParam(String), getStringParam(String, String)
getSUID, getSUID()
getWorkspaceDir, getWorkspaceDir()
hasFileInput, hasFileInput(String)
hasMetainfo, hasMetainfo(String)
hasParam, hasParam(String)
hasWorkspaceDir, hasWorkspaceDir()
postprocess, postprocess()
postProcess, postProcess()
preprocess, preprocess()
preProcess, preProcess()
process, process()
putReport, putReport(File...), putReport(File), putReport(File, String), putReport(String, boolean), putReport(String, boolean, String), putReport(String, boolean, String, String), putReport(String, double), putReport(String, double, String), putReport(String, double, String, String), putReport(String, int), putReport(String, int, String), putReport(String, int, String, String), putReport(String, JSONObject), putReport(String, JSONObject, String), putReport(String, JSONObject, String, String), putReport(String, String), putReport(String, String, String), putReport(String, String, String, String)
putResult, putResult(File...), putResult(File), putResult(File, String), putResult(String, boolean), putResult(String, boolean, String), putResult(String, boolean, String, String), putResult(String, double), putResult(String, double, String), putResult(String, double, String, String), putResult(String, int), putResult(String, int, String), putResult(String, int, String, String), putResult(String, JSONObject), putResult(String, JSONObject, String), putResult(String, JSONObject, String, String), putResult(String, String), putResult(String, String, String), putResult(String, String, String, String)
redirectError, redirectError(String)
redirectOutput, redirectOutput(String)
report, report()
ServiceException, ServiceException(String), ServiceException(String, Throwable), ServiceException(Throwable)
setArguments, setArguments(Object...)
setMetainfo, setMetainfo(JSONObject)
setParam, setParam(JSONArray)
setParamMap, setParamMap(Map<String, JSONObject>)
setProgress, setProgress(int), setProgress(String)
setRequest, setRequest(JSONObject)
ModelDataService, Model­Data­Service
ModelDataService.Task, Model­Data­Service.­Task

O

OMS_DSL, OMS_DSL
OUTPUT, OUTPUT

R

redirectError, redirectError(String)
redirectOutput, redirectOutput(String)
REFERENCE, REFERENCE
report, report()
Resource, Resource, Resource
Resources, Resources
ResourceType, Resource­Type

T

type, type, type

V

value, value

W

wine, wine, wine