/** * 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.encode.sos.v2; import java.util.Collection; import java.util.Set; import net.opengis.sos.x20.CapabilitiesDocument; import net.opengis.sos.x20.CapabilitiesType; import net.opengis.sos.x20.CapabilitiesType.Contents; import net.opengis.sos.x20.ContentsType; import net.opengis.sos.x20.InsertionCapabilitiesDocument; import net.opengis.sos.x20.InsertionCapabilitiesType; import net.opengis.sos.x20.ObservationOfferingType; import net.opengis.swes.x20.AbstractContentsType.Offering; import net.opengis.swes.x20.FeatureRelationshipType; import org.apache.xmlbeans.XmlCursor; import org.apache.xmlbeans.XmlException; import org.apache.xmlbeans.XmlObject; import org.n52.sos.exception.CodedException; import org.n52.sos.exception.ows.OptionNotSupportedException; import org.n52.sos.exception.ows.concrete.XmlDecodingException; import org.n52.sos.ogc.gml.CodeType; import org.n52.sos.ogc.gml.GmlConstants; import org.n52.sos.ogc.gml.time.TimePeriod; import org.n52.sos.ogc.ows.OfferingExtension; import org.n52.sos.ogc.ows.OwsExceptionReport; import org.n52.sos.ogc.ows.StringBasedExtension; import org.n52.sos.ogc.sos.CapabilitiesExtension; 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.SosInsertionCapabilities; import org.n52.sos.ogc.sos.SosObservationOffering; import org.n52.sos.ogc.sos.SosOffering; import org.n52.sos.ogc.swes.SwesExtension; import org.n52.sos.response.GetCapabilitiesResponse; import org.n52.sos.util.CodingHelper; import org.n52.sos.w3c.SchemaLocation; import org.n52.sos.w3c.W3CConstants; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.google.common.collect.Sets; /** * TODO JavaDoc * * @author Christian Autermann <c.autermann@52north.org> * * @since 4.0.0 */ public class GetCapabilitiesResponseEncoder extends AbstractSosResponseEncoder<GetCapabilitiesResponse> { private static final Logger LOGGER = LoggerFactory.getLogger(GetCapabilitiesResponseEncoder.class); public GetCapabilitiesResponseEncoder() { super(SosConstants.Operations.GetCapabilities.name(), GetCapabilitiesResponse.class); } @Override protected XmlObject create(GetCapabilitiesResponse response) throws OwsExceptionReport { CapabilitiesDocument doc = CapabilitiesDocument.Factory.newInstance(getXmlOptions()); CapabilitiesType xbCaps = doc.addNewCapabilities(); if (response.isStatic()) { String xml = response.getXmlString(); LOGGER.trace("Response is static. XML-String:\n{}\n",xml); try { doc.set(XmlObject.Factory.parse(xml)); return doc; } catch (XmlException ex) { throw new XmlDecodingException("Static Capabilities", xml, ex); } } // set version. SosCapabilities caps = response.getCapabilities(); if (caps.isSetVersion()) { xbCaps.setVersion(caps.getVersion()); } else { xbCaps.setVersion(response.getVersion()); } encodeServiceIdentification(caps, xbCaps); encodeServiceProvider(caps, xbCaps); encodeOperationsMetadata(caps, xbCaps); encodeFilterCapabilities(caps, xbCaps); encodeContents(caps, xbCaps, response.getVersion()); encodeExtensions(caps, xbCaps); return doc; } private void setExtensions(XmlObject addNewExtension, CapabilitiesExtension extension) throws CodedException { if (extension instanceof SosInsertionCapabilities) { addNewExtension.set(createInsertionCapabilities((SosInsertionCapabilities) extension)); } else if (extension instanceof StringBasedExtension) { String xml = ((StringBasedExtension) extension).getExtension(); try { addNewExtension.set(XmlObject.Factory.parse(xml)); } catch (XmlException ex) { throw new XmlDecodingException("SwesExtension", xml, ex); } } else { throw new OptionNotSupportedException() .withMessage("The extension element is not supported by this service!"); } } private XmlObject createInsertionCapabilities(SosInsertionCapabilities caps) { InsertionCapabilitiesDocument doc = InsertionCapabilitiesDocument.Factory.newInstance(getXmlOptions()); InsertionCapabilitiesType xbCaps = doc.addNewInsertionCapabilities(); if (caps.isSetFeatureOfInterestTypes()) { for (String foiType : caps.getFeatureOfInterestTypes()) { if (!foiType.equals(SosConstants.NOT_DEFINED)) { xbCaps.addFeatureOfInterestType(foiType); } } } if (caps.isSetObservationTypes()) { for (String oType : caps.getObservationTypes()) { if (!oType.equals(SosConstants.NOT_DEFINED)) { xbCaps.addObservationType(oType); } } } if (caps.isSetProcedureDescriptionFormats()) { for (String pdf : caps.getProcedureDescriptionFormats()) { if (!pdf.equals(SosConstants.NOT_DEFINED)) { xbCaps.addProcedureDescriptionFormat(pdf); } } } if (caps.isSetSupportedEncodings()) { for (String se : caps.getSupportedEncodings()) { if (!se.equals(SosConstants.NOT_DEFINED)) { xbCaps.addSupportedEncoding(se); } } } return doc; } /** * Sets the content section to the Capabilities document. * * @param xbContents * SOS 2.0 contents section * @param offerings * SOS offerings for contents * @param version * SOS response version * * * @throws OwsExceptionReport * * if an error occurs. */ protected void setContents(Contents xbContents, Collection<SosObservationOffering> offerings, String version) throws OwsExceptionReport { final ContentsType xbContType = xbContents.addNewContents(); int offeringCounter = 0; // for gml:id generation for (final SosObservationOffering offering : offerings) { if (offering.isValidObservationOffering()) { ++offeringCounter; encodeObservationOffering(offering, offeringCounter, xbContType); } } // FIXME: change swes:AbstractOffering to sos:ObservationOffering and // the namespace prefix ns to sos due to // XMLBeans problems with substitution // (http://www.mail-archive.com/dev%40xmlbeans.apache.org/msg00962.html). renameContentsElementNames(xbContents); } /** * Creates a XML FeatureRelationship for the relatedFeature * * @param featureRelationship * XML feature relationship * @param relatedFeatureTarget * Feature target identifier * @param roles * Features role */ private void createRelatedFeature(final FeatureRelationshipType featureRelationship, final String relatedFeatureTarget, final Collection<String> roles) { featureRelationship.addNewTarget().setHref(relatedFeatureTarget); if (roles != null) { for (final String role : roles) { featureRelationship.setRole(role); } } } private void renameContentsElementNames(final Contents xbContents) { for (final Offering offering : xbContents.getContents().getOfferingArray()) { final XmlCursor cursor = offering.getAbstractOffering().newCursor(); cursor.setName(Sos2Constants.QN_OBSERVATION_OFFERING); cursor.removeAttribute(W3CConstants.QN_XSI_TYPE); if (cursor.toChild(Sos2Constants.QN_SOS_OBSERVED_AREA)) { cursor.setName(Sos2Constants.QN_SOS_OBSERVED_AREA); cursor.toParent(); } if (cursor.toChild(Sos2Constants.QN_SOS_PHENOMENON_TIME)) { cursor.setName(Sos2Constants.QN_SOS_PHENOMENON_TIME); cursor.toParent(); } if (cursor.toChild(Sos2Constants.QN_SOS_RESULT_TIME)) { cursor.setName(Sos2Constants.QN_SOS_RESULT_TIME); cursor.toParent(); } if (cursor.toChild(Sos2Constants.QN_SOS_RESPONSE_FORMAT)) { cursor.setName(Sos2Constants.QN_SOS_RESPONSE_FORMAT); while (cursor.toNextSibling(Sos2Constants.QN_SOS_RESPONSE_FORMAT)) { cursor.setName(Sos2Constants.QN_SOS_RESPONSE_FORMAT); } cursor.toParent(); } if (cursor.toChild(Sos2Constants.QN_SOS_OBSERVATION_TYPE)) { cursor.setName(Sos2Constants.QN_SOS_OBSERVATION_TYPE); while (cursor.toNextSibling(Sos2Constants.QN_SOS_OBSERVATION_TYPE)) { cursor.setName(Sos2Constants.QN_SOS_OBSERVATION_TYPE); } cursor.toParent(); } if (cursor.toChild(Sos2Constants.QN_SOS_FEATURE_OF_INTEREST_TYPE)) { cursor.setName(Sos2Constants.QN_SOS_FEATURE_OF_INTEREST_TYPE); while (cursor.toNextSibling(Sos2Constants.QN_SOS_FEATURE_OF_INTEREST_TYPE)) { cursor.setName(Sos2Constants.QN_SOS_FEATURE_OF_INTEREST_TYPE); } } cursor.dispose(); } } @Override public Set<SchemaLocation> getConcreteSchemaLocations() { return Sets.newHashSet(Sos2Constants.SOS_GET_CAPABILITIES_SCHEMA_LOCATION); } private void encodeServiceIdentification(SosCapabilities caps, CapabilitiesType xbCaps) throws OwsExceptionReport { if (caps.isSetServiceIdentification()) { xbCaps.addNewServiceIdentification().set(encodeOws(caps.getServiceIdentification())); } } private void encodeServiceProvider(SosCapabilities caps, CapabilitiesType xbCaps) throws OwsExceptionReport { if (caps.isSetServiceProvider()) { xbCaps.addNewServiceProvider().set(encodeOws(caps.getServiceProvider())); } } private void encodeOperationsMetadata(SosCapabilities caps, CapabilitiesType xbCaps) throws OwsExceptionReport { if (caps.isSetOperationsMetadata() && caps.getOperationsMetadata().isSetOperations()) { xbCaps.addNewOperationsMetadata().set(encodeOws(caps.getOperationsMetadata())); } } private void encodeFilterCapabilities(SosCapabilities caps, CapabilitiesType xbCaps) throws OwsExceptionReport { if (caps.isSetFilterCapabilities()) { xbCaps.addNewFilterCapabilities().addNewFilterCapabilities().set(encodeFes(caps.getFilterCapabilities())); } } private void encodeContents(SosCapabilities caps, CapabilitiesType xbCaps, String version) throws OwsExceptionReport { if (caps.isSetContents()) { setContents(xbCaps.addNewContents(), caps.getContents(), version); } } private void encodeExtensions(SosCapabilities caps, CapabilitiesType xbCaps) throws OwsExceptionReport { if (caps.isSetExtensions()) { for (CapabilitiesExtension e : caps.getExtensions()) { setExtensions(xbCaps.addNewExtension(), e); } } } private void encodeObservationOffering(SosObservationOffering offering, int offeringCounter, ContentsType xbContType) throws OwsExceptionReport { final ObservationOfferingType xbObsOff = ObservationOfferingType.Factory.newInstance(getXmlOptions()); SosOffering sosOffering = offering.getOffering(); xbObsOff.setIdentifier(sosOffering.getIdentifier()); if (sosOffering.isSetName()) { for (CodeType name : sosOffering.getName()) { xbObsOff.addNewName().set(CodingHelper.encodeObjectToXml(GmlConstants.NS_GML_32, name)); } } if (sosOffering.isSetDescription()) { xbObsOff.setDescription(sosOffering.getDescription()); } encodeOfferingExtension(offering, xbObsOff); for (String procedure : offering.getProcedures()) { xbObsOff.setProcedure(procedure); } encodeObservableProperties(offering, xbObsOff); encodeRelatedFeatures(offering, xbObsOff); encodeObservedArea(offering, xbObsOff); encodePhenomenonTime(offering, offeringCounter, xbObsOff); encodeResultTime(offering, offeringCounter, xbObsOff); encodeResponseFormat(offering, xbObsOff); encodeObservationType(offering, xbObsOff); encodeFeatureOfInterestTypes(offering, xbObsOff); encodeProcedureDescriptionFormats(offering, xbObsOff); xbContType.addNewOffering().setAbstractOffering(xbObsOff); /* * Offering addNewOffering = xbContType.addNewOffering(); * addNewOffering.addNewAbstractOffering().set(xbObsOff); XmlHelper * .substituteElement(addNewOffering.getAbstractOffering(), xbObsOff); */ } private void encodeOfferingExtension(SosObservationOffering sosOffering, ObservationOfferingType xbObsOff) throws OwsExceptionReport { if (sosOffering.isSetExtensions()) { for (SwesExtension<?> swesExtention : sosOffering.getExtensions().getExtensions()) { if (swesExtention.getValue() instanceof OfferingExtension) { OfferingExtension extension = (OfferingExtension) swesExtention.getValue(); try { xbObsOff.addNewExtension().set(XmlObject.Factory.parse(extension.getExtension())); } catch (XmlException ex) { throw new XmlDecodingException("SwesExtension", extension.getExtension(), ex); } } else { xbObsOff.addNewExtension().set(CodingHelper.encodeObjectToXml(swesExtention.getNamespace(), swesExtention)); } } } } private void encodeObservableProperties(SosObservationOffering offering, ObservationOfferingType xbObsOff) { // TODO: pdf [0..*] // set observableProperties [0..*] for (String phenomenon : offering.getObservableProperties()) { xbObsOff.addObservableProperty(phenomenon); } } private void encodeRelatedFeatures(SosObservationOffering offering, ObservationOfferingType xbObsOff) { // set relatedFeatures [0..*] if (offering.isSetRelatedFeature()) { for (String target : offering.getRelatedFeatures().keySet()) { createRelatedFeature(xbObsOff.addNewRelatedFeature().addNewFeatureRelationship(), target, offering .getRelatedFeatures().get(target)); } } } private void encodeObservedArea(SosObservationOffering offering, ObservationOfferingType xbObsOff) throws OwsExceptionReport { // set observed area [0..1] if (offering.isSetObservedArea() && offering.getObservedArea().isSetEnvelope() && offering.getObservedArea().isSetSrid()) { XmlObject encodeObjectToXml = encodeGml(offering.getObservedArea()); xbObsOff.addNewObservedArea().addNewEnvelope().set(encodeObjectToXml); } } private void encodePhenomenonTime(SosObservationOffering offering, int offeringCounter, ObservationOfferingType xbObsOff) throws OwsExceptionReport { // set up phenomenon time [0..1] if (offering.getPhenomenonTime() instanceof TimePeriod) { TimePeriod tp = (TimePeriod) offering.getPhenomenonTime(); if (!tp.isEmpty()) { tp.setGmlId(String.format("%s_%d", Sos2Constants.EN_PHENOMENON_TIME, offeringCounter)); XmlObject xmlObject = encodeGml(tp); xbObsOff.addNewPhenomenonTime().addNewTimePeriod().set(xmlObject); xbObsOff.getPhenomenonTime().substitute(Sos2Constants.QN_SOS_PHENOMENON_TIME, xbObsOff.getPhenomenonTime().schemaType()); } } } private void encodeResultTime(SosObservationOffering offering, int offeringCounter, ObservationOfferingType xbObsOff) throws OwsExceptionReport { // set resultTime [0..1] if (offering.getResultTime() instanceof TimePeriod) { TimePeriod tp = (TimePeriod) offering.getResultTime(); tp.setGmlId(String.format("%s_%d", Sos2Constants.EN_RESULT_TIME, offeringCounter)); if (!tp.isEmpty()) { XmlObject xmlObject = encodeGml(tp); xbObsOff.addNewResultTime().addNewTimePeriod().set(xmlObject); xbObsOff.getResultTime().substitute(Sos2Constants.QN_SOS_RESULT_TIME, xbObsOff.getResultTime().schemaType()); } } } private void encodeResponseFormat(SosObservationOffering offering, ObservationOfferingType xbObsOff) { // set responseFormat [0..*] if (offering.isSetResponseFormats()) { for (String responseFormat : offering.getResponseFormats()) { xbObsOff.addResponseFormat(responseFormat); } } } private void encodeObservationType(SosObservationOffering offering, ObservationOfferingType xbObsOff) { // set observationType [0..*] if (offering.isSetObservationTypes()) { for (String obsType : offering.getObservationTypes()) { xbObsOff.addObservationType(obsType); } } } private void encodeFeatureOfInterestTypes(SosObservationOffering offering, ObservationOfferingType xbObsOff) { // set featureOfInterestType [0..1] if (offering.isSetFeatureOfInterestTypes()) { for (String foit : offering.getFeatureOfInterestTypes()) { xbObsOff.addFeatureOfInterestType(foit); } } } private void encodeProcedureDescriptionFormats(SosObservationOffering offering, ObservationOfferingType xbObsOff) { if (offering.isSetProcedureDescriptionFormats()) { for (String pdf : offering.getProcedureDescriptionFormats()) { xbObsOff.addProcedureDescriptionFormat(pdf); } } } }