org.n52.web.ctrl.TimeseriesDataController.java Source code

Java tutorial

Introduction

Here is the source code for org.n52.web.ctrl.TimeseriesDataController.java

Source

/*
 * Copyright (C) 2013-2016 52North 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;

import static org.n52.io.MimeType.APPLICATION_ZIP;
import static org.n52.io.MimeType.TEXT_CSV;
import static org.n52.io.request.IoParameters.createFromQuery;
import static org.n52.io.request.QueryParameters.createFromQuery;
import static org.n52.io.request.RequestSimpleParameterSet.createForSingleSeries;
import static org.n52.io.request.RequestSimpleParameterSet.createFromDesignedParameters;
import static org.n52.series.spi.srv.GeneralizingMeasurementDataService.composeDataService;
import static org.n52.web.common.Stopwatch.startStopwatch;
import static org.n52.web.ctrl.UrlSettings.COLLECTION_TIMESERIES;
import static org.springframework.web.bind.annotation.RequestMethod.GET;
import static org.springframework.web.bind.annotation.RequestMethod.POST;

import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Arrays;

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.DatasetFactoryException;
import org.n52.io.DefaultIoFactory;
import org.n52.io.IntervalWithTimeZone;
import org.n52.io.IoFactory;
import org.n52.io.MimeType;
import org.n52.io.PreRenderingJob;
import org.n52.io.measurement.format.FormatterFactory;
import org.n52.io.request.IoParameters;
import org.n52.io.request.RequestParameterSet;
import org.n52.io.request.RequestSimpleParameterSet;
import org.n52.io.request.RequestStyledParameterSet;
import org.n52.io.response.dataset.DataCollection;
import org.n52.io.response.dataset.measurement.MeasurementData;
import org.n52.io.response.dataset.measurement.MeasurementDatasetOutput;
import org.n52.io.response.dataset.measurement.MeasurementValue;
import org.n52.io.v1.data.RawFormats;
import org.n52.series.spi.srv.DataService;
import org.n52.series.spi.srv.ParameterService;
import org.n52.web.common.Stopwatch;
import org.n52.web.exception.BadRequestException;
import org.n52.web.exception.InternalServerException;
import org.n52.web.exception.ResourceNotFoundException;
import org.n52.web.exception.WebExceptionAdapter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
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.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.ModelAndView;

@Deprecated
@RestController
@RequestMapping(value = COLLECTION_TIMESERIES, produces = { "application/json" })
public class TimeseriesDataController extends BaseController {

    private final static Logger LOGGER = LoggerFactory.getLogger(TimeseriesDataController.class);

    private ParameterService<MeasurementDatasetOutput> timeseriesMetadataService;

    private DataService<MeasurementData> timeseriesDataService;

    private PreRenderingJob preRenderingTask;

    private String requestIntervalRestriction;

    @RequestMapping(value = "/getData", produces = { "application/json" }, method = POST)
    public ModelAndView getTimeseriesCollectionData(HttpServletResponse response,
            @RequestBody RequestSimpleParameterSet parameters) throws Exception {

        checkIfUnknownTimeseries(parameters, parameters.getDatasets());
        if (parameters.isSetRawFormat()) {
            getRawTimeseriesCollectionData(response, parameters);
            return null;
        }

        DataCollection<MeasurementData> seriesData = getTimeseriesData(parameters);
        DataCollection<?> formattedDataCollection = format(seriesData, parameters.getFormat());
        return new ModelAndView().addObject(formattedDataCollection.getAllSeries());
    }

    @RequestMapping(value = "/{timeseriesId}/getData", produces = { "application/json" }, method = GET)
    public ModelAndView getTimeseriesData(HttpServletResponse response, @PathVariable String timeseriesId,
            @RequestParam(required = false) MultiValueMap<String, String> query) {

        IoParameters map = createFromQuery(query);
        checkIfUnknownTimeseries(map, timeseriesId);

        IntervalWithTimeZone timespan = map.getTimespan();
        checkAgainstTimespanRestriction(timespan.toString());
        RequestSimpleParameterSet parameters = createForSingleSeries(timeseriesId, map);
        if (map.getResultTime() != null) {
            parameters.setResultTime(map.getResultTime().toString());
        }

        parameters.setGeneralize(map.isGeneralize());
        parameters.setExpanded(map.isExpanded());

        // TODO add paging
        DataCollection<MeasurementData> seriesData = getTimeseriesData(parameters);
        DataCollection<?> formattedDataCollection = format(seriesData, map.getFormat());
        if (map.isExpanded()) {
            return new ModelAndView().addObject(formattedDataCollection.getAllSeries());
        }
        Object formattedTimeseries = formattedDataCollection.getAllSeries().get(timeseriesId);
        return new ModelAndView().addObject(formattedTimeseries);
    }

    @RequestMapping(value = "/getData", method = POST, params = { RawFormats.RAW_FORMAT })
    public void getRawTimeseriesCollectionData(HttpServletResponse response,
            @RequestBody RequestSimpleParameterSet parameters) throws Exception {
        checkIfUnknownTimeseries(parameters, parameters.getDatasets());
        if (!timeseriesDataService.supportsRawData()) {
            throw new BadRequestException(
                    "Querying of raw timeseries data is not supported by the underlying service!");
        }

        try (InputStream inputStream = timeseriesDataService.getRawDataService().getRawData(parameters)) {
            if (inputStream == null) {
                throw new ResourceNotFoundException("No raw data found.");
            }
            IOUtils.copyLarge(inputStream, response.getOutputStream());
        } catch (IOException e) {
            throw new InternalServerException("Error while querying raw data", e);
        }
    }

    @RequestMapping(value = "/{timeseriesId}/getData", method = GET, params = { RawFormats.RAW_FORMAT })
    public void getRawTimeseriesData(HttpServletResponse response, @PathVariable String timeseriesId,
            @RequestParam MultiValueMap<String, String> query) {
        IoParameters map = createFromQuery(query);
        checkIfUnknownTimeseries(map, timeseriesId);
        RequestSimpleParameterSet parameters = createForSingleSeries(timeseriesId, map);
        if (!timeseriesDataService.supportsRawData()) {
            throw new BadRequestException(
                    "Querying of raw procedure data is not supported by the underlying service!");
        }
        try (InputStream inputStream = timeseriesDataService.getRawDataService().getRawData(parameters)) {
            if (inputStream == null) {
                throw new ResourceNotFoundException("No raw data found for id '" + timeseriesId + "'.");
            }
            IOUtils.copyLarge(inputStream, response.getOutputStream());
        } catch (IOException e) {
            throw new InternalServerException("Error while querying raw data", e);
        }
    }

    private DataCollection<?> format(DataCollection<MeasurementData> timeseriesData, String format) {
        return FormatterFactory.createFormatterFactory(format).create().format(timeseriesData);
    }

    @RequestMapping(value = "/getData", produces = { "application/pdf" }, method = POST)
    public void getTimeseriesCollectionReport(HttpServletResponse response,
            @RequestBody RequestStyledParameterSet requestParameters) throws Exception {

        IoParameters map = createFromQuery(requestParameters);
        checkIfUnknownTimeseries(map, requestParameters.getDatasets());

        RequestSimpleParameterSet parameters = createFromDesignedParameters(requestParameters);
        checkAgainstTimespanRestriction(parameters.getTimespan());
        parameters.setGeneralize(map.isGeneralize());
        parameters.setExpanded(map.isExpanded());

        response.setContentType(MimeType.APPLICATION_PDF.getMimeType());
        createIoFactory(parameters).withStyledRequest(requestParameters)
                .createHandler(MimeType.APPLICATION_PDF.getMimeType()).writeBinary(response.getOutputStream());
    }

    private IoFactory<MeasurementData, MeasurementDatasetOutput, MeasurementValue> createIoFactory(
            RequestSimpleParameterSet parameters)
            throws DatasetFactoryException, URISyntaxException, MalformedURLException {
        return new DefaultIoFactory<MeasurementData, MeasurementDatasetOutput, MeasurementValue>()
                .create("measurement").withSimpleRequest(parameters).withBasePath(getRootResource())
                .withDataService(timeseriesDataService).withDatasetService(timeseriesMetadataService);
    }

    private URI getRootResource() throws URISyntaxException, MalformedURLException {
        return getServletConfig().getServletContext().getResource("/").toURI();
    }

    @RequestMapping(value = "/{timeseriesId}/getData", produces = { "application/pdf" }, method = GET)
    public void getTimeseriesReport(HttpServletResponse response, @PathVariable String timeseriesId,
            @RequestParam(required = false) MultiValueMap<String, String> query) throws Exception {

        IoParameters map = createFromQuery(query);
        checkIfUnknownTimeseries(map, timeseriesId);

        MeasurementDatasetOutput metadata = timeseriesMetadataService.getParameter(timeseriesId, map);
        RequestSimpleParameterSet parameters = createForSingleSeries(timeseriesId, map);
        checkAgainstTimespanRestriction(parameters.getTimespan());
        parameters.setGeneralize(map.isGeneralize());
        parameters.setExpanded(map.isExpanded());

        response.setContentType(MimeType.APPLICATION_PDF.getMimeType());
        createIoFactory(parameters).createHandler(MimeType.APPLICATION_PDF.getMimeType())
                .writeBinary(response.getOutputStream());
    }

    @RequestMapping(value = "/{timeseriesId}/getData", produces = { "application/zip" }, method = GET)
    public void getTimeseriesAsZippedCsv(HttpServletResponse response, @PathVariable String timeseriesId,
            @RequestParam(required = false) MultiValueMap<String, String> query) throws Exception {
        query.put("zip", Arrays.asList(new String[] { Boolean.TRUE.toString() }));

        response.setContentType(MimeType.APPLICATION_ZIP.getMimeType());
        getTimeseriesAsCsv(response, timeseriesId, query);
    }

    @RequestMapping(value = "/{timeseriesId}/getData", produces = { "text/csv" }, method = GET)
    public void getTimeseriesAsCsv(HttpServletResponse response, @PathVariable String timeseriesId,
            @RequestParam(required = false) MultiValueMap<String, String> query) throws Exception {

        IoParameters map = createFromQuery(query);
        checkIfUnknownTimeseries(map, timeseriesId);

        MeasurementDatasetOutput metadata = timeseriesMetadataService.getParameter(timeseriesId, map);
        RequestSimpleParameterSet parameters = createForSingleSeries(timeseriesId, map);
        checkAgainstTimespanRestriction(parameters.getTimespan());
        parameters.setGeneralize(map.isGeneralize());
        parameters.setExpanded(map.isExpanded());

        response.setCharacterEncoding("UTF-8");
        if (Boolean.parseBoolean(map.getOther("zip"))) {
            response.setContentType(APPLICATION_ZIP.toString());
        } else {
            response.setContentType(TEXT_CSV.toString());
        }

        createIoFactory(parameters).createHandler("text/csv").writeBinary(response.getOutputStream());
    }

    @RequestMapping(value = "/getData", produces = { "image/png" }, method = POST)
    public void getTimeseriesCollectionChart(HttpServletResponse response,
            @RequestBody RequestStyledParameterSet requestParameters) throws Exception {

        IoParameters map = createFromQuery(requestParameters);
        checkIfUnknownTimeseries(map, requestParameters.getDatasets());

        RequestSimpleParameterSet parameters = createFromDesignedParameters(requestParameters);
        checkAgainstTimespanRestriction(parameters.getTimespan());
        parameters.setGeneralize(map.isGeneralize());
        parameters.setExpanded(map.isExpanded());
        parameters.setBase64(map.isBase64());

        response.setContentType(MimeType.IMAGE_PNG.getMimeType());
        createIoFactory(parameters).withStyledRequest(requestParameters).createHandler("image/png")
                .writeBinary(response.getOutputStream());
    }

    @RequestMapping(value = "/{timeseriesId}/getData", produces = { "image/png" }, method = GET)
    public void getTimeseriesChart(HttpServletResponse response, @PathVariable String timeseriesId,
            @RequestParam(required = false) MultiValueMap<String, String> query) throws Exception {

        IoParameters map = createFromQuery(query);
        checkIfUnknownTimeseries(map, timeseriesId);

        RequestSimpleParameterSet parameters = createForSingleSeries(timeseriesId, map);
        RequestStyledParameterSet styledParameters = map.toRequestStyledParameterSet();
        checkAgainstTimespanRestriction(parameters.getTimespan());

        parameters.setGeneralize(map.isGeneralize());
        parameters.setBase64(map.isBase64());
        parameters.setExpanded(map.isExpanded());

        response.setContentType(MimeType.IMAGE_PNG.getMimeType());
        createIoFactory(parameters).withStyledRequest(styledParameters).createHandler("image/png")
                .writeBinary(response.getOutputStream());
    }

    @RequestMapping(value = "/{timeseriesId}/{chartQualifier}", produces = { "image/png" }, method = GET)
    public void getTimeseriesChartByInterval(HttpServletResponse response, @PathVariable String timeseriesId,
            @PathVariable String chartQualifier,
            @RequestParam(required = false) MultiValueMap<String, String> query) throws Exception {
        if (preRenderingTask == null) {
            throw new ResourceNotFoundException("Diagram prerendering is not enabled.");
        }
        if (!preRenderingTask.hasPrerenderedImage(timeseriesId, chartQualifier)) {
            throw new ResourceNotFoundException(
                    "No pre-rendered chart found for timeseries '" + timeseriesId + "'.");
        }
        preRenderingTask.writePrerenderedGraphToOutputStream(timeseriesId, chartQualifier,
                response.getOutputStream());
    }

    private void checkAgainstTimespanRestriction(String timespan) {
        Duration duration = Period.parse(requestIntervalRestriction).toDurationFrom(new DateTime());
        if (duration.getMillis() < Interval.parse(timespan).toDurationMillis()) {
            throw new BadRequestException("Requested timespan is to long, please use a period shorter than '"
                    + requestIntervalRestriction + "'");
        }
    }

    private void checkIfUnknownTimeseries(RequestParameterSet parameters, String... timeseriesIds) {
        checkIfUnknownTimeseries(IoParameters.createFromQuery(parameters), timeseriesIds);
    }

    private void checkIfUnknownTimeseries(IoParameters parameters, String... timeseriesIds) {
        for (String timeseriesId : timeseriesIds) {
            if (!timeseriesMetadataService.exists(timeseriesId, parameters)) {
                throw new ResourceNotFoundException("The timeseries with id '" + timeseriesId + "' was not found.");
            }
        }
    }

    //    /**
    //     * @param response the response to write binary on.
    //     * @param parameters the timeseries parameter to request raw data.
    //     * @param renderer an output renderer.
    //     * @throws InternalServerException if data processing fails for some reason.
    //     */
    //    private void handleBinaryResponse(HttpServletResponse response,
    //            RequestSimpleParameterSet parameters,
    //            IoHandler<MeasurementData> renderer) {
    //        try {
    //            renderer.generateOutput(getTimeseriesData(parameters));
    //            if (parameters.isBase64()) {
    //                ByteArrayOutputStream baos = new ByteArrayOutputStream();
    //                renderer.encodeAndWriteTo(baos);
    //                byte[] imageData = baos.toByteArray();
    //                byte[] encode = Base64.encodeBase64(imageData);
    //                response.getOutputStream().write(encode);
    //            } else {
    //                renderer.encodeAndWriteTo(response.getOutputStream());
    //            }
    //        } catch (IOException e) { // handled by BaseController
    //            throw new InternalServerException("Error handling output stream.", e);
    //        } catch (IoParseException e) { // handled by BaseController
    //            throw new InternalServerException("Could not write binary to stream.", e);
    //        } finally {
    //            try {
    //                if ( !response.isCommitted()) {
    //                    response.flushBuffer();
    //                }
    //            } catch (IOException e) {
    //                throw new InternalServerException("Could not flush buffer.", e);
    //            }
    //        }
    //    }

    private DataCollection<MeasurementData> getTimeseriesData(RequestSimpleParameterSet parameters) {
        Stopwatch stopwatch = startStopwatch();
        DataCollection<MeasurementData> timeseriesData = parameters.isGeneralize()
                ? composeDataService(timeseriesDataService).getData(parameters)
                : timeseriesDataService.getData(parameters);
        LOGGER.debug("Processing request took {} seconds.", stopwatch.stopInSeconds());
        return timeseriesData;
    }

    public ParameterService<MeasurementDatasetOutput> getTimeseriesMetadataService() {
        return timeseriesMetadataService;
    }

    public void setTimeseriesMetadataService(ParameterService<MeasurementDatasetOutput> timeseriesMetadataService) {
        this.timeseriesMetadataService = new WebExceptionAdapter<>(timeseriesMetadataService);
    }

    public DataService<MeasurementData> getTimeseriesDataService() {
        return timeseriesDataService;
    }

    public void setTimeseriesDataService(DataService<MeasurementData> timeseriesDataService) {
        this.timeseriesDataService = timeseriesDataService;
    }

    public PreRenderingJob getPreRenderingTask() {
        return preRenderingTask;
    }

    public void setPreRenderingTask(PreRenderingJob prerenderingTask) {
        this.preRenderingTask = prerenderingTask;
    }

    public String getRequestIntervalRestriction() {
        return requestIntervalRestriction;
    }

    public void setRequestIntervalRestriction(String requestIntervalRestriction) {
        // validate requestIntervalRestriction, if it's no period an exception occured
        Period.parse(requestIntervalRestriction);
        this.requestIntervalRestriction = requestIntervalRestriction;
    }

}