/** * Copyright (C) 2012-2017 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.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.Set; import javax.xml.namespace.QName; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.n52.sos.binding.Binding; import org.n52.sos.binding.BindingRepository; import org.n52.sos.coding.CodingRepository; import org.n52.sos.config.SettingsManager; import org.n52.sos.decode.Decoder; import org.n52.sos.encode.Encoder; import org.n52.sos.exception.CodedException; import org.n52.sos.exception.ConfigurationException; import org.n52.sos.exception.ows.InvalidParameterValueException; import org.n52.sos.exception.ows.NoApplicableCodeException; import org.n52.sos.ogc.OGCConstants; import org.n52.sos.ogc.filter.FilterCapabilities; import org.n52.sos.ogc.filter.FilterConstants.ComparisonOperator; import org.n52.sos.ogc.filter.FilterConstants.ConformanceClassConstraintNames; import org.n52.sos.ogc.filter.FilterConstants.SpatialOperator; import org.n52.sos.ogc.filter.FilterConstants.TimeOperator; import org.n52.sos.ogc.gml.GmlConstants; import org.n52.sos.ogc.gml.time.TimePeriod; import org.n52.sos.ogc.ows.MergableExtension; import org.n52.sos.ogc.ows.OWSConstants; import org.n52.sos.ogc.ows.OfferingExtension; import org.n52.sos.ogc.ows.OwsDomainType; import org.n52.sos.ogc.ows.OwsExceptionReport; import org.n52.sos.ogc.ows.OwsExtendedCapabilitiesProvider; import org.n52.sos.ogc.ows.OwsExtendedCapabilitiesRepository; import org.n52.sos.ogc.ows.OwsNoValues; import org.n52.sos.ogc.ows.OwsOperation; import org.n52.sos.ogc.ows.OwsOperationsMetadata; import org.n52.sos.ogc.ows.OwsParameterValuePossibleValues; import org.n52.sos.ogc.ows.SosServiceIdentification; import org.n52.sos.ogc.ows.StaticCapabilities; import org.n52.sos.ogc.sos.CapabilitiesExtension; import org.n52.sos.ogc.sos.CapabilitiesExtensionProvider; import org.n52.sos.ogc.sos.CapabilitiesExtensionRepository; import org.n52.sos.ogc.sos.Sos1Constants; import org.n52.sos.ogc.sos.Sos2Constants; import org.n52.sos.ogc.sos.SosCapabilities; import org.n52.sos.ogc.sos.SosConstants; import org.n52.sos.ogc.sos.SosEnvelope; import org.n52.sos.ogc.sos.SosObservationOffering; import org.n52.sos.ogc.sos.SosOffering; import org.n52.sos.ogc.swes.OfferingExtensionProvider; import org.n52.sos.ogc.swes.OfferingExtensionRepository; import org.n52.sos.ogc.swes.SwesExtensionImpl; import org.n52.sos.request.GetCapabilitiesRequest; import org.n52.sos.request.operator.RequestOperatorKey; import org.n52.sos.request.operator.RequestOperatorRepository; import org.n52.sos.response.GetCapabilitiesResponse; import org.n52.sos.service.Configurator; import org.n52.sos.service.operator.ServiceOperatorRepository; import org.n52.sos.util.CollectionHelper; import org.n52.sos.util.GeometryHandler; import org.n52.sos.util.I18NHelper; import org.n52.sos.i18n.LocaleHelper; import org.n52.sos.util.MultiMaps; import org.n52.sos.util.OMHelper; import org.n52.sos.util.SetMultiMap; import com.google.common.collect.Collections2; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Sets; /** * Implementation of the interface IGetCapabilitiesDAO * * @since 4.0.0 */ public class GetCapabilitiesDAO extends AbstractGetCapabilitiesDAO { private class SectionSpecificContentObject { private GetCapabilitiesRequest request; private GetCapabilitiesResponse response; private Set<String> requestedExtensionSections; private int requestedSections; private SosCapabilities sosCapabilities; public SectionSpecificContentObject setRequest(GetCapabilitiesRequest request) { this.request = request; return this; } public GetCapabilitiesRequest getGetCapabilitiesRequest() { return request; } public SectionSpecificContentObject setResponse(GetCapabilitiesResponse response) { this.response = response; return this; } public GetCapabilitiesResponse getGetCapabilitiesResponse() { return response; } public SectionSpecificContentObject setRequestedExtensionSections(Set<String> requestedExtensionSections) { this.requestedExtensionSections = requestedExtensionSections; return this; } public Set<String> getRequestedExtensionSesctions() { return requestedExtensionSections; } public SectionSpecificContentObject setRequestedSections(int requestedSections) { this.requestedSections = requestedSections; return this; } public int getRequestedSections() { return requestedSections; } public SectionSpecificContentObject setSosCapabilities(SosCapabilities sosCapabilities) { this.sosCapabilities = sosCapabilities; return this; } public SosCapabilities getSosCapabilities() { return sosCapabilities; } } private static final Logger LOGGER = LoggerFactory.getLogger(GetCapabilitiesDAO.class); /* section flags (values are powers of 2) */ private static final int SERVICE_IDENTIFICATION = 0x01; private static final int SERVICE_PROVIDER = 0x02; private static final int OPERATIONS_METADATA = 0x04; private static final int FILTER_CAPABILITIES = 0x08; private static final int CONTENTS = 0x10; private static final int ALL = 0x20 | SERVICE_IDENTIFICATION | SERVICE_PROVIDER | OPERATIONS_METADATA | FILTER_CAPABILITIES | CONTENTS; public GetCapabilitiesDAO() { super(SosConstants.SOS); } @Override public GetCapabilitiesResponse getCapabilities(final GetCapabilitiesRequest request) throws OwsExceptionReport { final GetCapabilitiesResponse response = request.getResponse(); final String scId = request.getCapabilitiesId(); if (scId == null) { if (getSettingsManager().isStaticCapabilitiesActive()) { response.setXmlString(getSettingsManager().getActiveStaticCapabilitiesDocument()); return response; } } else if (!scId.equals(SosConstants.GetCapabilitiesParams.DYNAMIC_CAPABILITIES_IDENTIFIER)) { final StaticCapabilities sc = getSettingsManager().getStaticCapabilities(scId); if (sc == null) { throw new InvalidParameterValueException(SosConstants.GetCapabilitiesParams.CapabilitiesId, scId); } response.setXmlString(sc.getDocument()); return response; } final Set<String> availableExtensionSections = getExtensionSections(response.getService(), response.getVersion()); final Set<String> requestedExtensionSections = new HashSet<String>(availableExtensionSections.size()); final int requestedSections = identifyRequestedSections(request, response, availableExtensionSections, requestedExtensionSections); final SosCapabilities sosCapabilities = new SosCapabilities(response.getVersion()); SectionSpecificContentObject sectionSpecificContentObject = new SectionSpecificContentObject().setRequest(request).setResponse(response) .setRequestedExtensionSections(requestedExtensionSections) .setRequestedSections(requestedSections).setSosCapabilities(sosCapabilities); addSectionSpecificContent(sectionSpecificContentObject, request); response.setCapabilities(sosCapabilities); return response; } private void addSectionSpecificContent(final SectionSpecificContentObject sectionSpecificContentObject, GetCapabilitiesRequest request) throws OwsExceptionReport { String verion = sectionSpecificContentObject.getGetCapabilitiesResponse().getVersion(); String service = sectionSpecificContentObject.getGetCapabilitiesResponse().getService(); if (isServiceIdentificationSectionRequested(sectionSpecificContentObject.getRequestedSections())) { sectionSpecificContentObject.getSosCapabilities().setServiceIdentification( getServiceIdentification(request, verion)); } if (isServiceProviderSectionRequested(sectionSpecificContentObject.getRequestedSections())) { sectionSpecificContentObject.getSosCapabilities().setServiceProvider( getConfigurator().getServiceProvider()); } if (isOperationsMetadataSectionRequested(sectionSpecificContentObject.getRequestedSections())) { sectionSpecificContentObject.getSosCapabilities().setOperationsMetadata( getOperationsMetadataForOperations(request, service, verion)); } if (isFilterCapabilitiesSectionRequested(sectionSpecificContentObject.getRequestedSections())) { sectionSpecificContentObject.getSosCapabilities().setFilterCapabilities(getFilterCapabilities(verion)); } if (isContentsSectionRequested(sectionSpecificContentObject.getRequestedSections())) { if (isVersionSos2(sectionSpecificContentObject.getGetCapabilitiesResponse())) { sectionSpecificContentObject.getSosCapabilities().setContents( getContentsForSosV2(sectionSpecificContentObject)); } else { sectionSpecificContentObject.getSosCapabilities().setContents( getContents(sectionSpecificContentObject)); } } if (isVersionSos2(sectionSpecificContentObject.getGetCapabilitiesResponse())) { if (sectionSpecificContentObject.getRequestedSections() == ALL) { sectionSpecificContentObject.getSosCapabilities().setExensions(getAndMergeExtensions(service, verion)); } else if (!sectionSpecificContentObject.getRequestedExtensionSesctions().isEmpty()) { sectionSpecificContentObject.getSosCapabilities().setExensions( getExtensions(sectionSpecificContentObject.getRequestedExtensionSesctions(), service, verion)); } } } private int identifyRequestedSections(final GetCapabilitiesRequest request, final GetCapabilitiesResponse response, final Set<String> availableExtensionSections, final Set<String> requestedExtensionSections) throws OwsExceptionReport { int sections = 0; // handle sections array and set requested sections flag if (!request.isSetSections()) { sections = ALL; } else { for (final String section : request.getSections()) { if (section.isEmpty()) { LOGGER.warn("A {} element is empty! Check if operator checks for empty elements!", SosConstants.GetCapabilitiesParams.Section.name()); continue; } if (section.equals(SosConstants.CapabilitiesSections.All.name())) { sections = ALL; break; } else if (section.equals(SosConstants.CapabilitiesSections.ServiceIdentification.name())) { sections |= SERVICE_IDENTIFICATION; } else if (section.equals(SosConstants.CapabilitiesSections.ServiceProvider.name())) { sections |= SERVICE_PROVIDER; } else if (section.equals(SosConstants.CapabilitiesSections.OperationsMetadata.name())) { sections |= OPERATIONS_METADATA; } else if ((section.equals(Sos1Constants.CapabilitiesSections.Filter_Capabilities.name()) && response .getVersion().equals(Sos1Constants.SERVICEVERSION)) || (section.equals(Sos2Constants.CapabilitiesSections.FilterCapabilities.name()) && isVersionSos2(response))) { sections |= FILTER_CAPABILITIES; } else if (section.equals(SosConstants.CapabilitiesSections.Contents.name())) { sections |= CONTENTS; } else if (availableExtensionSections.contains(section) && isVersionSos2(response)) { requestedExtensionSections.add(section); } else { throw new InvalidParameterValueException().at(SosConstants.GetCapabilitiesParams.Section) .withMessage("The requested section '%s' does not exist or is not supported!", section); } } } return sections; } private SosServiceIdentification getServiceIdentification( GetCapabilitiesRequest request, String version) throws OwsExceptionReport { Locale locale = LocaleHelper.fromRequest(request); SosServiceIdentification serviceIdentification = getConfigurator() .getServiceIdentification(locale); if (version.equals(Sos2Constants.SERVICEVERSION)) { serviceIdentification.setProfiles(getProfiles()); } return serviceIdentification; } private Set<String> getProfiles() { final List<String> profiles = new LinkedList<String>(); for (final Binding bindig : BindingRepository.getInstance().getBindings().values()) { profiles.addAll(bindig.getConformanceClasses()); } for (final RequestOperatorKey k : RequestOperatorRepository.getInstance().getActiveRequestOperatorKeys()) { profiles.addAll(RequestOperatorRepository.getInstance().getRequestOperator(k).getConformanceClasses()); } for (final Decoder<?, ?> decoder : CodingRepository.getInstance().getDecoders()) { profiles.addAll(decoder.getConformanceClasses()); } for (final Encoder<?, ?> encoder : CodingRepository.getInstance().getEncoders()) { profiles.addAll(encoder.getConformanceClasses()); } for (final OperationDAO operationDAO : OperationDAORepository.getInstance().getOperationDAOs().values()) { profiles.addAll(operationDAO.getConformanceClasses()); } // FIXME additional profiles if ("hydrology".equalsIgnoreCase(Configurator.getInstance().getProfileHandler().getActiveProfile() .getIdentifier())) { profiles.add("http://www.opengis.net/spec/SOS_application-profile_hydrology/1.0/req/hydrosos"); } return Sets.newHashSet(profiles); } /** * Get the OperationsMetadat for all supported operations * * @param service * Requested service * @param version * Requested service version * @return OperationsMetadata for all operations supported by the requested * service and version * @throws OwsExceptionReport * If an error occurs */ private OwsOperationsMetadata getOperationsMetadataForOperations(final GetCapabilitiesRequest request, final String service, final String version) throws OwsExceptionReport { final OwsOperationsMetadata operationsMetadata = new OwsOperationsMetadata(); operationsMetadata.addCommonValue(OWSConstants.RequestParams.service.name(), new OwsParameterValuePossibleValues(SosConstants.SOS)); operationsMetadata.addCommonValue( OWSConstants.RequestParams.version.name(), new OwsParameterValuePossibleValues(ServiceOperatorRepository.getInstance().getSupportedVersions( service))); // crs operationsMetadata.addCommonValue(OWSConstants.AdditionalRequestParams.crs.name(), new OwsParameterValuePossibleValues(GeometryHandler.getInstance().addOgcCrsPrefix(getCache().getEpsgCodes()))); // language operationsMetadata.addCommonValue(OWSConstants.AdditionalRequestParams.language.name(), new OwsParameterValuePossibleValues(Collections2.transform(getCache().getSupportedLanguages(), LocaleHelper.toStringFunction()))); // FIXME: OpsMetadata for InsertSensor, InsertObservation SOS 2.0 final Set<RequestOperatorKey> requestOperatorKeyTypes = RequestOperatorRepository.getInstance().getActiveRequestOperatorKeys(); final List<OwsOperation> opsMetadata = new ArrayList<OwsOperation>(requestOperatorKeyTypes.size()); for (final RequestOperatorKey requestOperatorKeyType : requestOperatorKeyTypes) { if (requestOperatorKeyType.getServiceOperatorKey().getVersion().equals(version)) { final OwsOperation operationMetadata = RequestOperatorRepository.getInstance().getRequestOperator(requestOperatorKeyType) .getOperationMetadata(service, version); if (operationMetadata != null) { opsMetadata.add(operationMetadata); } } } operationsMetadata.setOperations(opsMetadata); /* * check if an OwsExtendedCapabilities provider is available for this * service and check if this provider provides OwsExtendedCapabilities * for the request */ if (OwsExtendedCapabilitiesRepository.getInstance().hasExtendedCapabilitiesProvider(request)) { OwsExtendedCapabilitiesProvider extendedCapabilitiesProvider = OwsExtendedCapabilitiesRepository.getInstance().getExtendedCapabilitiesProvider(request); if (extendedCapabilitiesProvider != null && extendedCapabilitiesProvider.hasExtendedCapabilitiesFor(request)) { operationsMetadata.setExtendedCapabilities(extendedCapabilitiesProvider .getOwsExtendedCapabilities(request)); } } return operationsMetadata; } /** * Get the FilterCapabilities * * @param version * Requested service version * @return FilterCapabilities */ private FilterCapabilities getFilterCapabilities(final String version) { final FilterCapabilities filterCapabilities = new FilterCapabilities(); if (Sos2Constants.SERVICEVERSION.equals(version)) { getConformance(filterCapabilities); } // !!! Modify methods addicted to your implementation !!! if (version.equals(Sos1Constants.SERVICEVERSION)) { getScalarFilterCapabilities(filterCapabilities); } getSpatialFilterCapabilities(filterCapabilities, version); getTemporalFilterCapabilities(filterCapabilities, version); return filterCapabilities; } private void getConformance(final FilterCapabilities filterCapabilities) { // set Query conformance class filterCapabilities.addConformance(new OwsDomainType(ConformanceClassConstraintNames.ImplementsQuery.name(), new OwsNoValues(), FALSE)); // set Ad hoc query conformance class filterCapabilities.addConformance(new OwsDomainType(ConformanceClassConstraintNames.ImplementsAdHocQuery .name(), new OwsNoValues(), FALSE)); // set Functions conformance class filterCapabilities.addConformance(new OwsDomainType( ConformanceClassConstraintNames.ImplementsFunctions.name(), new OwsNoValues(), FALSE)); // set Resource Identification conformance class filterCapabilities.addConformance(new OwsDomainType(ConformanceClassConstraintNames.ImplementsResourceld .name(), new OwsNoValues(), FALSE)); // set Minimum Standard Filter conformance class filterCapabilities.addConformance(new OwsDomainType( ConformanceClassConstraintNames.ImplementsMinStandardFilter.name(), new OwsNoValues(), FALSE)); // set Standard Filter conformance class filterCapabilities.addConformance(new OwsDomainType(ConformanceClassConstraintNames.ImplementsStandardFilter .name(), new OwsNoValues(), FALSE)); // set Minimum Spatial Filter conformance class filterCapabilities.addConformance(new OwsDomainType(ConformanceClassConstraintNames.ImplementsMinSpatialFilter .name(), new OwsNoValues(), TRUE)); // set Spatial Filter conformance class filterCapabilities.addConformance(new OwsDomainType(ConformanceClassConstraintNames.ImplementsSpatialFilter .name(), new OwsNoValues(), TRUE)); // set Minimum Temporal Filter conformance class filterCapabilities.addConformance(new OwsDomainType( ConformanceClassConstraintNames.ImplementsMinTemporalFilter.name(), new OwsNoValues(), TRUE)); // set Temporal Filter conformance class filterCapabilities.addConformance(new OwsDomainType(ConformanceClassConstraintNames.ImplementsTemporalFilter .name(), new OwsNoValues(), TRUE)); // set Version navigation conformance class filterCapabilities.addConformance(new OwsDomainType(ConformanceClassConstraintNames.ImplementsVersionNav .name(), new OwsNoValues(), FALSE)); // set Sorting conformance class filterCapabilities.addConformance(new OwsDomainType(ConformanceClassConstraintNames.ImplementsSorting.name(), new OwsNoValues(), FALSE)); // set Extended Operators conformance class filterCapabilities.addConformance(new OwsDomainType( ConformanceClassConstraintNames.ImplementsExtendedOperators.name(), new OwsNoValues(), FALSE)); // set Minimum XPath conformance class filterCapabilities.addConformance(new OwsDomainType(ConformanceClassConstraintNames.ImplementsMinimumXPath .name(), new OwsNoValues(), FALSE)); // set Schema Element Function conformance class filterCapabilities.addConformance(new OwsDomainType( ConformanceClassConstraintNames.ImplementsSchemaElementFunc.name(), new OwsNoValues(), FALSE)); } /** * Get the contents for SOS 1.0.0 capabilities * * @param version * Requested service version * @return Offerings for contents * * * @throws OwsExceptionReport * * If an error occurs */ private List<SosObservationOffering> getContents(SectionSpecificContentObject sectionSpecificContentObject) throws OwsExceptionReport { String version = sectionSpecificContentObject.getGetCapabilitiesResponse().getVersion(); final Collection<String> offerings = getCache().getOfferings(); final List<SosObservationOffering> sosOfferings = new ArrayList<SosObservationOffering>(offerings.size()); for (final String offering : offerings) { final Collection<String> procedures = getProceduresForOffering(offering, version); final SosEnvelope envelopeForOffering = getCache().getEnvelopeForOffering(offering); final Set<String> featuresForoffering = getFOI4offering(offering); final Collection<String> responseFormats = CodingRepository.getInstance().getSupportedResponseFormats(SosConstants.SOS, Sos1Constants.SERVICEVERSION); if (checkOfferingValues(envelopeForOffering, featuresForoffering, responseFormats, procedures)) { final SosObservationOffering sosObservationOffering = new SosObservationOffering(); // insert observationTypes sosObservationOffering.setObservationTypes(getObservationTypes(offering)); // only if fois are contained for the offering set the values of // the envelope sosObservationOffering .setObservedArea(processObservedArea(getCache().getEnvelopeForOffering(offering))); // TODO: add intended application // xb_oo.addIntendedApplication(""); // add offering name addSosOfferingToObservationOffering(offering, sosObservationOffering, sectionSpecificContentObject.getGetCapabilitiesRequest()); // set up phenomena sosObservationOffering .setObservableProperties(getCache().getObservablePropertiesForOffering(offering)); sosObservationOffering.setCompositePhenomena(getCache().getCompositePhenomenonsForOffering(offering)); final Map<String, Collection<String>> phens4CompPhens = new HashMap<String, Collection<String>>(); if (getCache().getCompositePhenomenonsForOffering(offering) != null) { for (final String compositePhenomenon : getCache().getCompositePhenomenonsForOffering(offering)) { phens4CompPhens.put(compositePhenomenon, getCache() .getObservablePropertiesForCompositePhenomenon(compositePhenomenon)); } } sosObservationOffering.setPhens4CompPhens(phens4CompPhens); // set up time setUpTimeForOffering(offering, sosObservationOffering); // add feature of interests if (getConfigurator().getProfileHandler().getActiveProfile().isListFeatureOfInterestsInOfferings()) { sosObservationOffering.setFeatureOfInterest(getFOI4offering(offering)); } // set procedures sosObservationOffering.setProcedures(procedures); // insert result models final Collection<QName> resultModels = OMHelper.getQNamesForResultModel(getCache().getObservationTypesForOffering(offering)); sosObservationOffering.setResultModels(resultModels); // set response format sosObservationOffering.setResponseFormats(responseFormats); // set response Mode sosObservationOffering.setResponseModes(SosConstants.RESPONSE_MODES); sosOfferings.add(sosObservationOffering); } } return sosOfferings; } protected SettingsManager getSettingsManager() throws ConfigurationException { return SettingsManager.getInstance(); } private SosEnvelope processObservedArea(SosEnvelope sosEnvelope) throws CodedException { // TODO Check transformation // if (requestedSrid >= 0 && sosEnvelope.getSrid() != requestedSrid) { // SosEnvelope tranformedEnvelope = new SosEnvelope(); // tranformedEnvelope.setSrid(requestedSrid); // tranformedEnvelope.setEnvelope(GeometryHandler.getInstance().transformEnvelope(sosEnvelope.getEnvelope(), // sosEnvelope.getSrid(), requestedSrid)); // return tranformedEnvelope; // } return sosEnvelope; } private boolean checkOfferingValues(final SosEnvelope envelopeForOffering, final Set<String> featuresForOffering, final Collection<String> responseFormats, Collection<String> procedures) { return SosEnvelope.isNotNullOrEmpty(envelopeForOffering) && CollectionHelper.isNotEmpty(featuresForOffering) && CollectionHelper.isNotEmpty(responseFormats) && CollectionHelper.isNotEmpty(procedures); } /** * Get the contents for SOS 2.0 capabilities * * @param version * Requested service version * @return Offerings for contents * * * @throws OwsExceptionReport * * If an error occurs */ // FIXME why version parameter? The method signature cleary states which // version is supported by this! private List<SosObservationOffering> getContentsForSosV2(SectionSpecificContentObject sectionSpecificContentObject) throws OwsExceptionReport { String version = sectionSpecificContentObject.getGetCapabilitiesResponse().getVersion(); final Collection<String> offerings = getCache().getOfferings(); final List<SosObservationOffering> sosOfferings = new ArrayList<SosObservationOffering>(offerings.size()); final Map<String, List<OfferingExtension>> extensions = getSettingsManager().getActiveOfferingExtensions(); if (CollectionHelper.isEmpty(offerings)) { // Set empty offering to add empty Contents section to Capabilities sosOfferings.add(new SosObservationOffering()); } else { for (final String offering : offerings) { final Collection<String> procedures = getProceduresForOffering(offering, version); final Collection<String> observationTypes = getObservationTypes(offering); if (observationTypes != null && !observationTypes.isEmpty()) { // FIXME why a loop? We are in SOS 2.0 context -> offering 1 // <-> 1 procedure! for (final String procedure : procedures) { final SosObservationOffering sosObservationOffering = new SosObservationOffering(); // insert observationTypes sosObservationOffering.setObservationTypes(observationTypes); if (getCache().hasSpatialFilteringProfileEnvelopeForOffering(offering)) { sosObservationOffering.setObservedArea(processObservedArea(getCache() .getSpatialFilteringProfileEnvelopeForOffering(offering))); } else { sosObservationOffering.setObservedArea(processObservedArea(getCache() .getEnvelopeForOffering(offering))); } sosObservationOffering.setProcedures(Collections.singletonList(procedure)); // TODO: add intended application // add offering to observation offering addSosOfferingToObservationOffering(offering, sosObservationOffering, sectionSpecificContentObject.getGetCapabilitiesRequest()); // add offering extension if (OfferingExtensionRepository.getInstance().hasOfferingExtensionProviderFor(sectionSpecificContentObject.getGetCapabilitiesRequest())) { for (OfferingExtensionProvider provider : OfferingExtensionRepository.getInstance().getOfferingExtensionProvider(sectionSpecificContentObject.getGetCapabilitiesRequest())) { if (provider != null && provider.hasExtendedOfferingFor(offering)) { sosObservationOffering.addExtensions(provider.getOfferingExtensions(offering)); } } } if (extensions.containsKey(sosObservationOffering.getOffering().getIdentifier())) { for (OfferingExtension offeringExtension : extensions.get(sosObservationOffering.getOffering().getIdentifier())) { sosObservationOffering.addExtension(new SwesExtensionImpl<OfferingExtension>().setValue(offeringExtension)); } } setUpPhenomenaForOffering(offering, procedure, sosObservationOffering); setUpTimeForOffering(offering, sosObservationOffering); setUpRelatedFeaturesForOffering(offering, version, procedure, sosObservationOffering); setUpFeatureOfInterestTypesForOffering(offering, sosObservationOffering); setUpProcedureDescriptionFormatForOffering(sosObservationOffering, version); setUpResponseFormatForOffering(version, sosObservationOffering); sosOfferings.add(sosObservationOffering); } } } } return sosOfferings; } private void addSosOfferingToObservationOffering(String offering, SosObservationOffering sosObservationOffering, GetCapabilitiesRequest request) { SosOffering sosOffering = new SosOffering(offering, false); sosObservationOffering.setOffering(sosOffering); // add offering name I18NHelper.addOfferingNames(sosOffering, request); // add offering description I18NHelper.addOfferingDescription(sosOffering, request); } /** * Set SpatialFilterCapabilities to FilterCapabilities * * @param filterCapabilities * FilterCapabilities * @param version * SOS version */ private void getSpatialFilterCapabilities(final FilterCapabilities filterCapabilities, final String version) { // set GeometryOperands final List<QName> operands = new LinkedList<QName>(); if (version.equals(Sos2Constants.SERVICEVERSION)) { operands.add(GmlConstants.QN_ENVELOPE_32); } else if (version.equals(Sos1Constants.SERVICEVERSION)) { operands.add(GmlConstants.QN_ENVELOPE); operands.add(GmlConstants.QN_POINT); operands.add(GmlConstants.QN_LINESTRING); operands.add(GmlConstants.QN_POLYGON); } filterCapabilities.setSpatialOperands(operands); // set SpatialOperators final SetMultiMap<SpatialOperator, QName> ops = MultiMaps.newSetMultiMap(SpatialOperator.class); if (version.equals(Sos2Constants.SERVICEVERSION)) { ops.add(SpatialOperator.BBOX, GmlConstants.QN_ENVELOPE_32); } else if (version.equals(Sos1Constants.SERVICEVERSION)) { ops.add(SpatialOperator.BBOX, GmlConstants.QN_ENVELOPE); // set Contains ops.add(SpatialOperator.Contains, GmlConstants.QN_POINT); ops.add(SpatialOperator.Contains, GmlConstants.QN_LINESTRING); ops.add(SpatialOperator.Contains, GmlConstants.QN_POLYGON); // set Intersects ops.add(SpatialOperator.Intersects, GmlConstants.QN_POINT); ops.add(SpatialOperator.Intersects, GmlConstants.QN_LINESTRING); ops.add(SpatialOperator.Intersects, GmlConstants.QN_POLYGON); // set Overlaps ops.add(SpatialOperator.Overlaps, GmlConstants.QN_POINT); ops.add(SpatialOperator.Overlaps, GmlConstants.QN_LINESTRING); ops.add(SpatialOperator.Overlaps, GmlConstants.QN_POLYGON); } filterCapabilities.setSpatialOperators(ops); } /** * Set TemporalFilterCapabilities to FilterCapabilities * * @param filterCapabilities * FilterCapabilities * @param version * SOS version */ private void getTemporalFilterCapabilities(final FilterCapabilities filterCapabilities, final String version) { // set TemporalOperands final List<QName> operands = new ArrayList<QName>(2); if (version.equals(Sos2Constants.SERVICEVERSION)) { operands.add(GmlConstants.QN_TIME_PERIOD_32); operands.add(GmlConstants.QN_TIME_INSTANT_32); } else if (version.equals(Sos1Constants.SERVICEVERSION)) { operands.add(GmlConstants.QN_TIME_PERIOD); operands.add(GmlConstants.QN_TIME_INSTANT); } filterCapabilities.setTemporalOperands(operands); // set TemporalOperators final SetMultiMap<TimeOperator, QName> ops = MultiMaps.newSetMultiMap(TimeOperator.class); if (version.equals(Sos2Constants.SERVICEVERSION)) { for (final TimeOperator op : TimeOperator.values()) { ops.add(op, GmlConstants.QN_TIME_INSTANT_32); ops.add(op, GmlConstants.QN_TIME_PERIOD_32); } } else if (version.equals(Sos1Constants.SERVICEVERSION)) { for (final TimeOperator op : TimeOperator.values()) { ops.add(op, GmlConstants.QN_TIME_INSTANT); ops.add(op, GmlConstants.QN_TIME_PERIOD); } } filterCapabilities.setTempporalOperators(ops); } /** * Set ScalarFilterCapabilities to FilterCapabilities * * @param filterCapabilities * FilterCapabilities */ private void getScalarFilterCapabilities(final FilterCapabilities filterCapabilities) { // TODO PropertyIsNil, PropertyIsNull? better: // filterCapabilities.setComparisonOperators(Arrays.asList(ComparisonOperator.values())); final List<ComparisonOperator> comparisonOperators = new ArrayList<ComparisonOperator>(8); comparisonOperators.add(ComparisonOperator.PropertyIsBetween); comparisonOperators.add(ComparisonOperator.PropertyIsEqualTo); comparisonOperators.add(ComparisonOperator.PropertyIsNotEqualTo); comparisonOperators.add(ComparisonOperator.PropertyIsLessThan); comparisonOperators.add(ComparisonOperator.PropertyIsLessThanOrEqualTo); comparisonOperators.add(ComparisonOperator.PropertyIsGreaterThan); comparisonOperators.add(ComparisonOperator.PropertyIsGreaterThanOrEqualTo); comparisonOperators.add(ComparisonOperator.PropertyIsLike); filterCapabilities.setComparisonOperators(comparisonOperators); } /** * Get FOIs contained in an offering * * @param offering * Offering identifier * @return FOI identifiers * * * @throws OwsExceptionReport * * If an error occurs */ private Set<String> getFOI4offering(final String offering) throws OwsExceptionReport { final Set<String> featureIDs = new HashSet<String>(0); final Set<String> features = getConfigurator().getCache().getFeaturesOfInterestForOffering(offering); if (!getConfigurator().getProfileHandler().getActiveProfile().isListFeatureOfInterestsInOfferings() || features == null) { featureIDs.add(OGCConstants.UNKNOWN); } else { featureIDs.addAll(features); } return featureIDs; } private Collection<String> getObservationTypes(final String offering) { final Collection<String> allObservationTypes = getCache().getObservationTypesForOffering(offering); final List<String> observationTypes = new ArrayList<String>(allObservationTypes.size()); for (final String observationType : allObservationTypes) { if (!observationType.equals(SosConstants.NOT_DEFINED)) { observationTypes.add(observationType); } } if (observationTypes.isEmpty()) { for (final String observationType : getCache().getAllowedObservationTypesForOffering(offering)) { if (!observationType.equals(SosConstants.NOT_DEFINED)) { observationTypes.add(observationType); } } } return observationTypes; } @Override protected Set<String> getExtensionSections(final String service, final String version) throws OwsExceptionReport { final Collection<CapabilitiesExtension> extensions = getAndMergeExtensions(service, version); final HashSet<String> sections = new HashSet<String>(extensions.size()); for (final CapabilitiesExtension e : extensions) { sections.add(e.getSectionName()); } return sections; } /** * Get extensions and merge MergableExtension of the same class. * * @return Extensions * * * @throws OwsExceptionReport */ @SuppressWarnings({ "rawtypes", "unchecked" }) private List<CapabilitiesExtension> getAndMergeExtensions(final String service, final String version) throws OwsExceptionReport { final List<CapabilitiesExtensionProvider> capabilitiesExtensionProviders = CapabilitiesExtensionRepository.getInstance().getCapabilitiesExtensionProvider(service, version); final List<CapabilitiesExtension> extensions = Lists.newLinkedList(); if (CollectionHelper.isNotEmpty(capabilitiesExtensionProviders)) { final HashMap<String, MergableExtension> map = new HashMap<String, MergableExtension>(capabilitiesExtensionProviders.size()); for (final CapabilitiesExtensionProvider capabilitiesExtensionDAO : capabilitiesExtensionProviders) { if (capabilitiesExtensionDAO.getExtension() != null) { if (capabilitiesExtensionDAO.getExtension() instanceof MergableExtension) { final MergableExtension me = (MergableExtension) capabilitiesExtensionDAO.getExtension(); final MergableExtension previous = map.get(me.getSectionName()); if (previous == null) { map.put(me.getSectionName(), me); } else { previous.merge(me); } } else { extensions.add(capabilitiesExtensionDAO.getExtension()); } } } extensions.addAll(map.values()); } extensions.addAll(getSettingsManager().getActiveCapabilitiesExtensions().values()); return extensions; } private Collection<CapabilitiesExtension> getExtensions(final Set<String> requestedExtensionSections, final String service, final String version) throws OwsExceptionReport { final List<CapabilitiesExtension> extensions = getAndMergeExtensions(service, version); final List<CapabilitiesExtension> filtered = new ArrayList<CapabilitiesExtension>(requestedExtensionSections.size()); for (final CapabilitiesExtension e : extensions) { if (requestedExtensionSections.contains(e.getSectionName())) { filtered.add(e); } } return filtered; } protected void setUpPhenomenaForOffering(final String offering, final String procedure, final SosObservationOffering sosOffering) { final Collection<String> phenomenons = new LinkedList<String>(); final Collection<String> observablePropertiesForOffering = getCache().getObservablePropertiesForOffering(offering); for (final String observableProperty : observablePropertiesForOffering) { if (getCache().getPublishedObservableProperties().contains(observableProperty)) { final Set<String> proceduresForObservableProperty = getCache().getProceduresForObservableProperty(observableProperty); if (proceduresForObservableProperty.contains(procedure) || isHiddenChildProcedureObservableProperty(offering, proceduresForObservableProperty)) { phenomenons.add(observableProperty); } } } sosOffering.setObservableProperties(phenomenons); sosOffering.setCompositePhenomena(getCache().getCompositePhenomenonsForOffering(offering)); final Collection<String> compositePhenomenonsForOffering = getCache().getCompositePhenomenonsForOffering(offering); if (compositePhenomenonsForOffering != null) { final Map<String, Collection<String>> phens4CompPhens = new HashMap<String, Collection<String>>(compositePhenomenonsForOffering.size()); for (final String compositePhenomenon : compositePhenomenonsForOffering) { final Collection<String> phenomenonsForComposite = getCache().getObservablePropertiesForCompositePhenomenon(compositePhenomenon); phens4CompPhens.put(compositePhenomenon, phenomenonsForComposite); } sosOffering.setPhens4CompPhens(phens4CompPhens); } else { sosOffering.setPhens4CompPhens(Collections.<String, Collection<String>> emptyMap()); } } private boolean isHiddenChildProcedureObservableProperty(final String offering, final Set<String> proceduresForObservableProperty) { for (final String hiddenProcedure : getCache().getHiddenChildProceduresForOffering(offering)) { if (proceduresForObservableProperty.contains(hiddenProcedure)) { return true; } } return false; } protected void setUpRelatedFeaturesForOffering(final String offering, final String version, final String procedure, final SosObservationOffering sosOffering) throws OwsExceptionReport { final Map<String, Set<String>> relatedFeatures = Maps.newHashMap(); final Set<String> relatedFeaturesForThisOffering = getCache().getRelatedFeaturesForOffering(offering); if (CollectionHelper.isNotEmpty(relatedFeaturesForThisOffering)) { for (final String relatedFeature : relatedFeaturesForThisOffering) { relatedFeatures.put(relatedFeature, getCache().getRolesForRelatedFeature(relatedFeature)); } /* * TODO add setting to set FeatureOfInterest if relatedFeatures are * empty. } else { final Set<String> role = * Collections.singleton("featureOfInterestID"); final Set<String> * featuresForOffering = * getCache().getFeaturesOfInterestForOffering(offering); if * (featuresForOffering != null) { for (final String foiID : * featuresForOffering) { if * (getCache().getProceduresForFeatureOfInterest * (foiID).contains(procedure)) { relatedFeatures.put(foiID, role); * } } } */ } sosOffering.setRelatedFeatures(relatedFeatures); } protected void setUpTimeForOffering(final String offering, final SosObservationOffering sosOffering) { sosOffering.setPhenomenonTime(new TimePeriod(getCache().getMinPhenomenonTimeForOffering(offering), getCache() .getMaxPhenomenonTimeForOffering(offering))); sosOffering.setResultTime(new TimePeriod(getCache().getMinResultTimeForOffering(offering), getCache() .getMaxResultTimeForOffering(offering))); } protected void setUpFeatureOfInterestTypesForOffering(final String offering, final SosObservationOffering sosOffering) { sosOffering.setFeatureOfInterestTypes(getCache().getAllowedFeatureOfInterestTypesForOffering(offering)); } protected void setUpResponseFormatForOffering(final String version, final SosObservationOffering sosOffering) { // initialize as new HashSet so that collection is modifiable final Collection<String> responseFormats = new HashSet<String>(CodingRepository.getInstance().getSupportedResponseFormats(SosConstants.SOS, version)); sosOffering.setResponseFormats(responseFormats); // TODO set as property } protected void setUpProcedureDescriptionFormatForOffering(final SosObservationOffering sosOffering, final String version) { // TODO: set procDescFormat <-- what is required here? sosOffering.setProcedureDescriptionFormat(CodingRepository.getInstance() .getSupportedProcedureDescriptionFormats(SosConstants.SOS, version)); } private Collection<String> getProceduresForOffering(final String offering, final String version) throws OwsExceptionReport { final Collection<String> procedures = Sets.newHashSet(getCache().getProceduresForOffering(offering)); if (version.equals(Sos1Constants.SERVICEVERSION)) { procedures.addAll(getCache().getHiddenChildProceduresForOffering(offering)); } if (procedures.isEmpty()) { throw new NoApplicableCodeException() .withMessage( "No procedures are contained in the database for the offering '%s'! Please contact the admin of this SOS.", offering); } Collection<String> published = Sets.newHashSet(); for (String procedure : procedures) { if (getCache().getPublishedProcedures().contains(procedure)) { published.add(procedure); } } return published; } private boolean isVersionSos2(final GetCapabilitiesResponse response) { return response.getVersion().equals(Sos2Constants.SERVICEVERSION); } private boolean isContentsSectionRequested(final int sections) { return (sections & CONTENTS) != 0; } private boolean isFilterCapabilitiesSectionRequested(final int sections) { return (sections & FILTER_CAPABILITIES) != 0; } private boolean isOperationsMetadataSectionRequested(final int sections) { return (sections & OPERATIONS_METADATA) != 0; } private boolean isServiceProviderSectionRequested(final int sections) { return (sections & SERVICE_PROVIDER) != 0; } private boolean isServiceIdentificationSectionRequested(final int sections) { return (sections & SERVICE_IDENTIFICATION) != 0; } @Override public String getDatasourceDaoIdentifier() { return IDEPENDET_IDENTIFIER; } }