The JSON Archive Proxy for CSS is intended as a simple tool for integrating archive data-sources into Control System Studio without having to install lots of dependencies (e.g. libraries for accessing database systems). Furthermore, the JSON Archive Proxy can be used for easily integrating third-party applications that can act either as data sources, providing archived PV data to CSS, or as clients that can read archived PV data from CSS data-sources.
The JSON Archive Proxy consists of two components that can be used in combination (simply acting as a proxy for an archive reader plug-in) or separately for integrating a third-party application with CSS. The first component is the JSON Archive Proxy reader plug-in that can be installed into CSS in order to access an archive source exposed through the JSON/HTTP protocol. The second component is the JSON Archive Proxy server that can expose the data sources provided by any CSS archive reader plug-in through the JSON/HTTP protocol.
These two components are completely independent and communicate with each other using JSON/HTTP only. This is why it is easy to replace either component with a different implementation thus facilitating the integration of third-party applications with CSS. One example of such a third-party application is the Cassandra PV Archiver which exposes its archive data through the JSON/HTTP protocol so that it can be accessed from CSS using the JSON Archive Proxy reader plug-in.
In comparison to older versions, the JSON Archive Proxy 3.0 is now compatible with newer versions of Control System Studio (in particular versions 4.3 and 4.4). The JSON/HTTP protocol has stayed the same, so that the server and reader components can simply be mixed with older versions of the JSON Archive Proxy.
With version 3.0, the distribution format of the JSON Archive Proxy has changed. It is no longer distributed as a downloadable archive. Instead, the software is distributed through a P2 repository (Eclipse update-site). Installing the reader plug-in from the update site is both simpler and more reliable than manually fiddling with the Eclipse / CSS installation. However, it also means that in order to use the server component, one now has to build a product which adds the necessary archive reader plug-ins.
The installation process is different for the reader and the server component. While the reader component can simply be installed into CSS, the server component has to be used for building a custom Eclipse product.
Installing the JSON Archive Proxy reader plug-in into CSS is very simple. One only has to select JSON Archive Proxy web-site. Next, the “JSON Archive Proxy Reader” feature has to be selected. The “JSON Archive Proxy Reader Developer Resources” feature only contains source files and does not have to be installed. It is only useful when creating a new Eclipse target platform for plug-in development. The “JSON Archive Proxy Server” feature is only intended for creating a new server product and must never be installed into CSS. This feature will not work in a regular CSS installation and might interfere with other CSS features.
from the menu in CSS and point it to the URL of the update site for the JSON Archive Proxy release that is supposed to be installed. The URL of the update site can be found on theThe “JSON Archive Proxy Reader” feature depends on a few plug-ins that are not provided by the same repository. In particular, it depends on the CSS archive APIs and the Jackson JSON library. These plug-ins are provided by the CSS and Eclipse repositories, so the update-sites for the respective CSS and Eclipse releases should also be present in the CSS software configuration. Typically, these update sites are already present in most CSS products and do not have to be added explicitly.
After installing the plug-in, one can add a data-source for the CSS data
browser.
The URLs recognized by the JSON Archive Proxy reader have the form
json:http://
where in this example server.example.com
:8080
/server.example.com
is
the server’s hostname and 8080
is the TCP
port on which the server is listening for incoming connections.
The path might differ from the path given in the example if a server
does not expose the archive-access API at its root.
The JSON Archive Proxy server is the component that can expose any CSS archive reader plug-in through the JSON/HTTP protocol used by the JSON Archive Proxy reader plug-in. In order to be useful, the JSON Archive Proxy server plug-in has to be bundled with the archive reader plug-in that is used for accessing the underlying archive. This can be achieved by creating a custom Eclipse product that depends on both the JSON Archive Proxy server feature and the feature that provides the relevant archive reader plug-in.
Creating a custom Eclipse product is outside the scope of this document,
but the source tree of the JSON Archive Proxy provides an example
project using
Tycho for
building such a product in the
com.aquenos.csstudio.json.server.product
directory.
In general, for building such a product, one has to ensure that the
update-sites of the Eclipse RCP release, the CSS release, and the JSON
Archive Proxy release are present in the target platform used for
building the product.
The product definition should specify the
com.aquenos.csstudio.archive.json.server.engine
product and the
com.aquenos.csstudio.archive.json.server.application
application.
In addition to the archive-reader specific features, it has to contain
the com.aquenos.csstudio.archive.json.server.feature
,
org.eclipse.equinox.server.jetty
, and the
org.eclipse.equinox.core.feature
features.
When using the
com.aquenos.csstudio.archive.json.server.application
application as the base of the product, the launcher will support two
command-line parameters:
The optional -port
argument takes the ports number
on which the server will listen for incoming requests as its parameter.
If not specified, the server will listen on port 8080 by default.
The mandatory -archive-url
argument takes the URL of
the underlying archive data-source as its parameter.
The format of this URL depends on the archive reader plug-in being used.
The JSON-based archive access protocol is the protocol that is used for communication between the JSON Archive Proxy reader plug-in and the JSON Archive Proxy server.
The base URL used for all requests concerning the JSON-based
archive-access protocol 1.0 depends on the server implementation and the
deployment configuration.
The JSON Archive Proxy server provides the API right at the root, so that
the base URL for accessing a the JSON Archive Proxy server running on
myserver.example.com
and listening on port 8080 is
http://myserver.example.com:8080/
.
This base URL has to be prepended to all URLs that are mentioned in this
protocol specification.
Other server implementations might choose a different path or default
port.
Please refer to the documentation of the respective server implementation
for details.
All requests are made by specifying query parameters in the URL.
The request body is always empty.
The response is always sent in the JSON format (MIME type
application/json) unless there is an error (which is identified by a
corresponding HTTP status code).
All requests are sent as GET
requests.
The JSON Archive Proxy server and the JSON Archive Proxy reader plug-in support deflate and gzip compression of the response body. Other client and server implementations should also support these compression methods when possible. For JSON data, compression can dramatically reduce the amount of data that has to be transferred, so clients should support compression when possible. In any, case clients and servers supporting compression must also be compatible with clients or servers that do not support compression, falling back to uncompressed data transfer.
The request URL for retrieving the list of available archives has the following form:
/archive/[?prettyPrint]
If the optional prettyPrint
parameter is present,
the output is formatted nicely, which can be useful for debugging.
Usually, this parameter should be omitted because this will result in
a more compact representation, saving bandwidth.
The response is a JSON array, each element being one available archive (JSON object). Each of these JSON objects has the following fields:
Field name | Internal data type | JSON data type | Description |
---|---|---|---|
key | int | number (must be in integer format) | numeric key identifying the archive (unique) |
name | string | string | name of the archive (might not be unique) |
description | string | string | description of the archive |
The request URL used in order to search for channels takes one of the following two forms:
/archive/<archive key>
/channels-by-pattern/<glob pattern expression>
↪[?prettyPrint] /archive/<archive key>
/channels-by-regexp/<regular expression>
;[?prettyPrint]
The archive key
is the numeric key of the
archive as specified in the list of archives (typically
1
).
The search for a channel name can be done with a glob pattern or a regular expression. In either case, the pattern needs to be URL encoded so that all special characters (in particular those that have a special meaning in a URL, like the question mark) are encoded with %xx where xx is the hexadecimal character code. This includes the special wildcard characters that are part of the pattern. When the expression contains non-ASCII characters, those characters are expected to be specified in UTF-8 encoding.
When using a glob pattern, the channels-by-pattern
URL has to be used.
In the glob pattern expression
, the ? and *
characters have a special meaning.
The question mark acts as wildcard that matches exactly one character.
The asterisk acts as a wildcard that matches an arbitrary number of
characters (including zero characters).
When using a regular expression, the
channels-by-regexp
URL has to be used.
The regular expression
must be specified in
a form that is understood by the
java.util.regex.Pattern.compile(java.lang.String)
method.
If the optional prettyPrint
parameter is present,
the output is formatted nicely, which can be useful for debugging.
Usually, this parameter should be omitted because this will result in
a more compact representation, saving bandwidth.
The response is a JSON array, containing JSON strings, where each string is a channel name. When no matching channel is found, an empty array is returned.
The request URL for retrieving samples for a specific channel has the following form:
/archive/<archive key>
/samples/<channel name>
?start=<start time-stamp>
& ↪end=<end time-stamp>
[&count=<desired number of samples>
][&prettyPrint]
The archive key
is the numeric key of the
archive as specified in the list of archives (typically
1
).
The channel name
is the name of the channel
for which samples are requested.
The channel name must be URL encoded so that all special characters
(in particular those that have a special meaning in a URL, like the
question mark) are encoded with %xx where xx is the hexadecimal
character code.
When the channel name contains non-ASCII characters, those characters
are expected to be specified in UTF-8 encoding.
The start time-stamp
specifies the start of
the interval for which samples are requested.
The time stamp is specified as the number of nanoseconds since epoch
(January 1st, 1970, 00:00:00 UTC).
The end time-stamp
specifies the end of
the interval for which samples are requested.
The time stamp is specified as the number of nanoseconds since epoch
(January 1st, 1970, 00:00:00 UTC).
The count
parameter is optional.
If specified, the desired number of samples
is a strictly positive number that specifies the number of samples
that should be returned.
The number of samples returned will usually not match this number
exactly.
However, if samples with various densities are available, the density
which will result in the number of samples closest to the requested
number is chosen.
If this parameter is not specified, raw samples are used.
If the optional prettyPrint
parameter is present,
the output is formatted nicely, which can be useful for debugging.
Usually, this parameter should be omitted because this will result in
a more compact representation, saving bandwidth.
The response is a JSON array, each element being one sample (JSON object). In addition to the samples between the start and the end time-stamp, one sample at or before the start time-stamp and one sample at or after the end time-stamp is returned (if such samples exist at all). This way, the returned data is sufficient for creating a plot covering the whole interval, even if the specified time stamps do not exactly match the time stamps of samples.
Each of the sample objects can have the following fields:
Field name | Internal data type | JSON data type | Description |
---|---|---|---|
time | big integer | number (must be in integer format) | time-stamp in nanoseconds since epoch (January 1st, 1970, 00:00:00 UTC) |
severity | see below | object | alarm severity |
status | string | string | alarm status (might contain additional information about the severity) |
quality | string | string | sample quality - one of “Original” or “Interpolated” (not case-sensitive) |
metaData | see below | object | meta-data of the sample |
type | string | string | sample type - must be one of “double”, “enum”, “long”, “minMaxDouble”, or “string” (not case-sensitive) |
value | depends on sample type | array | array of values making up the sample |
minimum | double | number or string | minimum value – must be in number format unless it cannot be expressed as a JSON number (e.g. infinity) |
maximum | double | number or string | maximum value – must be in number format unless it cannot be expressed as a JSON number (e.g. infinity) |
The type
, time
,
severity
, status
,
quality
, and value
fields are
always present.
The minimum
and maximum
fields
are only present if the type is minMaxDouble
.
The type
field must always come before the
value
field.
The quality
field indicates whether the sample is a
raw sample (“Original”) or a decimated sample (“Interpolated”).
The metaData
field may be present for all types
except the string
type.
The format of the meta-data depends on the type (see below).
At places where a number may also be expressed as a JSON string, the
use of a string is reserved to cases where the number cannot be
represented as a JSON number (infinity and not-a-number).
Valid strings are inf
, infinity
,
+inf
, +infinity
,
-inf
, -infinity
, and
nan
(all not case-sensitive).
The value is always represented as a JSON array. The type of the array elements depends on the sample type:
Sample type | Element JSON type | Remarks |
---|---|---|
double | number or string | must be in number format unless it cannot be expressed as a JSON number (e.g. infinity) |
enum | number | must be in integer format, numbers outside the interval [-231, 231-1] may be truncated |
long | number | must be in integer format, numbers outside the interval [-263, 263-1] may be truncated |
minMaxDouble | number or string | must be in number format unless it cannot be expressed as a JSON number (e.g. infinity) |
string | string |
The minMaxDouble
type is used for samples that have
been aggregates from several raw samples and the
minimum
and maximum
represent
the least and the greatest value of any of the original samples.
Sample of type minMaxDouble
typically have a
quality
of “Interpolated” because they represent
decimated samples.
The severity is a JSON object with the following fields (all mandatory):
Field name | Internal data type | JSON data type | Description |
---|---|---|---|
level | string | string | sample severity - one of “OK”, “MINOR”, “MAJOR”, or “INVALID” (all not case-sensitive) |
hasValue | boolean | boolean | tells whether the sample has a value (or just signals a condition with a certain severity) |
The meta-data is a JSON object.
The format depends on the sample type.
Samples that are of the string
type do not have
meta data.
Samples that are of the enum
type can have meta
data in the following format (all fields are mandatory):
Field name | Internal data type | JSON data type | Description |
---|---|---|---|
type | string | string | value is always “enum” (not case-sensitive) |
states | array of strings | array of strings | labels for the enum states |
Samples that are of the double
,
long
, or minMaxDouble
type can
have meta data in the following format (all fields are mandatory):
Field name | Internal data type | JSON data type | Description |
---|---|---|---|
type | string | string | value is always “numeric” (not case-sensitive) |
precision | integer | number | number of fractional digits to be displayed, must be in integer format |
unit | string | string | engineering units of the value |
displayLow | double | number or string | lower display limit – must be in number format unless it cannot be expressed as a JSON number (e.g. infinity) |
displayHigh | double | number or string | upper display limit – must be in number format unless it cannot be expressed as a JSON number (e.g. infinity) |
warnLow | double | number or string | lower warning limit – must be in number format unless it cannot be expressed as a JSON number (e.g. infinity) |
warnHigh | double | number or string | upper warning limit – must be in number format unless it cannot be expressed as a JSON number (e.g. infinity) |
alarmLow | double | number or string | lower alarm limit – must be in number format unless it cannot be expressed as a JSON number (e.g. infinity) |
alarmHigh | double | number or string | upper alarm limit – must be in number format unless it cannot be expressed as a JSON number (e.g. infinity) |
Request:
GET /archive-access/api/1.0/archive/1/samples/testCalc?start=0& ↪end=1500000000000000000&prettyPrint HTTP/1.0
Response:
[ { "time" : 1468429059824011000, "severity" : { "level" : "OK", "hasValue" : true }, "status" : "NO_ALARM", "quality" : "Original", "metaData" : { "type" : "numeric", "precision" : 2, "units" : "V", "displayLow" : 0.0, "displayHigh" : 0.0, "warnLow" : "NaN", "warnHigh" : 12.0, "alarmLow" : "NaN", "alarmHigh" : 15.0 }, "type" : "double", "value" : [ 7.0 ] }, { "time" : 1468429060825564000, "severity" : { "level" : "MINOR", "hasValue" : true }, "status" : "HIGH", "quality" : "Original", "metaData" : { "type" : "numeric", "precision" : 2, "units" : "V", "displayLow" : 0.0, "displayHigh" : 0.0, "warnLow" : "NaN", "warnHigh" : 12.0, "alarmLow" : "NaN", "alarmHigh" : 15.0 }, "type" : "double", "value" : [ 12.0 ] } ]