A RESTful Service to access FESA and DeviceAccess devices.

japc-rest is a RESTful service that allows accessing FESA or DeviceAccess devices, platform and programming language independant, over JAPC.

The base URL UPDATED

UPDATED The base URL to access the resources in the production environment is https://asl157.acc.gsi.de/japc-client/v1/

UPDATED API documentation is available via https://asl157.acc.gsi.de/japc-client/v1/_api

wip Note that the sections below are at least partially outdated

The WADL describes the service

With https://restpro00a.acc.gsi.de/japc/client/v1/application.wadl we get the list of available resources under the base URL.

WADL is for REST what WSDL for SOAP is: It describe the resource, its path parameters with their respective names and types, its methods with their respective types (GET, PUT, ..) among other things.

The following code-snippet shows the resource https://restpro00a.acc.gsi.de/japc/client/v1//{device}/{property}.
...
<resource path="/{device}/{property}">
<param name="property" style="template" type="xs:string"/>
<param name="device" style="template" type="xs:string"/>
<method id="setParameterValue" name="PUT">
<request>
<param name="selector" style="query" type="xs:string"/>
<representation mediaType="application/json"/>
</request>
<response>
<representation mediaType="application/json"/>
</response>
</method>
<method id="getParameterValue" name="GET">
<request>
<param name="selector" style="query" type="xs:string"/>
</request>
<response>
<representation mediaType="application/json"/>
</response>
</method>
</resource>

It shows the path of the resource, which must be added to the basic URL of the service, in this case it is composed of the device name followed by the property name.
The device and properies name are the 2 path parameters of the resource. Both path parameters are of type string.
It's abvious that the resource has 2 methods, one for PUT and another for GET operartions. Furthermore the GET request as well as the PUT request may have a query parameter with the name selector of type string.
The response element shows that both request produce and send back a json object to the client.

The json object the PUT operation returns to the client has the following simple structure:
{
"code": number,
"message": string
}

The value for code represents the HTTP status code and the optional message tries to explain the result of the request.

The response of the GET operation returns a complex JSON object: To keep it simple, a property with a unique field is shown in the following example.
{
"deviceName": "GSITemplateTestvmla017",
"propertyName": "Power",
"fieldName":"power"
"valueMap": {
"power: {
"type": "int";
"value": 1
}
}
}

Synchronous and Asynchronous Resources

For GET as well as for PUT operations japc-rest provides synchronous resources and there conterpart ashynchronous ones.

Synchronous resources

A synchronous resource is a resource that processes a request synchronously. How the client procedes is another story.
When a request is received, an I/O thread from a pool of such threads, available at server side, is dedicated to accept and process the request. The thread blocks until the request is finished and returned. As the number of available I/O threads is limited, the situation in which no more threads are available to accept and process any new request may take place when the number of requests is high and processing is time consuming.

Asynchronous Resources

An asynchronous resource processes a request quite differently: a first thread (acceptor) is dedicated to accept a request, the processing is done by another thread (worker). The accepor-thread accepts a request hands it over to the worker and is immediately released and returned to the pool, so that it can accept another potential connection. It's of course the worker-thread that sends back the response to the client.

Reading the Fields' Values of a Property of FESA and DeviceAccess devices

To read the values of a property's fields or the value of a single field of FESA and DeviceAccess devices, japc-rest provides resources.

Reading the Fields' Values of a Device's Property

A FESA or DeviceAccess device has one or more properties and a property has one or more fields. To get the values of the fields of a device's property we use the resource: /{device}/{property}.

For the device GSITemplateTestvmla017 and its property Power , the GET request will be:

https://restpro00a.acc.gsi.de/japc/client/v1/GSITemplateTestvmla017/Power

The returned Json-object is:
{
"deviceName":"GSITemplateTestvmla017",
"propertyName":"Power",
"valueMap":{
"power":{
"type":"int",
"value":1
}
}
}

Reading the Value of a single Field of a Device's Paramter

To get just the value of a unique field japc-rest provides the resource /{device}/{property}/{field}.

To keep things simple, let's use the same device GSITemplateTestvmla017 and the same property Power. This property has a unique field power, but even if it had many more fields, we would use the same resource. The GET request is: https://restpro00a.acc.gsi.de/japc/client/v1/GSITemplateTestvmla017/Power/power

The returned json object is:
{  
"deviceName":"GSITemplateTestvmla017",
"propertyName":"Power",
"fieldName":"power",
"valueMap":{
"power":{
"type":"int",
"value":1
}
}
}

Setting the Fields' Values of Property of FESA and DeviceAccess devices

japc-rest provides also resources to set the values of property's fields.

The Requirement of the Correct Value of a Query Property

Setting the values of a property must be done with caucious, that is why the requester must provide the correct value of a query parameter named token to filfull this operation.
For this type of operations the client-IP, the device name, the property name and the field name are always logged.

Setting the Value of a single Field of a Device's Property

To set the value of a sole field japc-rest provides the resource /{device}/{property}/{field}.

Again to keep things simple, let's use the same device GSITemplateTestvmla017 and the same property Power. The unique field power, requies an integer value and is defined in FESA as:
<enum name="DEVICE_POWER" id="xxxxxxxxxxx">
<!--An enumeration Type used to control the operational mode of the device. -->
<!--Its values are a subset of those in the DEVICE_POWER_STATE type -->
<item access="RW" meaning="ON" symbol="ON" value="1" id="_181009120017_3" />
<!--The device is in fully operational state -->
<item access="RW" meaning="OFF" symbol="OFF" value="2" id="_181009120018_0" />
<!--The device is turned off -->
</enum>

The correct values for this field are thus 1 for "ON" or 2 for "OFF".

The PUT request is: https://restpro00a.acc.gsi.de/japc/client/v1/GSITemplateTestvmla017/Power/power

and the Json-Object to provide as payload in the body of the request using POSTMAN or any other REST Client Browser-addon like RESTClient is:
{
"deviceName":"GSITemplateTestvmla017",
"propertyName": "Power",
"valueMap":{
"power":{
"type":"int",
"value":2
}
}
}

For this request without the famous token query parameter, the returned json object is:
{
"code": 400,
"message": "No value provided for token."
}

For the same PUT request with the correct Value for token: https://restpro00a.acc.gsi.de/japc/client/v1/GSITemplateTestvmla017/Power/power?token=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx we get a response with an empty body, the Status 204 and the message that "The server successfully processed the request, but is not returning any content".

Setting the Fields' Values of a Device's Property

For a device's property with 2 or more fields, the same PUT-request with the token query parameter can be use to set the values of these fields:

{
"deviceName":"a-device-name",
"propertyName": "a-property-name",
"valueMap":{
"field-1":{
"type":"type-of-field-1",
"value":"any-value-of-the-type-above"
},
"field-2":{
"type":"type-of-field-2",
"value":"any-value-of-the-type-above"
},
.....
"field-N":{
"type":"type-of-field-N",
"value":"any-value-of-the-type-above"
}
}
}

The element "type" can be:
  1. one of the primitive types: byte, boolean, char, decimal, double, float, int/integer, long, short, String.
  2. A simple array of one of the primitive types: byte[], boolean[], char[], decimal[], double[], float[], int[], long[], short[], String[].
  3. A 2-D array: byte[][], boolean[][], char[][], decimal[][], double[][], float[][], int[][], long[][], short[][], String[][].

A Java Client to Read and Set the Fields' Values of a Device's Property

A Java client desktop application japc-rest-client-api has been written to access and use japc-rest.

Using Python to Read and Set the Fields' Values of a Device's Property

It's of course possible to access and use japc-rest from any program, or script written in any programming-language.

As Python is an importing langauge, we will present simple scripts to read and to write the fields' values of a device's property.

A Python-Script to Read the Fields' Values of a Device's Property

With the simple python script listed below we get the value of the unique field power of property Power of the device GSITemplateTestvmla017.

#!/bin/python
# tested with python version 3.6.6 on Windows 7 Entreprise

import requests
import json

deviceName='GSITemplateTestvmla017'
propertyName='Power'

headers = {'content-type': 'application/json'}

# the url for request
url = 'https://restpro00a.acc.gsi.de/japc/client/v1/' + deviceName + '/' + propertyName

# send a get request
response = requests.get(url, headers=headers)

print ("returned status-code: " + str(response.status_code))

if response.status_code == 200:
print("The GET request was successful")
else:
# Something went wrong
print("The GET request was unsuccessful")
# just print the returned Json-Object
print(response.text)

The script has been written and tested with the 3.6.6 version of WPython. To use this script for another device, the values for deviceName, propertyName must be of course set accordingly.

It must be clear for the script user which properties a certain device has and which fields a certain property has. Furthermore it must be clear for him/her which type the value of each field has and therefore he/she must know in advance what for a structure the returned json object has.

.. (to be continued)

A Python-Script for a PUT

The python script below shows how to set the fields of the property Power of the device GSITemplateTestvmla017. In this case again the property has a the unique field power but the same script is suitable to set the values of a property's fields,

#!/bin/python
# tested with python version 3.6.6 on Windows 7 Entreprise

import requests
import json

deviceName='GSITemplateTestvmla017'
propertyName='Power'

headers = {'content-type': 'application/json'}

# the url for request
url1 = 'https://restpro00a.acc.gsi.de/japc/client/v1/'+devicename+'/'+propertyName + '?token=Zi5sYWZyaXRlOmdzaS1mYWlyLWdlaGVpbQ=='

payload = {
"deviceName":"GSITemplateTestvmla017",
"propertyName": "Power",
"valueMap":{
"power":{
"type":"int",
"value":2
}
}
}

print("Trying to set the property '" + propertyName + "' (url " + str(url1) + ")")

# a put request must be sent to set the parameter's Fileds' values.
response = requests.put(url1, json=payload, headers=headers)

if response.status_code != 204:
# Something went wrong
print("The PUT request was unsuccessful")
print ("returned status-code: " + str(response.status_code))
print(response.text)
# raise requests.HTTPError(response.text)
else:
print("The PUT request was successful")
print ("returned status-code: " + str(response.status_code))

.. (to be continued)

Returned Messages By Errors

If we execute the following script, where the propertyName in the payload json object is other than the one of the path-parameter:

#!/bin/python
# tested with python version 3.6.6 on Windows 7 Entreprise

import requests
import json

deviceName='GSITemplateTestvmla017'
propertyName='Setting'

headers = {'content-type': 'application/json'}

# the url for request
url1 = 'https://restpro00a.acc.gsi.de/japc/client/v1/'+devicename+'/'+propertyName + '?token=Zi5sYWZyaXRlOmdzaS1mYWlyLWdlaGVpbQ=='

payload = {
"deviceName":"GSITemplateTestvmla017",
"propertyName": "Power",
"valueMap":{
"power":{
"type":"int",
"value":2
}
}
}
....

We get the following error:

The PUT request was unsuccessful
returned status-code: 400
{

"code":400,

"message":"Invalid Request: The value 'Power' provided for property-name in the json object and the value 'Setting' of the path-parameter 'property' must be identical."

}

The property Power of GSITemplateTestvmla017 has a sole field power that requies an integer value: "1" for "ON" and "2" for "OFF".

Trying to set its value to "3" for example, we get the following error-message:

The PUT request was unsuccessful
returned status-code: 404
{

"code":404,"message":"FESA_12005 Value item 'power': invalid data; nested error message: FESA_10009 Invalid value: '3' is invalid regarding type '::GSITemplate::DEVICE_POWER::DEVICE_POWER'..

generated/cpp/GSITemplate/GeneratedCode/TypeDefinition.h:433. /opt/fesa/fesa-fwk/5.0.1/include/fesa-core/Server/ServerData.h:435"

}

Trying to set the value of the field power to a boolean

payload = { 
"deviceName":"GSITemplateTestvmla017",
"propertyName": "Power",
"valueMap":{
"power":{
"type":"boolean",
"value":True
}
}
....

The PUT request was unsuccessful
returned status-code: 404
{"code":404,"message":"FESA_12007 Value item 'power': invalid type 'bool', 'int32_t' is expected. src/fesa-core/Server/ServerData.cpp:259"}

Feedbacks and Questions

If you have any question, please don't hesitate to contact me,

Your feedback is highly appreciated: it will be considered for further enhancement.
Topic revision: r10 - 21 Jun 2023, HannoHuether
This site is powered by FoswikiCopyright © by the contributing authors. All material on this collaboration platform is the property of the contributing authors.
Ideas, requests, problems regarding Foswiki? Send feedback