Merge branch 'master' into ATEST-246

Conflicts:
	.settings/org.eclipse.jdt.core.prefs
	src/test/java/ch/psi/daq/test/queryrest/controller/DaqRestControllerTest.java
This commit is contained in:
Fabian Märki
2015-10-30 11:46:30 +01:00
9 changed files with 745 additions and 19 deletions
@@ -9,9 +9,11 @@ import java.util.function.Function;
import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import javax.servlet.Filter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
@@ -23,12 +25,6 @@ import org.springframework.util.StringUtils;
import org.springframework.validation.Validator;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import com.fasterxml.jackson.annotation.JsonInclude.Include;
import com.fasterxml.jackson.core.JsonFactory;
import com.fasterxml.jackson.core.Version;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.module.SimpleModule;
import ch.psi.daq.cassandra.util.test.CassandraDataGen;
import ch.psi.daq.common.statistic.StorelessStatistics;
import ch.psi.daq.domain.DataEvent;
@@ -39,11 +35,18 @@ import ch.psi.daq.query.model.Aggregation;
import ch.psi.daq.query.model.Query;
import ch.psi.daq.query.model.QueryField;
import ch.psi.daq.queryrest.controller.validator.QueryValidator;
import ch.psi.daq.queryrest.filter.CorsFilter;
import ch.psi.daq.queryrest.model.PropertyFilterMixin;
import ch.psi.daq.queryrest.response.JsonByteArraySerializer;
import ch.psi.daq.queryrest.response.JsonStreamSerializer;
import ch.psi.daq.queryrest.response.ResponseStreamWriter;
import com.fasterxml.jackson.annotation.JsonInclude.Include;
import com.fasterxml.jackson.core.JsonFactory;
import com.fasterxml.jackson.core.Version;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.module.SimpleModule;
@Configuration
@PropertySource(value = {"classpath:queryrest.properties"})
@PropertySource(value = {"file:${user.home}/.config/daq/queryrest.properties"}, ignoreResourceNotFound = true)
@@ -168,6 +171,12 @@ public class QueryRestConfig extends WebMvcConfigurerAdapter {
return new QueryValidator();
}
@Bean
@ConditionalOnProperty("queryrest.cors.enable")
public Filter corsFilter() {
return new CorsFilter();
}
// ==========================================================================================
// TODO: This is simply for initial / rudimentary testing - remove once further evolved
@Bean
@@ -2,9 +2,11 @@ package ch.psi.daq.queryrest.controller;
import java.io.IOException;
import java.util.Collection;
import java.util.List;
import java.util.Map.Entry;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import javax.annotation.Resource;
@@ -27,9 +29,11 @@ import org.springframework.web.bind.annotation.RestController;
import ch.psi.daq.cassandra.request.validate.RequestProviderValidator;
import ch.psi.daq.cassandra.util.test.CassandraDataGen;
import ch.psi.daq.common.json.deserialize.AttributeBasedDeserializer;
import ch.psi.daq.common.ordering.Ordering;
import ch.psi.daq.domain.DataEvent;
import ch.psi.daq.query.analyzer.QueryAnalyzer;
import ch.psi.daq.query.model.Aggregation;
import ch.psi.daq.query.model.AggregationType;
import ch.psi.daq.query.model.DBMode;
import ch.psi.daq.query.model.Query;
import ch.psi.daq.query.model.QueryField;
@@ -39,6 +43,8 @@ import ch.psi.daq.query.request.ChannelsRequest;
import ch.psi.daq.queryrest.config.QueryRestConfig;
import ch.psi.daq.queryrest.response.ResponseStreamWriter;
import com.google.common.collect.Lists;
@RestController
public class QueryRestController {
@@ -114,6 +120,68 @@ public class QueryRestController {
return getChannels(new ChannelsRequest(channelName));
}
/**
* Returns the current list of {@link Ordering}s available.
*
* @return list of {@link Ordering}s as String array
*/
@RequestMapping(value = "ordering", method = {RequestMethod.GET},
produces = {MediaType.APPLICATION_JSON_VALUE})
public @ResponseBody List<String> getOrderingValues() {
List<Ordering> orderings = Lists.newArrayList(Ordering.values());
return orderings.stream()
.map((Ordering ord) -> {
return ord.toString();
}).collect(Collectors.toList());
}
/**
* Returns the current list of {@link QueryField}s available.
*
* @return list of {@link QueryField}s as String array
*/
@RequestMapping(value = "queryfields", method = {RequestMethod.GET},
produces = {MediaType.APPLICATION_JSON_VALUE})
public @ResponseBody List<String> getQueryFieldValues() {
List<QueryField> orderings = Lists.newArrayList(QueryField.values());
return orderings.stream()
.map((QueryField qf) -> {
return qf.toString();
}).collect(Collectors.toList());
}
/**
* Returns the current list of {@link Aggregation}s available.
*
* @return list of {@link Aggregation}s as String array
*/
@RequestMapping(value = "aggregations", method = {RequestMethod.GET},
produces = {MediaType.APPLICATION_JSON_VALUE})
public @ResponseBody List<String> getAggregationsValues() {
List<Aggregation> orderings = Lists.newArrayList(Aggregation.values());
return orderings.stream()
.map((Aggregation value) -> {
return value.toString();
}).collect(Collectors.toList());
}
/**
* Returns the current list of {@link AggregationType}s available.
*
* @return list of {@link AggregationType}s as String array
*/
@RequestMapping(value = "aggregationtypes", method = {RequestMethod.GET},
produces = {MediaType.APPLICATION_JSON_VALUE})
public @ResponseBody List<String> getAggregationTypesValues() {
List<AggregationType> orderings = Lists.newArrayList(AggregationType.values());
return orderings.stream()
.map((AggregationType value) -> {
return value.toString();
}).collect(Collectors.toList());
}
/**
* Catch-all query method for getting data from the backend.
* <p>
@@ -143,8 +211,8 @@ public class QueryRestController {
QueryAnalyzer queryAnalizer = queryAnalizerFactory.apply(query);
// all the magic happens here
Stream<Entry<String, Stream<? extends DataEvent>>> channelToDataEvents = getQueryProcessor(query.getDbMode())
.process(queryAnalizer);
Stream<Entry<String, Stream<? extends DataEvent>>> channelToDataEvents =
getQueryProcessor(query.getDbMode()).process(queryAnalizer);
// do post-process
Stream<Entry<String, ?>> channelToData = queryAnalizer.postProcess(channelToDataEvents);
@@ -0,0 +1,80 @@
package ch.psi.daq.queryrest.filter;
import java.io.IOException;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
import java.util.stream.Collectors;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.filter.OncePerRequestFilter;
public class CorsFilter extends OncePerRequestFilter {
private static final String ALLOW_ORIGIN_HEADER = "Access-Control-Allow-Origin";
@Value("${queryrest.cors.allowedorigins}")
private String configuredOrigins;
@Value("${queryrest.cors.forceallheaders}")
private boolean forceAllHeaders;
/**
* @{inheritDoc
*/
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
Set<String> allowedOrigins = new HashSet<String>(Arrays.asList(configuredOrigins.split(","))
.stream()
.map(s -> {
return s.trim(); })
.collect(Collectors.toList()));
String originHeader = request.getHeader("Origin");
if (forceAllHeaders) {
// include headers no matter what - good for development
if (allowedOrigins.contains(originHeader)) {
response.addHeader(ALLOW_ORIGIN_HEADER, originHeader);
} else {
response.addHeader(ALLOW_ORIGIN_HEADER, "*");
}
setDefaultCorsHeaders(response);
} else if (request.getHeader("Access-Control-Request-Method") != null && "OPTIONS".equals(request.getMethod())) {
// this is for 'real' Cross-site browser requests
if (allowedOrigins.contains(originHeader)) {
response.addHeader(ALLOW_ORIGIN_HEADER, originHeader);
}
setDefaultCorsHeaders(response);
}
filterChain.doFilter(request, response);
}
private void setDefaultCorsHeaders(HttpServletResponse response) {
response.addHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
response.addHeader("Access-Control-Allow-Headers", "Origin, Authorization, Accept, Content-Type");
response.addHeader("Access-Control-Max-Age", "1800");
}
public void setConfiguredOrigins(String configuredOrigins) {
this.configuredOrigins = configuredOrigins;
}
public void setForceAllHeaders(boolean forceAllHeaders) {
this.forceAllHeaders = forceAllHeaders;
}
}