All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.n52.sos.ds.GetDataAvailabilityHandler Maven / Gradle / Ivy

There is a newer version: 5.0.0-alpha.10
Show newest version
/*
 * Copyright (C) 2012-2018 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.sos.ds;

import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;

import javax.inject.Inject;

import org.hibernate.Session;
import org.n52.io.request.IoParameters;
import org.n52.series.db.DataAccessException;
import org.n52.series.db.HibernateSessionStore;
import org.n52.series.db.beans.DatasetEntity;
import org.n52.series.db.beans.FormatEntity;
import org.n52.series.db.beans.OfferingEntity;
import org.n52.series.db.beans.dataset.Dataset;
import org.n52.series.db.dao.DatasetDao;
import org.n52.series.db.dao.DbQuery;
import org.n52.shetland.ogc.filter.TemporalFilter;
import org.n52.shetland.ogc.gml.ReferenceType;
import org.n52.shetland.ogc.gml.time.TimePeriod;
import org.n52.shetland.ogc.ows.exception.NoApplicableCodeException;
import org.n52.shetland.ogc.ows.exception.OwsExceptionReport;
import org.n52.shetland.ogc.ows.extension.Extension;
import org.n52.shetland.ogc.ows.extension.Extensions;
import org.n52.shetland.ogc.sos.SosConstants;
import org.n52.shetland.ogc.sos.gda.GetDataAvailabilityConstants;
import org.n52.shetland.ogc.sos.gda.GetDataAvailabilityRequest;
import org.n52.shetland.ogc.sos.gda.GetDataAvailabilityResponse;
import org.n52.shetland.ogc.sos.gda.GetDataAvailabilityResponse.DataAvailability;
import org.n52.shetland.ogc.sos.gda.GetDataAvailabilityResponse.FormatDescriptor;
import org.n52.shetland.ogc.sos.gda.GetDataAvailabilityResponse.ObservationFormatDescriptor;
import org.n52.shetland.ogc.sos.gda.GetDataAvailabilityResponse.ProcedureDescriptionFormatDescriptor;
import org.n52.sos.ds.dao.GetDataAvailabilityDao;

import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;

public class GetDataAvailabilityHandler extends AbstractGetDataAvailabilityHandler implements ApiQueryHelper {

    private HibernateSessionStore sessionStore;
    private Optional dao = Optional.empty();


    public GetDataAvailabilityHandler() {
        super(SosConstants.SOS);
    }

    @Inject
    public void setConnectionProvider(HibernateSessionStore sessionStore) {
        this.sessionStore = sessionStore;
    }

    @Inject
    public void setGetDataAvaolabilityDao(Optional getDataAvailabilityDao) {
        if (getDataAvailabilityDao != null) {
            this.dao = getDataAvailabilityDao;
        }
    }

    @Override
    public GetDataAvailabilityResponse getDataAvailability(GetDataAvailabilityRequest request)
            throws OwsExceptionReport {
        GetDataAvailabilityResponse response = new GetDataAvailabilityResponse();
        response.setService(request.getService());
        response.setVersion(request.getVersion());
        response.setResponseFormat(request.getResponseFormat());
        if (checkForGDAv20(request)) {
            response.setResponseFormat(GetDataAvailabilityConstants.NS_GDA_20);
        }
        for (DataAvailability da : queryDataAvailabilityValues(request)) {
            if (da != null) {
                response.addDataAvailability(da);
            }
        }
        return response;
    }

    @Override
    public boolean isSupported() {
        return true;
    }

    private List queryDataAvailabilityValues(GetDataAvailabilityRequest request) throws OwsExceptionReport {
        Session session = sessionStore.getSession();
        try {
            GDARequestContext context = new GDARequestContext(request);
            boolean gdaV20 = checkForGDAv20(request);
            for (final Dataset entity : new DatasetDao<>(session).getAllInstances(createDbQuery(request))) {
                if (gdaV20) {
                    processDataAvailabilityV2(entity, context, session);
                } else {
                    processDataAvailability(entity, context, session);
                }
            }
            if (!gdaV20) {
                return checkForDuplictation(context.getDataAvailabilityList());
            }
            return context.getDataAvailabilityList();
        } catch (DataAccessException e) {
            throw new NoApplicableCodeException().causedBy(e).withMessage(
                    "Error while querying data for GetDataAvailability!");
        } finally {
            sessionStore.returnSession(session);
        }
    }

    private DbQuery createDbQuery(GetDataAvailabilityRequest req) {
        Map map = Maps.newHashMap();
        if (req.isSetFeaturesOfInterest()) {
            map.put(IoParameters.FEATURES, listToString(req.getFeaturesOfInterest()));
        }
        if (req.isSetProcedures()) {
            map.put(IoParameters.PROCEDURES, listToString(req.getProcedures()));
        }
        if (req.isSetObservedProperties()) {
            map.put(IoParameters.PHENOMENA, listToString(req.getObservedProperties()));
        }
        if (req.isSetOfferings()) {
            map.put(IoParameters.OFFERINGS, listToString(req.getOfferings()));
        }
        map.put(IoParameters.MATCH_DOMAIN_IDS, Boolean.toString(true));
        return new DbQuery(IoParameters.createFromSingleValueMap(map));
    }

    private DataAvailability defaultProcessDataAvailability(Dataset entity, GDARequestContext context, Session session) throws OwsExceptionReport {
            TimePeriod timePeriod = createTimePeriod(entity);
            if (timePeriod != null && !timePeriod.isEmpty()) {
                DataAvailability dataAvailability =
                        new DataAvailability(getProcedureReference(entity, context.getProcedures()), getObservedPropertyReference(
                                entity, context.getObservableProperties()), getFeatureOfInterestReference(entity,
                                        context.getFeaturesOfInterest()), getOfferingReference(entity, context.getOfferings()), timePeriod);
                if (isShowCount(context.getRequest()) && entity.getObservationCount() >= 0) {
                    dataAvailability.setCount(entity.getObservationCount());
                }
                if (isIncludeResultTime(context.getRequest()) && dao.isPresent()) {
                    dataAvailability.setResultTimes(dao.get().getResultTimes(dataAvailability, context.getRequest()));
                }
                return dataAvailability;
            }
            return null;
        }

    /**
     * Get {@link DataAvailability}s for each series
     *
     * @param entity
     *           the {@link DatasetEntity} to get {@link DataAvailability}s for
     * @param context
     *            Request context to get {@link DataAvailability}s
     * @param session Hibernate session
     * @throws OwsExceptionReport
     *             If an error occurs
     */
    private void processDataAvailability(Dataset entity, GDARequestContext context, Session session) throws OwsExceptionReport {
        DataAvailability dataAvailability = defaultProcessDataAvailability(entity, context, session);
        if (dataAvailability != null) {
            context.addDataAvailability(dataAvailability);
        }
    }

    /**
     * Get {@link DataAvailability}s for each offering of a series
     *
     * @param entity
     *           the {@link DatasetEntity} to get {@link DataAvailability}s for
     * @param context
     *            Request context to get {@link DataAvailability}s
     * @throws OwsExceptionReport
     *             If an error occurs
     */
    private void processDataAvailabilityV2(Dataset entity, GDARequestContext context, Session session)
            throws OwsExceptionReport {
        DataAvailability dataAvailability = defaultProcessDataAvailability(entity, context, session);
        if (dataAvailability != null) {
            dataAvailability.setFormatDescriptor(getFormatDescriptor(context, entity));
            if (dao.isPresent()) {
                dataAvailability.setMetadata(dao.get().getMetadata(dataAvailability));
            }
            context.addDataAvailability(dataAvailability);
        }
        checkForParentOfferings(context, entity.getOffering());
    }

    private TimePeriod createTimePeriod(Dataset entity) {
        return new TimePeriod(entity.getFirstValueAt(), entity.getLastValueAt());
    }

    private void checkForParentOfferings(GDARequestContext context, OfferingEntity offeringEntity) {
        if (context.isSetDataAvailabilityList()) {
            List requestedOfferings = context.getRequest().getOfferings();
            for (String requestedOffering : requestedOfferings) {
                Set childOfferings = getChildOfferings(offeringEntity);
                if (!childOfferings.isEmpty()) {
                    if (context.hasDataAvailability(requestedOffering)) {
                        Set parentDataAvailabilities =
                                context.getDataAvailability(requestedOffering);
                        for (String childOffering : childOfferings) {
                            Set childDataAvailabilities = context.getDataAvailability(childOffering);
                            for (DataAvailability childDataAvailability : childDataAvailabilities) {
                                for (DataAvailability parentDataAvailability : parentDataAvailabilities) {
                                    parentDataAvailability.merge(childDataAvailability, true);
                                }
                            }
                        }
                    } else {
                        Set parentDataAvailabilities = Sets.newHashSet();
                        for (String childOffering : childOfferings) {
                            Set childDataAvailabilities = context.getDataAvailability(childOffering);
                            for (DataAvailability childDataAvailability : childDataAvailabilities) {
                                addParentDataAvailabilityIfMissing(parentDataAvailabilities, childDataAvailability,
                                        new ReferenceType(requestedOffering));
                                for (DataAvailability parentDataAvailability : parentDataAvailabilities) {
                                    parentDataAvailability.merge(childDataAvailability, true);
                                }
                            }
                        }
                        context.addDataAvailabilities(parentDataAvailabilities);
                    }
                }
            }
        }
    }

    private Set getChildOfferings(OfferingEntity offering) {
      Set childs = Sets.newTreeSet();
      if (offering.hasChildren()) {
          for (OfferingEntity child : offering.getChildren()) {
              childs.add(child.getIdentifier());
              childs.addAll(getChildOfferings(child));
          }
      }
      return childs;
    }

    private boolean checkForGDAv20(GetDataAvailabilityRequest request) {
        return (request.isSetResponseFormat() && GetDataAvailabilityConstants.NS_GDA_20.equals(request.getResponseFormat()))
                || GetDataAvailabilityConstants.NS_GDA_20.equals(request.getNamespace()) || isForceGDAv20Response();
    }

    private List checkForDuplictation(List dataAvailabilityValues) {
        List checked = Lists.newLinkedList();
        for (DataAvailability dataAvailability : dataAvailabilityValues) {
            if (checked.isEmpty()) {
                checked.add(dataAvailability);
            } else {
                boolean notDuplicated = true;
                for (DataAvailability checkedDA : checked) {
                    if (dataAvailability.equals(checkedDA)) {
                        checkedDA.getPhenomenonTime().extendToContain(dataAvailability.getPhenomenonTime());
                        notDuplicated = false;
                    }
                }
                if (notDuplicated) {
                    checked.add(dataAvailability);
                }
            }
        }
        return checked;
    }

    private ReferenceType getProcedureReference(Dataset entity, Map procedures) {
        String identifier = entity.getProcedure().getIdentifier();
        if (!procedures.containsKey(identifier)) {
            ReferenceType referenceType = new ReferenceType(identifier);
            if (entity.getProcedure().isSetName()) {
                referenceType.setTitle(entity.getProcedure().getName());
            }
            procedures.put(identifier, referenceType);
        }
        return procedures.get(identifier);
    }

    private ReferenceType getObservedPropertyReference(Dataset entity, Map observableProperties) {
        String identifier = entity.getPhenomenon().getIdentifier();
        if (!observableProperties.containsKey(identifier)) {
            ReferenceType referenceType = new ReferenceType(identifier);
            if (entity.getPhenomenon().isSetName()) {
                referenceType.setTitle(entity.getPhenomenon().getName());
            }
            observableProperties.put(identifier, referenceType);
        }
        return observableProperties.get(identifier);
    }

    private ReferenceType getFeatureOfInterestReference(Dataset entity, Map featuresOfInterest) {
        String identifier = entity.getFeature().getIdentifier();
        if (!featuresOfInterest.containsKey(identifier)) {
            ReferenceType referenceType = new ReferenceType(identifier);
            if (entity.getFeature().isSetName() ) {
                referenceType.setTitle(entity.getFeature().getName());
            }
            featuresOfInterest.put(identifier, referenceType);
        }
        return featuresOfInterest.get(identifier);
    }

    private ReferenceType getOfferingReference(Dataset entity, Map offerings){
        String identifier = entity.getOffering().getIdentifier();
        if (!offerings.containsKey(identifier)) {
            ReferenceType referenceType = new ReferenceType(identifier);
            if (entity.getOffering().isSetName()) {
                referenceType.setTitle(entity.getOffering().getName());
            }
            offerings.put(identifier, referenceType);
        }
        return offerings.get(identifier);
    }

    /**
     * Check if optional count should be added
     *
     * @param request
     *            GetDataAvailability request
     * @return true, if optional count should be added
     */
    private boolean isShowCount(GetDataAvailabilityRequest request) {
        if (request.hasExtension(SHOW_COUNT)) {
            return request.getBooleanExtension(SHOW_COUNT);
        }
        return isForceValueCount();
    }

    /**
     * Check if result times should be added
     *
     * @param request
     *            GetDataAvailability request
     * @return true, if result times should be added
     */
    private boolean isIncludeResultTime(GetDataAvailabilityRequest request) {
        if (request.hasExtension(INCLUDE_RESULT_TIMES)) {
            return request.getBooleanExtension(INCLUDE_RESULT_TIMES)
                    || hasPhenomenonTimeFilter(request.getExtensions());
        }
        return false;
    }

    /**
     * Check if extensions contains a temporal filter with valueReference
     * phenomenonTime
     *
     * @param extensions
     *            Extensions to check
     * @return true, if extensions contains a temporal filter with
     *         valueReference phenomenonTime
     */
    private boolean hasPhenomenonTimeFilter(Extensions extensions) {
        boolean hasFilter = false;
        for (Extension extension : extensions.getExtensions()) {
            if (extension.getValue() instanceof TemporalFilter) {
                TemporalFilter filter = (TemporalFilter) extension.getValue();
                if (SosConstants.PHENOMENON_TIME_VALUE_REFERENCE.equals(filter.getValueReference())) {
                    hasFilter = true;
                }
            }
        }
        return hasFilter;
    }

    private FormatDescriptor getFormatDescriptor(GDARequestContext context, Dataset entity) {
        return new FormatDescriptor(
                new ProcedureDescriptionFormatDescriptor(
                        entity.getProcedure().getFormat().getFormat()),
                getObservationFormatDescriptors(entity.getOffering(), context));
    }

    private Set getObservationFormatDescriptors(OfferingEntity entity, GDARequestContext context) {
        Map> responsFormatObservationTypesMap = Maps.newHashMap();
        for (FormatEntity observationType : entity.getObservationTypes()) {
            Set responseFormats = getResponseFormatsForObservationType(observationType.getFormat(), context.getRequest().getService(), context.getRequest().getVersion());
            for (String responseFormat : responseFormats) {
                if (responsFormatObservationTypesMap.containsKey(responseFormat)) {
                    responsFormatObservationTypesMap.get(responseFormat).add(observationType.getFormat());
                } else {
                    responsFormatObservationTypesMap.put(responseFormat, Sets.newHashSet(observationType.getFormat()));
                }
            }
        }
        Set formatDescriptors = Sets.newHashSet();
        for (String responsFormat : responsFormatObservationTypesMap.keySet()) {
            formatDescriptors.add(new ObservationFormatDescriptor(responsFormat, responsFormatObservationTypesMap.get(responsFormat)));
        }
        return formatDescriptors;
    }

    private boolean addParentDataAvailabilityIfMissing(Set parentDataAvailabilities,
            DataAvailability childDataAvailability, ReferenceType offering) {
        boolean notContained = true;
        for (DataAvailability parentDataAvailability : parentDataAvailabilities) {
            if (parentDataAvailability.sameConstellation(childDataAvailability)) {
                notContained = false;
            }
        }
        if (notContained) {
            parentDataAvailabilities.add(childDataAvailability.copy());
        }
        return notContained;
    }

    public class GDARequestContext {
        private GetDataAvailabilityRequest request;
        private List dataAvailabilityValues = Lists.newArrayList();
        private Map procedures = new HashMap<>();
        private Map observableProperties = new HashMap<>();
        private Map featuresOfInterest = new HashMap<>();
        private Map offerings = new HashMap<>();

        public GDARequestContext(GetDataAvailabilityRequest request) {
            this.request = request;
        }

        public GetDataAvailabilityRequest getRequest() {
            return request;
        }

        public Map getFeaturesOfInterest() {
            return featuresOfInterest;
        }

        public Map getObservableProperties() {
            return observableProperties;
        }

        public Map getProcedures() {
            return procedures;
        }

        public Map getOfferings() {
            return offerings;
        }

        public GDARequestContext setDataAvailabilityList(List dataAvailabilityValues) {
            this.dataAvailabilityValues.clear();
            return addDataAvailabilities(dataAvailabilityValues);
        }

        public GDARequestContext addDataAvailability(DataAvailability dataAvailability) {
            if (dataAvailability != null) {
                this.dataAvailabilityValues.add(dataAvailability);
            }
            return this;
        }

        public GDARequestContext addDataAvailabilities(Collection dataAvailabilityValues) {
            if (dataAvailabilityValues != null) {
                this.dataAvailabilityValues.addAll(dataAvailabilityValues);
            }
            return this;
        }

        public List getDataAvailabilityList() {
            return Lists.newArrayList(dataAvailabilityValues);
        }

        public boolean hasDataAvailability(String requestedOffering) {
            for (DataAvailability dataAvailability : dataAvailabilityValues) {
                if (requestedOffering.equals(dataAvailability.getOfferingString())) {
                    return true;
                }
            }
            return false;
        }

        public Set getDataAvailability(String offering) {
            Set das = Sets.newHashSet();
            for (DataAvailability dataAvailability : dataAvailabilityValues) {
                if (offering.equals(dataAvailability.getOfferingString())) {
                    das.add(dataAvailability);
                }
            }
            return das;
        }

        public boolean isSetDataAvailabilityList() {
            return getDataAvailabilityList() != null && !getDataAvailabilityList().isEmpty();
        }

    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy