/** * 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.streaming; import java.io.OutputStream; import java.util.Set; import javax.xml.stream.XMLStreamException; import org.apache.xmlbeans.XmlObject; import org.n52.sos.coding.CodingRepository; import org.n52.sos.encode.Encoder; import org.n52.sos.encode.EncoderKey; import org.n52.sos.encode.EncodingValues; import org.n52.sos.encode.OperationEncoderKey; import org.n52.sos.encode.XmlStreamWriter; import org.n52.sos.exception.ows.NoApplicableCodeException; import org.n52.sos.exception.ows.concrete.NoEncoderForKeyException; import org.n52.sos.ogc.ows.OwsExceptionReport; import org.n52.sos.response.AbstractServiceResponse; import org.n52.sos.soap.SoapConstants; import org.n52.sos.soap.SoapFault; import org.n52.sos.soap.SoapResponse; import org.n52.sos.util.CodingHelper; import org.n52.sos.util.Constants; import org.n52.sos.util.XmlOptionsHelper; import org.n52.sos.util.http.MediaTypes; import org.n52.sos.w3c.SchemaLocation; import org.n52.sos.w3c.W3CConstants; import com.google.common.collect.Sets; /** * {@link XmlStreamWriter} implementation for SOAP 1.2 * * @author Carsten Hollmann <c.hollmann@52north.org> * @since 4.1.0 * */ public class Soap12XmlStreamWriter extends XmlStreamWriter<SoapResponse> { private SoapResponse response; /** * constructor */ public Soap12XmlStreamWriter() { } /** * constructor * * @param response * Service internal SOAP response to encode */ public Soap12XmlStreamWriter(SoapResponse response) { setResponse(response); } @Override public void write(OutputStream out) throws OwsExceptionReport { write(getResponse(), out); } @Override public void write(OutputStream out, EncodingValues encodingValues) throws OwsExceptionReport { write(getResponse(), out, encodingValues); } @Override public void write(SoapResponse element, OutputStream out) throws OwsExceptionReport { write(element, out, new EncodingValues()); } @Override public void write(SoapResponse element, OutputStream out, EncodingValues encodingValues) throws OwsExceptionReport { try { init(out); start(encodingValues.isEmbedded()); writeSoapEnvelope(element); end(); finish(); } catch (XMLStreamException xmlse) { throw new NoApplicableCodeException().causedBy(xmlse); } } /** * Set the response element to encode and write to stream * * @param response * Service internal response */ public void setResponse(SoapResponse response) { this.response = response; } /** * Get the response element to encode and write to stream * * @return The response element to encode and write to stream */ protected SoapResponse getResponse() { return response; } /** * Write the SOAP 1.2. envelope element * * @param response * The response element to encode and write to stream * @throws XMLStreamException * If an error occurs when writing to {@link OutputStream} If an * error occurs when writing to {@link OutputStream} * @throws OwsExceptionReport * If an encoding error occurs */ protected void writeSoapEnvelope(SoapResponse response) throws XMLStreamException, OwsExceptionReport { start(SoapConstants.SOAP_12_ENVELOPE); namespace(W3CConstants.NS_XLINK_PREFIX, W3CConstants.NS_XLINK); namespace(SoapConstants.NS_SOAP_PREFIX, SoapConstants.NS_SOAP_12); schemaLocation(getSchemaLocation(response)); writeNewLine(); // writeSoapHeader() writeSoapBody(response); writeNewLine(); end(SoapConstants.SOAP_12_ENVELOPE); } protected Set<SchemaLocation> getSchemaLocation(SoapResponse response) throws OwsExceptionReport, XMLStreamException { Set<SchemaLocation> schemaLocations = Sets.newHashSet(); schemaLocations.add(SoapConstants.SOAP_12_SCHEMA_LOCATION); if (response.isSetBodyContent()) { Encoder<Object, AbstractServiceResponse> encoder = getEncoder(response.getBodyContent()); if (encoder != null) { schemaLocations.addAll(encoder.getSchemaLocations()); } } return schemaLocations; } /** * Write the SOAP 1.2 body element * * @param response * The response element to encode and write to stream * @throws XMLStreamException * If an error occurs when writing to {@link OutputStream} * @throws OwsExceptionReport * If an encoding error occurs */ protected void writeSoapBody(SoapResponse response) throws XMLStreamException, OwsExceptionReport { int before = indent; start(SoapConstants.SOAP_12_BODY); writeNewLine(); if (response != null) { if (response.isSetSoapFault()) { writeSoapFault(response.getSoapFault()); } else if (response.hasException()) { writeSoapFaultFromException(response.getException()); } else if (response.isSetBodyContent()) { writeBodyContent(response.getBodyContent()); } } indent = before; writeNewLine(); end(SoapConstants.SOAP_12_BODY); } /** * Encode and write the {@link AbstractServiceResponse} to stream * * @param bodyResponse * The service internal response to encode and write * @throws XMLStreamException * If an error occurs when writing to {@link OutputStream} * @throws OwsExceptionReport * If an encoding error occurs */ @SuppressWarnings({ "rawtypes", "unchecked" }) protected void writeBodyContent(AbstractServiceResponse bodyResponse) throws XMLStreamException, OwsExceptionReport { Encoder<Object, AbstractServiceResponse> encoder = getEncoder(new OperationEncoderKey(bodyResponse.getOperationKey(), MediaTypes.APPLICATION_XML)); if (encoder instanceof StreamingEncoder<?, ?>) { ((StreamingEncoder) encoder).encode(bodyResponse, getOutputStream(), new EncodingValues().setAsDocument(true).setEmbedded(true).setIndent(indent)); } else { String soapBodyContent = ((XmlObject) encoder.encode(bodyResponse)).xmlText(XmlOptionsHelper.getInstance().getXmlOptions()); if (soapBodyContent.startsWith("<?xml")) { soapBodyContent = soapBodyContent.substring(soapBodyContent.indexOf(Constants.GREATER_THAN_SIGN_STRING)); } rawText(soapBodyContent); } } /** * Encode and write SOAP 1.2 fault element to SOAP 1.2 body element * * @param fault * Service internal SOAP fault representation * @throws OwsExceptionReport * If an encoding error occurs * @throws XMLStreamException * If an error occurs when writing to {@link OutputStream} */ protected void writeSoapFault(SoapFault fault) throws OwsExceptionReport, XMLStreamException { Encoder<XmlObject, SoapFault> encoder = CodingHelper.getEncoder(SoapConstants.NS_SOAP_12, fault); String soapFault = ((XmlObject) encoder.encode(fault)).xmlText(XmlOptionsHelper.getInstance().getXmlOptions()); if (soapFault.startsWith("<?xml")) { soapFault = soapFault.substring(soapFault.indexOf(Constants.GREATER_THAN_SIGN_STRING)); } rawText(soapFault); } /** * Encode and write {@link OwsExceptionReport} element to SOAP 1.2 body * element * * @param exception * Service internal {@link OwsExceptionReport} * @throws OwsExceptionReport * If an encoding error occurs * @throws XMLStreamException * If an error occurs when writing to {@link OutputStream} */ protected void writeSoapFaultFromException(OwsExceptionReport exception) throws OwsExceptionReport, XMLStreamException { Encoder<XmlObject, OwsExceptionReport> encoder = CodingHelper.getEncoder(SoapConstants.NS_SOAP_12, exception); String soapFault = ((XmlObject) encoder.encode(exception)).xmlText(XmlOptionsHelper.getInstance().getXmlOptions()); if (soapFault.startsWith("<?xml")) { soapFault = soapFault.substring(soapFault.indexOf(Constants.GREATER_THAN_SIGN_STRING)); } rawText(soapFault); } protected Encoder<Object, AbstractServiceResponse> getEncoder(AbstractServiceResponse abstractServiceResponse) throws NoEncoderForKeyException { return getEncoder(new OperationEncoderKey(abstractServiceResponse.getOperationKey(), MediaTypes.APPLICATION_XML)); } /** * Get encoder for {@link EncoderKey} * * @param key * Encoder key to get encoder for * @return Matching encoder * @throws NoEncoderForKeyException * If no matching encoder was found */ protected Encoder<Object, AbstractServiceResponse> getEncoder(EncoderKey key) throws NoEncoderForKeyException { Encoder<Object, AbstractServiceResponse> encoder = CodingRepository.getInstance().getEncoder(key); if (encoder == null) { throw new NoEncoderForKeyException(key); } return encoder; } }