diff options
Diffstat (limited to 'src/main')
7 files changed, 237 insertions, 60 deletions
| diff --git a/src/main/java/at/gv/egiz/moazs/msg/MsgClient.java b/src/main/java/at/gv/egiz/moazs/msg/MsgClient.java index 6f0b1d9..fd36a92 100644 --- a/src/main/java/at/gv/egiz/moazs/msg/MsgClient.java +++ b/src/main/java/at/gv/egiz/moazs/msg/MsgClient.java @@ -6,6 +6,8 @@ import at.gv.zustellung.msg.xsd.DeliveryRequestStatusType;  import at.gv.zustellung.msg.xsd.DeliveryRequestType;  import org.apache.cxf.jaxws.JaxWsClientFactoryBean;  import org.apache.cxf.jaxws.JaxWsProxyFactoryBean; +import org.apache.cxf.message.Message; +import org.apache.cxf.phase.PhaseInterceptor;  import org.slf4j.Logger;  import org.slf4j.LoggerFactory; @@ -15,53 +17,34 @@ public class MsgClient {      private final DeliveryRequestType msgRequest;      private final ConfigType config; +    private final PhaseInterceptor<? extends Message> interceptor; -    MsgClient(DeliveryRequestType msgRequest, ConfigType config) { +    MsgClient(DeliveryRequestType msgRequest, ConfigType config, PhaseInterceptor<? extends Message> interceptor) {          this.msgRequest = msgRequest;          this.config = config; +        this.interceptor = interceptor;      } +    /** +     * Send {@code msgRequest} to {@code Config/Server/ZUSEUrlID} and run {@code interceptor} on response. +     * @return +     */      public DeliveryRequestStatusType send() { -          var proxy = connect(config); -          return proxy.delivery(msgRequest); -      }      private App2ZusePort connect(ConfigType config) { -        new JaxWsClientFactoryBean(); -          var address = config.getServer().getZUSEUrlID(); -        var factory = new JaxWsProxyFactoryBean(); + +        var factory = new JaxWsClientFactoryBean();          factory.setServiceClass(App2ZusePort.class);          factory.setAddress(address); +        factory.getInInterceptors().add(interceptor); -        var proxy = factory.create(); - -//        var client = ClientProxy.getClient(proxy); -//        var conduit = (HTTPConduit) client.getConduit(); -// -//        if (addressIsHttps(address)) { -//            var tlsParams = new TLSClientParameters(); -//            tlsParams.setSSLSocketFactory(createSSLContext().getSocketFactory()); -//            conduit.setTlsClientParameters(tlsParams); -//        } +        var proxy = new JaxWsProxyFactoryBean(factory).create();          return (App2ZusePort) proxy;      } - -//    private SSLContext createSSLContext() { -//        java.util.Properties props = new Properties(); -//        props.entrySet(); -// -//        // return SSLUtils.getPropertiesSSLContext(this.props, this.configDir, this.propsPrefix, forceTrustAllManager); -//        return null; -//    } - -    private boolean addressIsHttps(String address) { -        return address.startsWith("https://"); -    } -  } diff --git a/src/main/java/at/gv/egiz/moazs/msg/MsgClientFactory.java b/src/main/java/at/gv/egiz/moazs/msg/MsgClientFactory.java index 9884bd5..82468bc 100644 --- a/src/main/java/at/gv/egiz/moazs/msg/MsgClientFactory.java +++ b/src/main/java/at/gv/egiz/moazs/msg/MsgClientFactory.java @@ -2,13 +2,21 @@ package at.gv.egiz.moazs.msg;  import at.gv.zustellung.app2mzs.xsd.ConfigType;  import at.gv.zustellung.msg.xsd.DeliveryRequestType; +import org.springframework.beans.factory.annotation.Autowired;  import org.springframework.stereotype.Component;  @Component  public class MsgClientFactory { +    private final StoreSOAPBodyBinaryInRepositoryInterceptor storeResponseInterceptor; + +    @Autowired +    public MsgClientFactory(StoreSOAPBodyBinaryInRepositoryInterceptor storeResponseInterceptor) { +        this.storeResponseInterceptor = storeResponseInterceptor; +    } +      public MsgClient create(DeliveryRequestType msgRequest, ConfigType config) { -        return new MsgClient(msgRequest, config); +        return new MsgClient(msgRequest, config, storeResponseInterceptor);      }  } diff --git a/src/main/java/at/gv/egiz/moazs/msg/StoreSOAPBodyBinaryInRepositoryInterceptor.java b/src/main/java/at/gv/egiz/moazs/msg/StoreSOAPBodyBinaryInRepositoryInterceptor.java new file mode 100644 index 0000000..4e023ac --- /dev/null +++ b/src/main/java/at/gv/egiz/moazs/msg/StoreSOAPBodyBinaryInRepositoryInterceptor.java @@ -0,0 +1,55 @@ +package at.gv.egiz.moazs.msg; + +import at.gv.egiz.moazs.MoaZSException; +import at.gv.egiz.moazs.repository.DeliveryRepository; +import at.gv.egiz.moazs.scheme.SOAPUtils; +import at.gv.egiz.moazs.util.CXFMessageUtils; +import org.apache.cxf.message.Message; +import org.apache.cxf.phase.AbstractPhaseInterceptor; +import org.apache.cxf.phase.Phase; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import org.w3c.dom.Element; +import org.xml.sax.SAXException; + +import javax.xml.parsers.ParserConfigurationException; +import java.io.IOException; + +@Component +public class StoreSOAPBodyBinaryInRepositoryInterceptor extends AbstractPhaseInterceptor<Message> { + +    private static final Logger log = LoggerFactory.getLogger(StoreSOAPBodyBinaryInRepositoryInterceptor.class); + +    private final CXFMessageUtils messageUtils; +    private final SOAPUtils soapUtils; +    private final DeliveryRepository repository; + +    @Autowired +    public StoreSOAPBodyBinaryInRepositoryInterceptor(CXFMessageUtils extractor, SOAPUtils soapUtils, +                                                      DeliveryRepository repository) { +        super(Phase.RECEIVE); +        this.messageUtils = extractor; +        this.soapUtils = soapUtils; +        this.repository = repository; +    } + +    public void handleMessage(Message message) { + +        try { +            byte[] content = messageUtils.copyContent(message); + +            if(content.length > 0) { +                Element document = soapUtils.toDOM(content); +                byte[] status = soapUtils.unwrapSoapEnvelope(document); +                String appDeliveryId = soapUtils.getAppDeliveryIDFrom(document); +                repository.addSignedDeliveryRequestStatus(status, appDeliveryId); +                log.info("Store binary DeliveryRequestStatus with AppDeliveryId={}", appDeliveryId); +            } +        } catch (ParserConfigurationException | SAXException | IOException | NullPointerException e) { +            throw new MoaZSException("Could not extract signed data from message.", e); +        } +    } + +} diff --git a/src/main/java/at/gv/egiz/moazs/scheme/MoaZSPrefixMapper.java b/src/main/java/at/gv/egiz/moazs/scheme/MoaZSPrefixMapper.java index faee8a5..d725ce6 100644 --- a/src/main/java/at/gv/egiz/moazs/scheme/MoaZSPrefixMapper.java +++ b/src/main/java/at/gv/egiz/moazs/scheme/MoaZSPrefixMapper.java @@ -12,43 +12,21 @@ public class MoaZSPrefixMapper extends NamespacePrefixMapper {      private final Map<String, String> map = new HashMap<>();      public MoaZSPrefixMapper() { -        map.put(getMsgNamespaceUri(),  "msg"); -        map.put(getMsgPNamespaceUri(), "msgp"); -        map.put(getMzsNamespaceUri(),  "mzs"); -        map.put(getMzsPNamespaceUri(), "mzsp"); -        map.put(getDsigNamespaceUri(), "dsig"); +        map.put(NameSpace.MSG,  "msg"); +        map.put(NameSpace.MSGP, "msgp"); +        map.put(NameSpace.MZS,  "mzs"); +        map.put(NameSpace.MZSP, "mzsp"); +        map.put(NameSpace.DSIG, "dsig");      }      public MoaZSPrefixMapper(boolean isMzs) {          this(); -        map.put((isMzs) ? getMzsPNamespaceUri() : getMsgPNamespaceUri(), "p"); -        map.put((isMzs) ? getMzsNamespaceUri()  : getMsgNamespaceUri(),  ""); +        map.put((isMzs) ? NameSpace.MZSP : NameSpace.MSGP, "p"); +        map.put((isMzs) ? NameSpace.MZS  : NameSpace.MSG , "");      }      @Override      public String getPreferredPrefix(String namespaceUri, String suggestion, boolean requirePrefix) {          return map.getOrDefault(namespaceUri, suggestion);      } - -    private String getMsgNamespaceUri() { -        return new at.gv.zustellung.msg.xsd.ObjectFactory().createDeliveryRequest(null).getName().getNamespaceURI(); -    } - -    private String getMsgPNamespaceUri() { -        return new at.gv.zustellung.msg.xsd.persondata.ObjectFactory().createPerson(null).getName().getNamespaceURI(); -    } - -    private String getMzsNamespaceUri() { -        return new at.gv.zustellung.app2mzs.xsd.ObjectFactory().createDeliveryRequest(null).getName().getNamespaceURI(); -    } - -    private String getMzsPNamespaceUri() { -        return new at.gv.zustellung.app2mzs.xsd.persondata.ObjectFactory().createAbstractPersonData(null).getName().getNamespaceURI(); -    } - -    private String getDsigNamespaceUri() { -        return new  org.w3._2000._09.xmldsig_.ObjectFactory().createCanonicalizationMethod(null).getName().getNamespaceURI(); -    } - -  } diff --git a/src/main/java/at/gv/egiz/moazs/scheme/NameSpace.java b/src/main/java/at/gv/egiz/moazs/scheme/NameSpace.java new file mode 100644 index 0000000..63276cb --- /dev/null +++ b/src/main/java/at/gv/egiz/moazs/scheme/NameSpace.java @@ -0,0 +1,17 @@ +package at.gv.egiz.moazs.scheme; + +public class NameSpace { + +    private NameSpace() {} + +    public static final String MSG = new at.gv.zustellung.msg.xsd.ObjectFactory().createDeliveryRequest(null).getName().getNamespaceURI(); + +    public static final String MSGP = new at.gv.zustellung.msg.xsd.persondata.ObjectFactory().createPerson(null).getName().getNamespaceURI(); + +    public static final String MZS = new at.gv.zustellung.app2mzs.xsd.ObjectFactory().createDeliveryRequest(null).getName().getNamespaceURI(); + +    public static final String MZSP = new at.gv.zustellung.app2mzs.xsd.persondata.ObjectFactory().createAbstractPersonData(null).getName().getNamespaceURI(); + +    public static final String DSIG = new org.w3._2000._09.xmldsig_.ObjectFactory().createCanonicalizationMethod(null).getName().getNamespaceURI(); + +} diff --git a/src/main/java/at/gv/egiz/moazs/scheme/SOAPUtils.java b/src/main/java/at/gv/egiz/moazs/scheme/SOAPUtils.java new file mode 100644 index 0000000..2d4df4b --- /dev/null +++ b/src/main/java/at/gv/egiz/moazs/scheme/SOAPUtils.java @@ -0,0 +1,44 @@ +package at.gv.egiz.moazs.scheme; + +import at.gv.egiz.moazs.MoaZSException; +import at.gv.util.DOMUtils; +import org.apache.cxf.binding.soap.Soap11; +import org.springframework.stereotype.Component; +import org.w3c.dom.Element; +import org.xml.sax.SAXException; + +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.transform.TransformerException; +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.nio.charset.StandardCharsets; + +@Component +public class SOAPUtils { + +    public Element toDOM(byte[] bytes) throws IOException, SAXException, ParserConfigurationException { +        var stream = new ByteArrayInputStream(bytes); +        return DOMUtils.parseXmlNonValidating(stream); +    } + +    public byte[] unwrapSoapEnvelope(Element document)  { +        try { +            var body = document.getElementsByTagNameNS(Soap11.SOAP_NAMESPACE, "Body"); +            var item = body.item(0).getFirstChild(); + +            return DOMUtils.serializeNode(item, true) +                    .getBytes(StandardCharsets.UTF_8); + +        } catch (IOException | TransformerException e) { +            throw new MoaZSException("Error while parsing message. ", e); +        } +    } + +    public String getAppDeliveryIDFrom(Element document) { +        var elements = document.getElementsByTagNameNS(NameSpace.MSG, "AppDeliveryID"); + +        var appDeliveryIdElement = elements.item(0).getFirstChild(); + +        return appDeliveryIdElement.getNodeValue(); +    } +} diff --git a/src/main/java/at/gv/egiz/moazs/util/CXFMessageUtils.java b/src/main/java/at/gv/egiz/moazs/util/CXFMessageUtils.java new file mode 100644 index 0000000..07fdfb6 --- /dev/null +++ b/src/main/java/at/gv/egiz/moazs/util/CXFMessageUtils.java @@ -0,0 +1,92 @@ +package at.gv.egiz.moazs.util; + +import org.apache.cxf.helpers.IOUtils; +import org.apache.cxf.io.CachedOutputStream; +import org.apache.cxf.io.CachedWriter; +import org.apache.cxf.io.DelegatingInputStream; +import org.apache.cxf.message.Message; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Component; + +import java.io.IOException; +import java.io.InputStream; +import java.io.Reader; +import java.io.SequenceInputStream; + +@Component +public class CXFMessageUtils { + +    private static final Logger LOG = LoggerFactory.getLogger(CXFMessageUtils.class); + +    /** +     * Copy and return content of org.apache.cxf.message.Message; Restore InputStream / Reader from +     * message.getContent() after consuming it. +     * @param message +     * @return +     * @throws IOException +     */ +    public byte[] copyContent(Message message) throws IOException { + +        if (message.getContent(InputStream.class) != null) { +            return streamMessageContentToByteArray(message); +        } else if (message.getContent(Reader.class) != null) { +            return readMessageContentToByteArray(message); +        } else { +            LOG.warn("Message Content is neither Reader nor InputStream; will return empty content."); +            return new byte[0]; +        } +    } + +    /** +     * Source: Adapted from ApacheCXF 3.3.0 / LoggingInInterceptor.logInputStream() +     * @param message +     * @return copy of message content +     * @throws IOException +     */ +    private byte[] streamMessageContentToByteArray(Message message) throws IOException { + +        var in = message.getContent(InputStream.class); + +        try (var out = new CachedOutputStream()) { + +            // use the appropriate input stream and restore it later +            InputStream bis = in instanceof DelegatingInputStream +                    ? ((DelegatingInputStream)in).getInputStream() : in; + +            //only copy up to the limit since that's all we need to log +            //we can stream the rest +            IOUtils.copy(bis, out); +            out.flush(); +            bis = new SequenceInputStream(out.getInputStream(), bis); + +            // restore the delegating input stream or the input stream +            if (in instanceof DelegatingInputStream) { +                ((DelegatingInputStream)in).setInputStream(bis); +            } else { +                message.setContent(InputStream.class, bis); +            } + +            return out.getBytes(); +        } + +    } + +    /** +     * Source: Adapted from ApacheCXF 3.3.0 / LoggingInInterceptor.logReader() +     * @param message +     * @return copy of message content +     * @throws IOException +     */ +    private byte[] readMessageContentToByteArray(Message message) throws IOException { +        var reader = message.getContent(Reader.class); +        var writer = new CachedWriter(); +        IOUtils.copyAndCloseInput(reader, writer); +        message.setContent(Reader.class, writer.getReader()); + +        var buffer = new StringBuilder(); +        writer.writeCacheTo(buffer); +        return buffer.toString().getBytes(); +    } + +} | 
