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

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

The newest version!
/*
 * Copyright (C) 2012-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.sos.ds;

import static java.util.stream.Collectors.toCollection;
import static java.util.stream.Collectors.toMap;
import static java.util.stream.Collectors.toSet;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.TreeSet;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import javax.inject.Inject;
import javax.xml.namespace.QName;

import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.locationtech.jts.geom.Geometry;
import org.n52.io.request.IoParameters;
import org.n52.series.db.DataAccessException;
import org.n52.series.db.HibernateSessionStore;
import org.n52.series.db.beans.OfferingEntity;
import org.n52.series.db.beans.PhenomenonEntity;
import org.n52.series.db.beans.ProcedureEntity;
import org.n52.series.db.dao.DbQuery;
import org.n52.series.db.dao.OfferingDao;
import org.n52.series.db.dao.PhenomenonDao;
import org.n52.series.db.dao.ProcedureDao;
import org.n52.shetland.ogc.gml.ReferenceType;
import org.n52.shetland.ogc.gml.time.TimePeriod;
import org.n52.shetland.ogc.ows.exception.CodedException;
import org.n52.shetland.ogc.ows.exception.NoApplicableCodeException;
import org.n52.shetland.ogc.ows.exception.OwsExceptionReport;
import org.n52.shetland.ogc.ows.extension.CapabilitiesExtension;
import org.n52.shetland.ogc.ows.service.GetCapabilitiesRequest;
import org.n52.shetland.ogc.sos.Sos1Constants;
import org.n52.shetland.ogc.sos.Sos2Constants;
import org.n52.shetland.ogc.sos.SosConstants;
import org.n52.shetland.ogc.sos.SosObservationOffering;
import org.n52.shetland.ogc.sos.SosOffering;
import org.n52.shetland.ogc.sos.extension.SosObservationOfferingExtension;
import org.n52.shetland.ogc.sos.ro.RelatedOfferingConstants;
import org.n52.shetland.ogc.sos.ro.RelatedOfferings;
import org.n52.shetland.util.CollectionHelper;
import org.n52.shetland.util.OMHelper;
import org.n52.shetland.util.ReferencedEnvelope;
import org.n52.sos.config.CapabilitiesExtensionService;
import org.n52.sos.ogc.sos.SosObservationOfferingExtensionRepository;
import org.n52.sos.util.I18NHelper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Implementation of the interface AbstractGetCapabilitiesHandler
 *
 * @since 4.0.0
 */
public class GetCapabilitiesHandler extends AbstractSosGetCapabilitiesHandler implements ApiQueryHelper, I18NHelper {

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

    private static final String ERROR_QUERYING_CAPABILITIES = "Error while querying data for GetCapabilities document!";

    @Inject
    private HibernateSessionStore sessionStore;

    @Inject
    private CapabilitiesExtensionService capabilitiesExtensionService;

    @Inject
    private SosObservationOfferingExtensionRepository offeringExtensionRepository;

    /**
     * Get the contents for SOS 1.0.0 capabilities
     *
     * @return sectionSpecificContentObject metadata holder to get contents
     *
     * @throws OwsExceptionReport
     *             If an error occurs
     */
    @Override
    protected List getContentsForSosV1(
            SectionSpecificContentObject sectionSpecificContentObject) throws OwsExceptionReport {
        Session session = null;
        try {
            session = sessionStore.getSession();
            String version = sectionSpecificContentObject.getGetCapabilitiesResponse().getVersion();
            Collection offerings =
                    new OfferingDao(session).getAllInstances(new DbQuery(IoParameters.createDefaults()));
            List sosOfferings = new ArrayList<>(offerings.size());
            for (OfferingEntity offering : offerings) {
                Collection procedures =
                        GetCapabilitiesHandler.this.getProceduresForOfferingEntity(offering, session);
                ReferencedEnvelope envelopeForOffering = getCache().getEnvelopeForOffering(offering.getIdentifier());
                Set featuresForoffering = getFOI4offering(offering.getIdentifier());
                Collection responseFormats = getResponseFormatRepository()
                        .getSupportedResponseFormats(SosConstants.SOS, Sos1Constants.SERVICEVERSION);
                if (checkOfferingValues(envelopeForOffering, featuresForoffering, responseFormats)) {
                    SosObservationOffering sosObservationOffering = new SosObservationOffering();

                    // insert observationTypes
                    sosObservationOffering.setObservationTypes(getObservationTypes(offering.getIdentifier()));

                    // only if fois are contained for the offering set the
                    // values of
                    // the envelope
                    if (offering.isSetGeometry()) {
                        sosObservationOffering.setObservedArea(processObservedArea(offering.getGeometry()));
                    } else if (getCache().hasEnvelopeForOffering(offering.getIdentifier())) {
                        sosObservationOffering
                                .setObservedArea(getCache().getEnvelopeForOffering(offering.getIdentifier()));
                    }

                    // TODO: add intended application
                    // xb_oo.addIntendedApplication("");
                    // add offering name
                    addSosOfferingToObservationOffering(offering, sosObservationOffering,
                            sectionSpecificContentObject.getGetCapabilitiesRequest());

                    // set up phenomena
                    sosObservationOffering.setObservableProperties(
                            getCache().getObservablePropertiesForOffering(offering.getIdentifier()));
                    Set compositePhenomenonsForOffering =
                            getCache().getCompositePhenomenonsForOffering(offering.getIdentifier());
                    sosObservationOffering.setCompositePhenomena(compositePhenomenonsForOffering);

                    Map> phens4CompPhens =
                            Optional.ofNullable(compositePhenomenonsForOffering).map(Set::stream)
                                    .orElseGet(Stream::empty).collect(toMap(Function.identity(),
                                            getCache()::getObservablePropertiesForCompositePhenomenon));

                    sosObservationOffering.setPhens4CompPhens(phens4CompPhens);

                    // set up time
                    setUpTimeForOffering(offering, sosObservationOffering);

                    // add feature of interests
                    if (getProfileHandler().getActiveProfile().isListFeatureOfInterestsInOfferings()) {
                        sosObservationOffering.setFeatureOfInterest(getFOI4offering(offering.getIdentifier()));
                    }

                    // set procedures
                    sosObservationOffering.setProcedures(
                            procedures.stream().map(p -> p.getIdentifier()).collect(Collectors.toSet()));

                    // insert result models
                    Collection resultModels = OMHelper.getQNamesForResultModel(
                            getCache().getObservationTypesForOffering(offering.getIdentifier()));
                    sosObservationOffering.setResultModels(resultModels);

                    // set response format
                    sosObservationOffering.setResponseFormats(responseFormats);

                    // set response Mode
                    sosObservationOffering.setResponseModes(SosConstants.RESPONSE_MODES);

                    sosOfferings.add(sosObservationOffering);
                }
            }

            return sosOfferings;
        } catch (HibernateException | DataAccessException e) {
            throw new NoApplicableCodeException().causedBy(e)
                    .withMessage(ERROR_QUERYING_CAPABILITIES);
        } finally {
            sessionStore.returnSession(session);
        }
    }

    private ReferencedEnvelope processObservedArea(Geometry geometry) throws OwsExceptionReport {
        return new ReferencedEnvelope(
                getGeometryHandler().switchCoordinateAxisFromToDatasourceIfNeeded(geometry).getEnvelopeInternal(),
                geometry.getSRID());
    }

    /**
     * Get the contents for SOS 2.0 capabilities
     *
     * @return sectionSpecificContentObject metadata holder to get contents
     *
     * @throws OwsExceptionReport
     *             * If an error occurs
     */
    @Override
    protected List getContentsForSosV2(
            SectionSpecificContentObject sectionSpecificContentObject) throws OwsExceptionReport {
        Session session = null;
        try {
            session = sessionStore.getSession();
            Collection offerings =
                    new OfferingDao(session).getAllInstances(new DbQuery(IoParameters.createDefaults()));
            List sosOfferings = new ArrayList<>(offerings.size());
            Map> extensions =
                    this.capabilitiesExtensionService.getActiveOfferingExtensions();

            if (CollectionHelper.isEmpty(offerings)) {
                // Set empty offering to add empty Contents section to
                // Capabilities
                sosOfferings.add(new SosObservationOffering());
            } else {
                if (checkListOnlyParentOfferings()) {
                    sosOfferings.addAll(
                            createAndGetParentOfferings(offerings, sectionSpecificContentObject, extensions, session));
                } else {
                    for (OfferingEntity offering : offerings) {
                        Collection procedures = getProceduresForOfferingEntity(offering, session);
                        if (!procedures.isEmpty()) {
                            Collection observationTypes = getObservationTypes(offering);
                            if (observationTypes != null && !observationTypes.isEmpty()) {
                                // FIXME why a loop? We are in SOS 2.0 context
                                // -> offering 1
                                // <-> 1 procedure!
                                for (ProcedureEntity procedure : procedures) {

                                    SosObservationOffering sosObservationOffering = new SosObservationOffering();

                                    // insert observationTypes
                                    sosObservationOffering.setObservationTypes(observationTypes);

                                    if (offering.isSetGeometry()) {
                                        sosObservationOffering
                                                .setObservedArea(processObservedArea(offering.getGeometry()));
                                    } else if (getCache().hasEnvelopeForOffering(offering.getIdentifier())) {
                                        sosObservationOffering.setObservedArea(
                                                getCache().getEnvelopeForOffering(offering.getIdentifier()));
                                    }

                                    sosObservationOffering
                                            .setProcedures(Collections.singletonList(procedure.getIdentifier()));
                                    GetCapabilitiesRequest request =
                                            sectionSpecificContentObject.getGetCapabilitiesRequest();

                                    // TODO: add intended application
                                    // add offering to observation offering
                                    addSosOfferingToObservationOffering(offering, sosObservationOffering, request);
                                    // add offering extension
                                    if (offeringExtensionRepository.hasOfferingExtensionProviderFor(request)) {
                                        offeringExtensionRepository.getOfferingExtensionProvider(request).stream()
                                                .filter(Objects::nonNull)
                                                .filter(provider -> provider
                                                        .hasExtendedOfferingFor(offering.getIdentifier()))
                                                .map(provider -> provider
                                                        .getOfferingExtensions(offering.getIdentifier()))
                                                .forEach(sosObservationOffering::addExtensions);
                                    }

                                    if (extensions.containsKey(sosObservationOffering.getOffering().getIdentifier())) {
                                        extensions.get(sosObservationOffering.getIdentifier()).stream()
                                                .map(CapabilitiesExtension::new)
                                                .forEach(sosObservationOffering::addExtension);
                                    }

                                    setUpPhenomenaForOffering(offering, procedure, sosObservationOffering, session);
                                    setUpTimeForOffering(offering, sosObservationOffering);
                                    setUpRelatedFeaturesForOffering(offering, sosObservationOffering);
                                    setUpFeatureOfInterestTypesForOffering(offering, sosObservationOffering);
                                    setUpProcedureDescriptionFormatForOffering(sosObservationOffering,
                                            Sos2Constants.SERVICEVERSION);
                                    setUpResponseFormatForOffering(sosObservationOffering,
                                            Sos2Constants.SERVICEVERSION);

                                    sosOfferings.add(sosObservationOffering);
                                }
                            }
                        } else {
                            LOGGER.error(
                                    "No procedures are contained in the database for the offering {}! "
                                    + "Please contact the admin of this SOS.",
                                    offering.getIdentifier());
                        }
                    }
                }
            }

            return sosOfferings;
        } catch (HibernateException | DataAccessException e) {
            throw new NoApplicableCodeException().causedBy(e)
                    .withMessage(ERROR_QUERYING_CAPABILITIES);
        } finally {
            sessionStore.returnSession(session);
        }
    }

    private Collection createAndGetParentOfferings(
            Collection offerings, SectionSpecificContentObject sectionSpecificContentObject,
            Map> extensions, Session session)
            throws OwsExceptionReport, DataAccessException {
        Map> parentChilds = getParentOfferings(offerings);

        List sosOfferings = new ArrayList<>(parentChilds.size());
        for (Entry> entry : parentChilds.entrySet()) {
            Collection observationTypes = getObservationTypes(entry);
            if (CollectionHelper.isNotEmpty(observationTypes)) {
                Collection procedures = getProceduresForOfferingEntity(entry, session);
                if (CollectionHelper.isNotEmpty(procedures)) {
                    Set allOfferings = new HashSet<>();
                    allOfferings.addAll(entry.getValue());
                    allOfferings.add(entry.getKey());
                    SosObservationOffering sosObservationOffering = new SosObservationOffering();
                    sosObservationOffering.setObservationTypes(observationTypes);
                    sosObservationOffering.setObservedArea(getObservedArea(entry));

                    sosObservationOffering.setProcedures(
                            procedures.stream().map(p -> p.getIdentifier()).collect(Collectors.toSet()));
                    //
                    // // TODO: add intended application
                    //
                    // // add offering to observation offering
                    addSosOfferingToObservationOffering(entry.getKey(), sosObservationOffering,
                            sectionSpecificContentObject.getGetCapabilitiesRequest());
                    // add offering extension
                    if (offeringExtensionRepository.hasOfferingExtensionProviderFor(
                            sectionSpecificContentObject.getGetCapabilitiesRequest())) {
                        offeringExtensionRepository
                                .getOfferingExtensionProvider(sectionSpecificContentObject.getGetCapabilitiesRequest())
                                .stream().filter(Objects::nonNull)
                                .filter(provider -> provider.hasExtendedOfferingFor(entry.getKey().getIdentifier()))
                                .map(provider -> provider.getOfferingExtensions(entry.getKey().getIdentifier()))
                                .forEach(sosObservationOffering::addExtensions);
                    }
                    if (extensions.containsKey(sosObservationOffering.getOffering().getIdentifier())) {
                        extensions.get(sosObservationOffering.getOffering().getIdentifier())
                                .forEach(sosObservationOffering::addExtension);
                    }
                    // add sub-level offerings
                    if (!entry.getValue().isEmpty()) {
                        RelatedOfferings relatedOfferings = new RelatedOfferings();
                        String gdaURL = getGetDataAvailabilityUrl();
                        gdaURL = addParameter(gdaURL, "responseFormat", "http://www.opengis.net/sosgda/2.0");
                        for (OfferingEntity offering : entry.getValue()) {
                            relatedOfferings.addValue(new ReferenceType(RelatedOfferingConstants.ROLE),
                                    new ReferenceType(addParameter(gdaURL, "offering", offering.getIdentifier()),
                                            offering.getIdentifier()));
                        }
                        sosObservationOffering.addExtension(relatedOfferings);
                    }

                    setUpPhenomenaForOffering(allOfferings, procedures.iterator().next(), sosObservationOffering,
                            session);
                    setUpTimeForOffering(allOfferings.stream().map(OfferingEntity::getIdentifier),
                            sosObservationOffering);
                    setUpRelatedFeaturesForOffering(allOfferings, sosObservationOffering);
                    setUpFeatureOfInterestTypesForOffering(allOfferings, sosObservationOffering);
                    setUpProcedureDescriptionFormatForOffering(sosObservationOffering, Sos2Constants.SERVICEVERSION);
                    setUpResponseFormatForOffering(sosObservationOffering, Sos2Constants.SERVICEVERSION);

                    sosOfferings.add(sosObservationOffering);
                }
            }
        }
        return sosOfferings;
    }

    private Map> getParentOfferings(Collection offerings) {
        return offerings.stream().filter(OfferingEntity::hasParents)
                .collect(toMap(Function.identity(), this::getAllParents));
    }

    private Set getAllParents(OfferingEntity entity) {
        return Stream
                .concat(Stream.of(entity), entity.getParents().stream().map(this::getAllParents).flatMap(Set::stream))
                .collect(toSet());
    }

    private void addSosOfferingToObservationOffering(OfferingEntity offering,
            SosObservationOffering sosObservationOffering, GetCapabilitiesRequest request) throws CodedException {
        SosOffering sosOffering = offering.isSetName() ? new SosOffering(offering.getIdentifier(), offering.getName())
                : new SosOffering(offering.getIdentifier(), false);
        sosObservationOffering.setOffering(sosOffering);
        // add offering name
        addOfferingNames(getCache(), sosOffering, getRequestedLocale(request), Locale.ROOT, isShowAllLanguages());
        // add offering description
        addOfferingDescription(sosOffering, getRequestedLocale(request), Locale.ROOT, getCache());
    }

    private Collection getObservationTypes(OfferingEntity offering) {
        if (offering.hasObservationTypes()) {
            return toStringSet(offering.getObservationTypes());
        } else {
            return getCache().getAllObservationTypesForOffering(offering.getIdentifier());
        }
    }

    private Collection getObservationTypes(Entry> entry) {
        Set observationTypes = new HashSet<>();
        entry.getValue().stream().map(v -> getObservationTypes(v)).forEach(observationTypes::addAll);
        observationTypes.addAll(getObservationTypes(entry.getKey().getIdentifier()));
        return observationTypes;
    }

    protected void setUpPhenomenaForOffering(Set allOfferings, ProcedureEntity procedure,
            SosObservationOffering sosObservationOffering, Session session) throws DataAccessException {
        for (OfferingEntity offering : allOfferings) {
            setUpPhenomenaForOffering(offering, procedure, sosObservationOffering, session);
        }
    }

    protected void setUpPhenomenaForOffering(OfferingEntity offering, ProcedureEntity procedure,
            SosObservationOffering sosOffering, Session session) throws DataAccessException {
        Map map = new HashMap<>();
        map.put(IoParameters.OFFERINGS, Long.toString(offering.getId()));
        map.put(IoParameters.PROCEDURES, Long.toString(procedure.getId()));

        List observableProperties =
                new PhenomenonDao(session).getAllInstances(new DbQuery(IoParameters.createFromSingleValueMap(map)));

        Collection phenomenons = new LinkedList<>();
        Map> phens4CompPhens = new HashMap<>(observableProperties.size());
        observableProperties.forEach(observableProperty -> {
            if (!observableProperty.hasChildren() && !observableProperty.hasParents()) {
                phenomenons.add(observableProperty.getIdentifier());
            } else if (observableProperty.hasChildren() && !observableProperty.hasParents()) {
                phens4CompPhens.put(observableProperty.getIdentifier(), observableProperty.getChildren().stream()
                        .map(PhenomenonEntity::getIdentifier).collect(toCollection(TreeSet::new)));
            }

        });
        sosOffering.setObservableProperties(phenomenons);
        sosOffering.setPhens4CompPhens(phens4CompPhens);
    }

    protected void setUpTimeForOffering(OfferingEntity offering, SosObservationOffering sosOffering) {
        sosOffering.setPhenomenonTime(new TimePeriod(offering.getSamplingTimeStart(), offering.getSamplingTimeEnd()));
        sosOffering.setResultTime(new TimePeriod(offering.getResultTimeStart(), offering.getResultTimeEnd()));
    }

    protected void setUpFeatureOfInterestTypesForOffering(Collection offerings,
            SosObservationOffering sosOffering) {
        sosOffering.setFeatureOfInterestTypes(offerings.stream().map(o -> getFeatureOfInterstTypesForOffering(o))
                .flatMap(Set::stream).collect(toSet()));
    }

    protected void setUpFeatureOfInterestTypesForOffering(OfferingEntity offering,
            SosObservationOffering sosOffering) {
        sosOffering.setFeatureOfInterestTypes(getFeatureOfInterstTypesForOffering(offering));
    }

    private Set getFeatureOfInterstTypesForOffering(OfferingEntity offering) {
        if (offering.hasFeatureTypes()) {
            return toStringSet(offering.getFeatureTypes());
        } else {
            return getCache().getAllowedFeatureOfInterestTypesForOffering(offering.getIdentifier());
        }
    }

    private void setUpRelatedFeaturesForOffering(OfferingEntity offering,
            SosObservationOffering sosObservationOffering) throws OwsExceptionReport {
        setUpRelatedFeaturesForOffering(Collections.singleton(offering), sosObservationOffering);
    }

    private void setUpRelatedFeaturesForOffering(Collection offerings,
            SosObservationOffering sosObservationOffering) throws OwsExceptionReport {
        setUpRelatedFeaturesForOffering(offerings.stream().map(OfferingEntity::getIdentifier), sosObservationOffering);
    }

    private ReferencedEnvelope getObservedArea(Entry> entry)
            throws OwsExceptionReport {
        ReferencedEnvelope envelope = new ReferencedEnvelope();
        if (!entry.getValue().isEmpty()) {
            for (OfferingEntity offering : entry.getValue()) {
                envelope.expandToInclude(getObservedArea(offering.getIdentifier()));
            }
        } else {
            envelope.expandToInclude(getObservedArea(entry.getKey().getIdentifier()));
        }
        return envelope;
    }

    private Collection getProceduresForOfferingEntity(
            Entry> entry, Session session)
            throws OwsExceptionReport, DataAccessException {
        Collection procedures = new HashSet<>();
        for (OfferingEntity offering : entry.getValue()) {
            procedures.addAll(getProceduresForOfferingEntity(offering, session));
        }
        procedures.addAll(getProceduresForOfferingEntity(entry.getKey(), session));
        return procedures;
    }

    private Collection getProceduresForOfferingEntity(OfferingEntity offering, Session session)
            throws OwsExceptionReport, DataAccessException {
        Map map = new HashMap<>(1);
        map.put(IoParameters.OFFERINGS, Long.toString(offering.getId()));
        return new ProcedureDao(session).getAllInstances(new DbQuery(IoParameters.createFromSingleValueMap(map)));
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy