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`
|
||||
|
||||
## 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"/>
|
||||
|
||||
# REST Interface
|
||||
|
@ -18,10 +18,6 @@ applicationDefaultJvmArgs = [
|
||||
"-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5006"
|
||||
]
|
||||
|
||||
//configurations {
|
||||
// compile.exclude group: "com.fasterxml.jackson.core"
|
||||
//}
|
||||
|
||||
dependencies {
|
||||
compile (project(':ch.psi.daq.query'))
|
||||
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"; }
|
||||
}
|
@ -7,6 +7,7 @@ import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.function.Function;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
import javax.annotation.Resource;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
@ -71,6 +72,39 @@ public class QueryRestConfig extends WebMvcConfigurerAdapter {
|
||||
@Resource
|
||||
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}
|
||||
*/
|
||||
@ -81,44 +115,11 @@ public class QueryRestConfig extends WebMvcConfigurerAdapter {
|
||||
* This is necessary so that the message conversion uses the configured object mapper.
|
||||
* Otherwise, a separate object mapper is instantiated for Springs message conversion.
|
||||
*/
|
||||
converter.setObjectMapper(objectMapper());
|
||||
converter.setObjectMapper(objectMapper);
|
||||
converters.add(converter);
|
||||
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
|
||||
public JsonFactory jsonFactory() {
|
||||
return new JsonFactory();
|
||||
|
@ -107,6 +107,15 @@ public class QueryRestController {
|
||||
try {
|
||||
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);
|
||||
|
||||
// all the magic happens here
|
||||
@ -116,12 +125,7 @@ public class QueryRestController {
|
||||
// do post-process
|
||||
Stream<Entry<String, ?>> channelToData = queryAnalizer.postProcess(channelToDataEvents);
|
||||
|
||||
// write the response back to the client using java 8 streams
|
||||
responseStreamWriter.respond(channelToData, query, res);
|
||||
} catch (Throwable t) {
|
||||
LOGGER.error("Failed execute query '{}'.", query, t);
|
||||
throw t;
|
||||
}
|
||||
return channelToData;
|
||||
}
|
||||
|
||||
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
|
||||
# if no fields have been specified by the user
|
||||
queryrest.default.response.fields=channel,pulseId,globalMillis,globalNanos,iocMillis,iocNanos,shape,value
|
||||
|
Reference in New Issue
Block a user