ATEST-242
This commit is contained in:
20
Readme.md
20
Readme.md
@ -20,6 +20,26 @@ Following files define and describe application properties:
|
|||||||
|
|
||||||
It is possible to overwrite properties by defining new values in `${HOME}/.config/daq/queryrest.properties`
|
It is possible to overwrite properties by defining new values in `${HOME}/.config/daq/queryrest.properties`
|
||||||
|
|
||||||
|
## Maven
|
||||||
|
|
||||||
|
Upload jar to the Maven repository (from ch.psi.daq.buildall):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./gradlew ch.psi.daq.queryrest:uploadArchives
|
||||||
|
```
|
||||||
|
|
||||||
|
## DropIt
|
||||||
|
|
||||||
|
Upload jar DropIt (from ch.psi.daq.buildall):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./gradlew ch.psi.daq.queryrest:dropIt -x test
|
||||||
|
```
|
||||||
|
|
||||||
|
## Local Instance
|
||||||
|
|
||||||
|
[DAQLocal](https://github.psi.ch/projects/ST/repos/ch.psi.daq.daqlocal/browse) provides a local instance of the DAQ system for testing purposes (allowing users/developers to verify their code before they come to PSI to do their research and interact with the DAQ cluster).
|
||||||
|
|
||||||
<a name="rest_interface"/>
|
<a name="rest_interface"/>
|
||||||
|
|
||||||
# REST Interface
|
# REST Interface
|
||||||
|
@ -18,10 +18,6 @@ applicationDefaultJvmArgs = [
|
|||||||
"-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5006"
|
"-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5006"
|
||||||
]
|
]
|
||||||
|
|
||||||
//configurations {
|
|
||||||
// compile.exclude group: "com.fasterxml.jackson.core"
|
|
||||||
//}
|
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
compile (project(':ch.psi.daq.query'))
|
compile (project(':ch.psi.daq.query'))
|
||||||
compile 'org.hibernate:hibernate-validator:5.2.0.Final'
|
compile 'org.hibernate:hibernate-validator:5.2.0.Final'
|
||||||
@ -42,6 +38,6 @@ uploadArchives {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
task dropItQueryREST(dependsOn: build) << {
|
task dropIt(dependsOn: build) << {
|
||||||
exec{ executable "curl"; args "-X", "POST", "-F", "file=@build/libs/ch.psi.daq.queryrest-" + version + ".jar", "http://dropit.psi.ch:8080/upload"; }
|
exec{ executable "curl"; args "-X", "POST", "-F", "file=@build/libs/ch.psi.daq.queryrest-" + version + ".jar", "http://dropit.psi.ch:8080/upload"; }
|
||||||
}
|
}
|
@ -7,6 +7,7 @@ import java.util.List;
|
|||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
|
|
||||||
|
import javax.annotation.PostConstruct;
|
||||||
import javax.annotation.Resource;
|
import javax.annotation.Resource;
|
||||||
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
@ -71,6 +72,39 @@ public class QueryRestConfig extends WebMvcConfigurerAdapter {
|
|||||||
@Resource
|
@Resource
|
||||||
private Environment env;
|
private Environment env;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private ObjectMapper objectMapper;
|
||||||
|
|
||||||
|
@PostConstruct
|
||||||
|
public void afterPropertiesSet() {
|
||||||
|
// add deserializers to ObjectMapper
|
||||||
|
String packageName = AbstractQuery.class.getPackage().getName();
|
||||||
|
Class<AbstractQuery> abstractQueryClass = AbstractQuery.class;
|
||||||
|
AttributeBasedDeserializer<AbstractQuery> abstractQueryDeserializer =
|
||||||
|
new AttributeBasedDeserializer<AbstractQuery>(abstractQueryClass).register(packageName);
|
||||||
|
SimpleModule module = new SimpleModule("PolymorphicAbstractQuery", Version.unknownVersion());
|
||||||
|
module.addDeserializer(abstractQueryClass, abstractQueryDeserializer);
|
||||||
|
objectMapper.registerModule(module);
|
||||||
|
|
||||||
|
// only include non-null values
|
||||||
|
objectMapper.setSerializationInclusion(Include.NON_NULL);
|
||||||
|
// Mixin which is used dynamically to filter out which properties get serialised and which
|
||||||
|
// won't. This way, the user can specify which columns are to be received.
|
||||||
|
objectMapper.addMixIn(DataEvent.class, PropertyFilterMixin.class);
|
||||||
|
objectMapper.addMixIn(StorelessStatistics.class, PropertyFilterMixin.class);
|
||||||
|
objectMapper.addMixIn(EnumMap.class, PropertyFilterMixin.class);
|
||||||
|
|
||||||
|
// defines how to writer inner Streams (i.e. Stream<Entry<String, Stream<?>>> toSerialize)
|
||||||
|
module = new SimpleModule("Streams API", Version.unknownVersion());
|
||||||
|
module.addSerializer(new JsonStreamSerializer());
|
||||||
|
objectMapper.registerModule(module);
|
||||||
|
|
||||||
|
// by default, byte[] are written as String
|
||||||
|
module = new SimpleModule("byte[]", Version.unknownVersion());
|
||||||
|
module.addSerializer(new JsonByteArraySerializer());
|
||||||
|
objectMapper.registerModule(module);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@inheritDoc}
|
* {@inheritDoc}
|
||||||
*/
|
*/
|
||||||
@ -81,44 +115,11 @@ public class QueryRestConfig extends WebMvcConfigurerAdapter {
|
|||||||
* This is necessary so that the message conversion uses the configured object mapper.
|
* This is necessary so that the message conversion uses the configured object mapper.
|
||||||
* Otherwise, a separate object mapper is instantiated for Springs message conversion.
|
* Otherwise, a separate object mapper is instantiated for Springs message conversion.
|
||||||
*/
|
*/
|
||||||
converter.setObjectMapper(objectMapper());
|
converter.setObjectMapper(objectMapper);
|
||||||
converters.add(converter);
|
converters.add(converter);
|
||||||
super.configureMessageConverters(converters);
|
super.configureMessageConverters(converters);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Bean
|
|
||||||
public ObjectMapper objectMapper() {
|
|
||||||
ObjectMapper mapper = new ObjectMapper();
|
|
||||||
|
|
||||||
String packageName = AbstractQuery.class.getPackage().getName();
|
|
||||||
Class<AbstractQuery> abstractQueryClass = AbstractQuery.class;
|
|
||||||
AttributeBasedDeserializer<AbstractQuery> abstractQueryDeserializer =
|
|
||||||
new AttributeBasedDeserializer<AbstractQuery>(abstractQueryClass).register(packageName);
|
|
||||||
SimpleModule module = new SimpleModule("PolymorphicAbstractQuery", Version.unknownVersion());
|
|
||||||
module.addDeserializer(abstractQueryClass, abstractQueryDeserializer);
|
|
||||||
mapper.registerModule(module);
|
|
||||||
|
|
||||||
// only include non-null values
|
|
||||||
mapper.setSerializationInclusion(Include.NON_NULL);
|
|
||||||
// Mixin which is used dynamically to filter out which properties get serialised and which
|
|
||||||
// won't. This way, the user can specify which columns are to be received.
|
|
||||||
mapper.addMixIn(DataEvent.class, PropertyFilterMixin.class);
|
|
||||||
mapper.addMixIn(StorelessStatistics.class, PropertyFilterMixin.class);
|
|
||||||
mapper.addMixIn(EnumMap.class, PropertyFilterMixin.class);
|
|
||||||
|
|
||||||
// defines how to writer inner Streams (i.e. Stream<Entry<String, Stream<?>>> toSerialize)
|
|
||||||
module = new SimpleModule("Streams API", Version.unknownVersion());
|
|
||||||
module.addSerializer(new JsonStreamSerializer());
|
|
||||||
mapper.registerModule(module);
|
|
||||||
|
|
||||||
// by default, byte[] are written as String
|
|
||||||
module = new SimpleModule("byte[]", Version.unknownVersion());
|
|
||||||
module.addSerializer(new JsonByteArraySerializer());
|
|
||||||
mapper.registerModule(module);
|
|
||||||
|
|
||||||
return mapper;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
public JsonFactory jsonFactory() {
|
public JsonFactory jsonFactory() {
|
||||||
return new JsonFactory();
|
return new JsonFactory();
|
||||||
|
@ -107,6 +107,15 @@ public class QueryRestController {
|
|||||||
try {
|
try {
|
||||||
LOGGER.debug("Executing query '{}'", query.getClass().getSimpleName());
|
LOGGER.debug("Executing query '{}'", query.getClass().getSimpleName());
|
||||||
|
|
||||||
|
// write the response back to the client using java 8 streams
|
||||||
|
responseStreamWriter.respond(executeQuery(query), query, res);
|
||||||
|
} catch (Throwable t) {
|
||||||
|
LOGGER.error("Failed execute query '{}'.", query, t);
|
||||||
|
throw t;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Stream<Entry<String, ?>> executeQuery(AbstractQuery query) {
|
||||||
QueryAnalyzer queryAnalizer = queryAnalizerFactory.apply(query);
|
QueryAnalyzer queryAnalizer = queryAnalizerFactory.apply(query);
|
||||||
|
|
||||||
// all the magic happens here
|
// all the magic happens here
|
||||||
@ -116,12 +125,7 @@ public class QueryRestController {
|
|||||||
// do post-process
|
// do post-process
|
||||||
Stream<Entry<String, ?>> channelToData = queryAnalizer.postProcess(channelToDataEvents);
|
Stream<Entry<String, ?>> channelToData = queryAnalizer.postProcess(channelToDataEvents);
|
||||||
|
|
||||||
// write the response back to the client using java 8 streams
|
return channelToData;
|
||||||
responseStreamWriter.respond(channelToData, query, res);
|
|
||||||
} catch (Throwable t) {
|
|
||||||
LOGGER.error("Failed execute query '{}'.", query, t);
|
|
||||||
throw t;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private QueryProcessor getQueryProcessor(DBMode dbMode) {
|
private QueryProcessor getQueryProcessor(DBMode dbMode) {
|
||||||
|
@ -1,6 +1,3 @@
|
|||||||
# port for the Spring boot application's embedded Tomcat server
|
|
||||||
server.port=8080
|
|
||||||
|
|
||||||
# defines the fields that are included in the response
|
# defines the fields that are included in the response
|
||||||
# if no fields have been specified by the user
|
# if no fields have been specified by the user
|
||||||
queryrest.default.response.fields=channel,pulseId,globalMillis,globalNanos,iocMillis,iocNanos,shape,value
|
queryrest.default.response.fields=channel,pulseId,globalMillis,globalNanos,iocMillis,iocNanos,shape,value
|
||||||
|
Reference in New Issue
Block a user