
org.n52.web.ctrl.data.DataController Maven / Gradle / Ivy
The newest version!
/*
* Copyright (C) 2013-2019 52°North Initiative for Geospatial Open Source
* Software GmbH
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published
* by the Free Software Foundation.
*
* If the program is linked with libraries which are licensed under one of
* the following licenses, the combination of the program with the linked
* library is not considered a "derivative work" of the program:
*
* - Apache License, version 2.0
* - Apache Software License, version 1.0
* - GNU Lesser General Public License, version 3
* - Mozilla Public License, versions 1.0, 1.1 and 2.0
* - Common Development and Distribution License (CDDL), version 1.0
*
* Therefore the distribution of the program linked with libraries licensed
* under the aforementioned licenses, is permitted by the copyright holders
* if the distribution is compliant with both the GNU General Public License
* version 2 and the aforementioned licenses.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
package org.n52.web.ctrl.data;
import java.io.IOException;
import java.io.InputStream;
import java.util.Arrays;
import java.util.Collections;
import java.util.Map;
import java.util.Set;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.io.IOUtils;
import org.joda.time.DateTime;
import org.joda.time.Duration;
import org.joda.time.Interval;
import org.joda.time.Period;
import org.n52.io.Constants;
import org.n52.io.IntervalWithTimeZone;
import org.n52.io.handler.DatasetFactoryException;
import org.n52.io.handler.DefaultIoFactory;
import org.n52.io.handler.IoHandlerFactory;
import org.n52.io.handler.IoProcessChain;
import org.n52.io.request.IoParameters;
import org.n52.io.request.Parameters;
import org.n52.io.request.RequestSimpleParameterSet;
import org.n52.io.request.RequestStyledParameterSet;
import org.n52.io.response.dataset.AbstractValue;
import org.n52.io.response.dataset.Data;
import org.n52.io.response.dataset.DataCollection;
import org.n52.io.response.dataset.DatasetOutput;
import org.n52.series.spi.srv.DataService;
import org.n52.series.spi.srv.ParameterService;
import org.n52.series.spi.srv.RawDataService;
import org.n52.series.spi.srv.RawFormats;
import org.n52.web.ctrl.BaseController;
import org.n52.web.exception.BadRequestException;
import org.n52.web.exception.InternalServerException;
import org.n52.web.exception.ResourceNotFoundException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.util.MultiValueMap;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.ModelAndView;
public abstract class DataController extends BaseController {
protected static final String CONTENT_DISPOSITION_HEADER = "Content-Disposition";
protected static final String CONTENT_DISPOSITION_VALUE_TEMPLATE =
"attachment; filename=\"Observations_for_Dataset_";
protected static final String SHOWTIMEINTERVALS_QUERY_OPTION = "showTimeIntervals";
protected static final String PROFILE = "profile";
protected static final String OBSERVATIONS = "observations";
private static final Logger LOGGER = LoggerFactory.getLogger(DatasetsDataController.class);
private static final String DEFAULT_RESPONSE_ENCODING = "UTF-8";
private final DefaultIoFactory>, AbstractValue< ? >> ioFactoryCreator;
private final DataService>> dataService;
private final ParameterService>> datasetService;
@Value("${requestIntervalRestriction:P370D}")
private String requestIntervalRestriction;
@Autowired
public DataController(DefaultIoFactory>, AbstractValue< ? >> ioFactory,
ParameterService>> datasetService,
DataService>> dataService) {
this.ioFactoryCreator = ioFactory;
this.datasetService = datasetService;
this.dataService = dataService;
}
protected abstract String getValueType(IoParameters map, String requestUrl);
protected ParameterService>> getDatasetService() {
return datasetService;
}
@RequestMapping(value = "/{datasetId}/observations",
produces = {
Constants.APPLICATION_JSON
},
method = RequestMethod.GET)
public ModelAndView getSeriesData(HttpServletRequest request,
HttpServletResponse response,
@PathVariable String datasetId,
@RequestHeader(value = Parameters.HttpHeader.ACCEPT_LANGUAGE,
required = false) String locale,
@RequestParam(required = false) MultiValueMap query)
throws Exception {
IoParameters map = createParameters(datasetId, query, locale, response);
LOGGER.debug("get data for item '{}' with query: {}", datasetId, map);
checkAgainstTimespanRestriction(map.getTimespan());
checkForUnknownDatasetId(map.removeAllOf(Parameters.BBOX)
.removeAllOf(Parameters.NEAR),
datasetId);
// RequestSimpleIoParameters parameters = RequestSimpleIoParameters.createForSingleSeries(seriesId,
// map);
// String valueType = ValueType.extractType(datasetId, handleAsValueTypeFallback);
String valueType = getValueType(map, request.getRequestURI());
IoProcessChain< ? > ioChain = createIoFactory(valueType).setParameters(map)
.createProcessChain();
DataCollection< ? > formattedDataCollection = ioChain.getProcessedData();
final Map processed = formattedDataCollection.getAllSeries();
return map.isExpanded()
? new ModelAndView().addObject(processed)
: new ModelAndView().addObject(processed.get(datasetId));
}
@RequestMapping(value = "/observations",
produces = {
Constants.APPLICATION_JSON
},
method = RequestMethod.POST)
public ModelAndView getCollectionData(HttpServletRequest request,
HttpServletResponse response,
@RequestHeader(value = Parameters.HttpHeader.ACCEPT_LANGUAGE,
required = false) String locale,
@RequestBody RequestSimpleParameterSet simpleParameters)
throws Exception {
IoParameters parameters = createParameters(simpleParameters, locale, response);
LOGGER.debug("get data collection with parameter set: {}", parameters);
checkForUnknownDatasetIds(parameters, parameters.getDatasets());
checkAgainstTimespanRestriction(parameters.getTimespan());
// final String datasetType = getValueType(parameters);
final String valueType = getValueType(parameters, request.getRequestURI());
IoProcessChain< ? > ioChain = createIoFactory(valueType).setParameters(parameters)
.createProcessChain();
DataCollection< ? > processed = ioChain.getData();
return new ModelAndView().addObject(processed.getAllSeries());
}
// private String getValueType(IoParameters parameters) {
// String handleAs = parameters.getOther(Parameters.HANDLE_AS_VALUE_TYPE);
// Set datasetIds = parameters.getDatasets();
// Iterator iterator = datasetIds.iterator();
// return iterator.hasNext()
// ? ValueType.extractType(iterator.next(), handleAs)
// : ValueType.DEFAULT_VALUE_TYPE;
// }
@RequestMapping(value = "/observations",
params = {
RawFormats.RAW_FORMAT
},
method = RequestMethod.POST)
public void getRawSeriesCollectionData(HttpServletResponse response,
@RequestHeader(value = Parameters.HttpHeader.ACCEPT_LANGUAGE,
required = false) String locale,
@RequestBody RequestSimpleParameterSet simpleParameters)
throws Exception {
IoParameters parameters = createParameters(simpleParameters, locale, response);
checkForUnknownDatasetIds(parameters, parameters.getDatasets());
writeRawData(parameters, response);
}
@RequestMapping(value = "/{datasetId}/observations",
method = RequestMethod.GET,
params = {
RawFormats.RAW_FORMAT
})
public void getRawSeriesData(HttpServletResponse response,
@PathVariable String datasetId,
@RequestHeader(value = Parameters.HttpHeader.ACCEPT_LANGUAGE,
required = false) String locale,
@RequestParam MultiValueMap query) {
IoParameters parameters = createParameters(datasetId, query, locale, response);
checkForUnknownDatasetId(parameters, datasetId);
writeRawData(parameters, response);
}
private void writeRawData(IoParameters parameters, HttpServletResponse response)
throws InternalServerException, ResourceNotFoundException, BadRequestException {
LOGGER.debug("get raw data collection with parameters: {}", parameters);
if (!dataService.supportsRawData()) {
throw new BadRequestException("Querying of raw timeseries data is not supported "
+ "by the underlying service!");
}
final RawDataService rawDataService = dataService.getRawDataService();
try (InputStream inputStream = rawDataService.getRawData(parameters)) {
response.setContentType(parameters.getRawFormat());
IOUtils.copyLarge(inputStream, response.getOutputStream());
} catch (IOException e) {
throw new InternalServerException("Error while querying raw data", e);
}
}
@RequestMapping(value = "/observations",
produces = {
Constants.APPLICATION_PDF
},
method = RequestMethod.POST)
public void getSeriesCollectionReport(HttpServletRequest request,
HttpServletResponse response,
@RequestHeader(value = Parameters.HttpHeader.ACCEPT_LANGUAGE,
required = false) String locale,
@RequestBody RequestStyledParameterSet simpleParameters)
throws Exception {
IoParameters parameters = createParameters(simpleParameters, locale, response);
LOGGER.debug("get data collection report with query: {}", parameters);
checkForUnknownDatasetIds(parameters, parameters.getDatasets());
checkAgainstTimespanRestriction(parameters.getTimespan());
// final String datasetType = getValueType(parameters);
final String valueType = getValueType(parameters, request.getRequestURI());
String outputFormat = Constants.APPLICATION_PDF;
response.setContentType(outputFormat);
createIoFactory(valueType).setParameters(parameters)
.createHandler(outputFormat)
.writeBinary(response.getOutputStream());
}
@RequestMapping(value = "/{datasetId}/observations",
produces = {
Constants.APPLICATION_PDF
},
method = RequestMethod.GET)
public void getSeriesReport(HttpServletRequest request,
HttpServletResponse response,
@PathVariable String datasetId,
@RequestHeader(value = Parameters.HttpHeader.ACCEPT_LANGUAGE,
required = false) String locale,
@RequestParam(required = false) MultiValueMap query)
throws Exception {
IoParameters parameters = createParameters(datasetId, query, locale, response);
LOGGER.debug("get data collection report for '{}' with query: {}", datasetId, parameters);
checkAgainstTimespanRestriction(parameters.getTimespan());
checkForUnknownDatasetId(parameters, datasetId);
// final String datasetType = getValueType(parameters);
final String valueType = getValueType(parameters, request.getRequestURI());
String outputFormat = Constants.APPLICATION_PDF;
response.setContentType(outputFormat);
response.setHeader(CONTENT_DISPOSITION_HEADER, CONTENT_DISPOSITION_VALUE_TEMPLATE + datasetId + ".pdf\"");
createIoFactory(valueType).setParameters(parameters)
.createHandler(outputFormat)
.writeBinary(response.getOutputStream());
}
@RequestMapping(value = "/{datasetId}/observations",
produces = {
Constants.APPLICATION_ZIP
},
method = RequestMethod.GET)
public void getSeriesAsZippedCsv(HttpServletRequest request,
HttpServletResponse response,
@PathVariable String datasetId,
@RequestHeader(value = Parameters.HttpHeader.ACCEPT_LANGUAGE,
required = false) String locale,
@RequestParam(required = false) MultiValueMap query)
throws Exception {
// Needed to retrieve Time Ends from Database
query.putIfAbsent(SHOWTIMEINTERVALS_QUERY_OPTION, Arrays.asList(Boolean.TRUE.toString()));
IoParameters parameters = createParameters(datasetId, query, locale, response);
LOGGER.debug("get data collection zip for '{}' with query: {}", datasetId, parameters);
checkAgainstTimespanRestriction(parameters.getTimespan());
checkForUnknownDatasetId(parameters, datasetId);
response.setCharacterEncoding(DEFAULT_RESPONSE_ENCODING);
response.setContentType(Constants.APPLICATION_ZIP);
response.setHeader(CONTENT_DISPOSITION_HEADER, CONTENT_DISPOSITION_VALUE_TEMPLATE + datasetId + ".zip\"");
// final String datasetType = getValueType(parameters);
final String valueType = getValueType(parameters, request.getRequestURI());
createIoFactory(valueType).setParameters(parameters)
.createHandler(Constants.APPLICATION_ZIP)
.writeBinary(response.getOutputStream());
}
@RequestMapping(value = "/{datasetId}/observations",
produces = {
Constants.TEXT_CSV
},
method = RequestMethod.GET)
public void getSeriesAsCsv(HttpServletRequest request,
HttpServletResponse response,
@PathVariable String datasetId,
@RequestHeader(value = Parameters.HttpHeader.ACCEPT_LANGUAGE,
required = false) String locale,
@RequestParam(required = false) MultiValueMap query)
throws Exception {
IoParameters parameters = createParameters(datasetId, query, locale, response);
LOGGER.debug("get data collection csv for '{}' with query: {}", datasetId, parameters);
checkAgainstTimespanRestriction(parameters.getTimespan());
checkForUnknownDatasetId(parameters, datasetId);
String extension = ".";
response.setCharacterEncoding(DEFAULT_RESPONSE_ENCODING);
if (Boolean.parseBoolean(parameters.getOther(Parameters.ZIP))) {
response.setContentType(Constants.APPLICATION_ZIP);
extension += Parameters.ZIP;
} else {
response.setContentType(Constants.TEXT_CSV);
extension += "csv";
}
response.setHeader(CONTENT_DISPOSITION_HEADER,
CONTENT_DISPOSITION_VALUE_TEMPLATE
+ datasetId
+ extension
+ "\"");
// final String datasetType = getValueType(parameters);
final String valueType = getValueType(parameters, request.getRequestURI());
createIoFactory(valueType).setParameters(parameters)
.createHandler(Constants.TEXT_CSV)
.writeBinary(response.getOutputStream());
}
protected void checkAgainstTimespanRestriction(IntervalWithTimeZone timespan) {
if (requestIntervalRestriction != null) {
Duration duration = Period.parse(requestIntervalRestriction)
.toDurationFrom(new DateTime());
if (duration.getMillis() < Interval.parse(timespan.toString())
.toDurationMillis()) {
throw new BadRequestException("Timespan too long, please use a period shorter than '"
+ requestIntervalRestriction
+ "'");
}
}
}
protected void checkForUnknownDatasetId(IoParameters parameters, String seriesId) {
checkForUnknownDatasetIds(parameters, Collections.singleton(seriesId));
}
protected void checkForUnknownDatasetIds(IoParameters parameters, Set seriesIds) {
if (seriesIds != null) {
for (String id : seriesIds) {
if (!datasetService.exists(id, parameters)) {
throw new ResourceNotFoundException("Series with id '" + id + "' wasn't found.");
}
}
}
}
@SuppressWarnings("checkstyle:linelength")
protected IoHandlerFactory>, AbstractValue< ? >> createIoFactory(final String valueType)
throws DatasetFactoryException {
if (!ioFactoryCreator.isKnown(valueType)) {
throw new ResourceNotFoundException("unknown dataset type: " + valueType);
}
return ioFactoryCreator.create(valueType)
.setDataService(dataService)
.setDatasetService(datasetService);
}
@Override
protected void addCacheHeader(IoParameters parameter, HttpServletResponse response) {
parameter.getCache()
.map(node -> node.asLong(0))
.ifPresent(v -> addCacheHeader(response, v));
}
protected boolean isProfileType(DatasetOutput> item) {
String observationType = item.getObservationType();
String datasetType = item.getDatasetType();
return observationType.equals(PROFILE)
|| datasetType.equals(PROFILE);
}
protected DatasetOutput> getFirstDatasetOutput(IoParameters map) {
return datasetService.getCondensedParameters(map)
.getItem(0);
}
public String getRequestIntervalRestriction() {
return requestIntervalRestriction;
}
public void setRequestIntervalRestriction(String requestIntervalRestriction) {
// validate requestIntervalRestriction, if it's no period an exception occured
Period.parse(requestIntervalRestriction);
LOGGER.debug("CONFIG: request.interval.restriction={}", requestIntervalRestriction);
this.requestIntervalRestriction = requestIntervalRestriction;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy