diff --git a/Readme.md b/Readme.md
index 2751bc8..d1fd361 100644
--- a/Readme.md
+++ b/Readme.md
@@ -108,6 +108,154 @@ curl -H "Content-Type: application/json" -X POST -d '{"regex": "AMPLT|PHASE"}' h
]
```
+
+
+## Channel Configurations
+
+It is possible to query channel configurations like type etc..
+
+The following configuration queries provide the latest known configuration of the channels (see [here](Readme.md#channel_configuration_history) on how to query the channel configuration history).
+
+
+
+
+### Query Channel Configurations
+
+### Request
+
+```
+POST https://:/channels/config
+```
+
+#### Data
+
+```json
+{
+ "regex":"^SINEG.*PHASE$",
+ "backends":[
+ "sf-databuffer"
+ ],
+ "ordering":"none",
+ "sourceRegex":"LLRF"
+}
+```
+
+##### Explanation
+
+- **regex**: Reqular expression used to filter channel names. In case this value is undefined, no filter will be applied. Filtering is done using JAVA's [Pattern](https://docs.oracle.com/javase/8/docs/api/java/util/regex/Pattern.html), more precisely [Matcher.find()](https://docs.oracle.com/javase/8/docs/api/java/util/regex/Matcher.html#find--)).
+- **backends**: Array of backends to access (values: sf-databuffer|sf-imagebuffer|sf-archiverappliance). In case this value is undefined, all backends will be queried for their channels.
+- **ordering**: The ordering of the channel names (values: **none**|asc|desc).
+- **sourceRegex**: Reqular expression used to filter source names (like e.g. tcp://SINEG01-CVME-LLRF1:20000). In case this value is undefined, no filter will be applied. Filtering is done using JAVA's [Pattern](https://docs.oracle.com/javase/8/docs/api/java/util/regex/Pattern.html), more precisely [Matcher.find()](https://docs.oracle.com/javase/8/docs/api/java/util/regex/Matcher.html#find--)).
+
+### Example
+
+#### Command
+
+```bash
+curl -H "Content-Type: application/json" -X POST -d '{"regex": "AMPLT|PHASE|CAM"}' https://data-api.psi.ch/sf/channels/config | python -m json.tool
+```
+
+#### Response
+
+```json
+[
+ {
+ "backend":"sf-databuffer",
+ "channels":[
+ {
+ "name":"Channel_01_AMPLT",
+ "type":"UInt16",
+ "shape":[2048],
+ "modulo":1,
+ "offset":0,
+ "backend":"sf-databuffer",
+ "source":"tcp://SINEG01-CVME-LLRF1:20000"
+ },
+ {
+ "name":"Channel_01_PHASE_AVG",
+ "type":"Float64",
+ "shape":[1],
+ "modulo":1,
+ "offset":0,
+ "backend":"sf-databuffer",
+ "source":"tcp://SINEG01-CVME-LLRF1:20000"
+ }
+ ]
+ },
+ {
+ "backend":"sf-imagebuffer",
+ "channels":[
+ {
+ "name":"Helges_CAM",
+ "type":"UInt16",
+ "shape":[1024,2048],
+ "modulo":1,
+ "offset":0,
+ "backend":"sf-imagebuffer",
+ "source":"tcp://HELGE_COMPI:9999"
+ }
+ ]
+ }
+]
+```
+
+
+
+### Query Specific Channel Configuration
+
+### Request
+
+```
+POST https://:/channel/config
+```
+or
+
+```
+GET https://:/channel/config/{channel}
+```
+
+#### Data
+
+```json
+{
+ "name":"SINEG01-RCIR-PUP10:SIG-AMPLT",
+ "backend":"sf-databuffer"
+}
+```
+
+##### Explanation
+
+- **name**: The channel name (see [here](https://github.psi.ch/sf_daq/ch.psi.daq.queryrest#define-channel-names) on how name clashes will be resolved).
+- **backend**: The backend of the channel.
+
+### Example
+
+#### Command
+
+```bash
+curl -H "Content-Type: application/json" -X POST -d '{"name": "SINEG01-RCIR-PUP10:SIG-AMPLT", "backend":"sf-databuffer"}' https://data-api.psi.ch/sf/channel/config | python -m json.tool
+```
+
+or
+
+```bash
+curl -H "Content-Type: application/json" -X GET https://data-api.psi.ch/sf/channel/config/SINEG01-RCIR-PUP10:SIG-AMPLT | python -m json.tool
+```
+
+#### Response
+
+```json
+{
+ "name":"SINEG01-RCIR-PUP10:SIG-AMPLT",
+ "type":"UInt16",
+ "shape":[2048],
+ "modulo":1,
+ "offset":0,
+ "backend":"sf-databuffer",
+ "source":"tcp://SINEG01-CVME-LLRF1:20000"
+}
+```
+
## Query Data
@@ -198,7 +346,7 @@ The simplest way to define channels is to use an array of channel name Strings.
]
```
-The query interface will automatically select the backend which contains the channel (e.g., *sf-databuffer* for *Channel_02* and *sf-archiverappliance* for *Channel_04*). In case name clashes exist, the query interface will use following order of priority: *sf-databuffer* and then *sf-archiverappliance*.
+The query interface will automatically select the backend which contains the channel (e.g., *sf-databuffer* for *Channel_02* and *sf-archiverappliance* for *Channel_04*). In case name clashes exist, the query interface will use following order of priority: *sf-databuffer*, *sf-imagebuffer*, and then *sf-archiverappliance*.
It is also possible to explicitly define the backend to overcome name clashes.
@@ -283,7 +431,7 @@ Queries are applied to a range. The following types of ranges are supported.
]
```
-- **fields**: Array of requested fields (see [here](https://github.psi.ch/sf_daq/ch.psi.daq.domain/blob/master/src/main/java/ch/psi/daq/domain/query/operation/QueryField.java) for possible values).
+- **fields**: Array of requested fields (see [here](https://github.psi.ch/sf_daq/ch.psi.daq.domain/blob/master/src/main/java/ch/psi/daq/domain/query/operation/EventField.java) for possible values of data queries and [here](https://github.psi.ch/sf_daq/ch.psi.daq.domain/blob/master/src/main/java/ch/psi/daq/domain/query/operation/ConfigField.java) for possible values of config queries).
It is possible to request the time in seconds (since midnight, January 1, 1970 UTC (the UNIX epoch) as a decimal value including fractional seconds - using fields *globalSeconds* and *iocSeconds*), in milliseconds (since midnight, January 1, 1970 UTC (the JAVA epoch) - using fields *globalMillis* and *iocMillis*) or as a ISO8601 formatted String - using fields *globalDate* and *iocDate* (such as 1997-07-16T19:20:30.123456789+02:00).
@@ -1245,3 +1393,50 @@ With *provide-as-is*, the response will contain all available data. In case *dro
```
+
+
+### Query Channel Configuration History
+
+### Request
+
+```
+POST https://:/query/config
+```
+
+#### Request body
+
+A request is performed by sending a valid JSON object in the HTTP request body. The JSON query defines the channels to be queried and the range.
+
+#### Data
+
+```json
+{
+ "channels":[
+ "Channel_01"
+ ],
+ "range":{
+ "startPulseId":0,
+ "endPulseId":3
+ },
+ "ordering":"asc",
+ "fields":[
+ "pulseId",
+ "globalDate",
+ "type"
+ ],
+ "response":{
+ "format":"json",
+ "compression":"none"
+ }
+}
+```
+
+##### Explanation
+
+The query format is equivalent to the data query (see [here](Readme.md#query_data) for further explanations).
+
+##### Command
+
+```bash
+curl -H "Content-Type: application/json" -X POST -d '{"range":{"startDate":"2017-01-01T01:00:00.000","endDate":"2017-11-01T01:00:00.030"},"channels":["Channel_01"]}' https://data-api.psi.ch/sf/query/config | python -m json.tool
+```
diff --git a/src/main/java/ch/psi/daq/queryrest/controller/QueryRestController.java b/src/main/java/ch/psi/daq/queryrest/controller/QueryRestController.java
index 4663f4f..f649447 100644
--- a/src/main/java/ch/psi/daq/queryrest/controller/QueryRestController.java
+++ b/src/main/java/ch/psi/daq/queryrest/controller/QueryRestController.java
@@ -18,6 +18,7 @@ import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
+import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.validation.DirectFieldBindingResult;
import org.springframework.validation.Errors;
@@ -39,6 +40,7 @@ import com.google.common.collect.Lists;
import ch.psi.daq.common.ordering.Ordering;
import ch.psi.daq.domain.backend.Backend;
import ch.psi.daq.domain.config.DomainConfig;
+import ch.psi.daq.domain.events.ChannelConfiguration;
import ch.psi.daq.domain.json.ChannelName;
import ch.psi.daq.domain.query.DAQConfigQuery;
import ch.psi.daq.domain.query.DAQConfigQueryElement;
@@ -176,12 +178,23 @@ public class QueryRestController implements ApplicationContextAware {
produces = {MediaType.APPLICATION_JSON_VALUE})
public void getChannelConfiguration(@RequestBody final ChannelName channelName, final HttpServletResponse res)
throws Throwable {
- ((AbstractHTTPResponse) defaultResponse).respond(
- context,
- res,
- null,
- queryManager.getChannelConfiguration(channelName),
- historicConfigFormatter);
+ try {
+ final ChannelConfiguration config = queryManager.getChannelConfiguration(channelName);
+
+ if (config != null) {
+ ((AbstractHTTPResponse) defaultResponse).respond(
+ context,
+ res,
+ null,
+ config,
+ historicConfigFormatter);
+ } else {
+ res.setStatus(HttpStatus.NOT_FOUND.value());
+ }
+ } catch (Throwable t) {
+ LOGGER.warn("Failed to get channel configuration.", t);
+ throw t;
+ }
}
@RequestMapping(