org.openhim.mediator.normalization.XDSbMimeProcessorActor.java Source code

Java tutorial

Introduction

Here is the source code for org.openhim.mediator.normalization.XDSbMimeProcessorActor.java

Source

/*
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */

package org.openhim.mediator.normalization;

import akka.actor.ActorRef;
import akka.actor.UntypedActor;
import org.apache.commons.io.IOUtils;
import org.apache.commons.io.output.ByteArrayOutputStream;
import org.openhim.mediator.engine.messages.ExceptError;
import org.openhim.mediator.engine.messages.MediatorRequestMessage;
import org.openhim.mediator.engine.messages.SimpleMediatorRequest;
import org.openhim.mediator.engine.messages.SimpleMediatorResponse;

import javax.mail.BodyPart;
import javax.mail.Header;
import javax.mail.MessagingException;
import javax.mail.internet.InternetHeaders;
import javax.mail.internet.MimeMultipart;
import javax.mail.util.ByteArrayDataSource;
import java.io.IOException;
import java.io.InputStream;
import java.util.*;

/**
 * A MIME container for processing MTOM/XOP requests.
 * <br/><br/>
 * The actor just parses out the SOAP message, but keeps the request in state
 * so that the complete MTOM request can be sent again with the enriched message.
 * <br/><br/>
 * Messages supported:
 * <ul>
 *     <li>MimeMessage: Parses the string as an MTOM/XOP request and responds with the SOAP part and a map referencing the other documents (XDSbMimeProcessorResponse)</li>
 *     <li>EnrichedMessage: Returns the original MTOM/XOP request but with the provided enriched SOAP part (XDSbMimeProcessorResponse)</li>
 * </ul>
 */
public class XDSbMimeProcessorActor extends UntypedActor {

    public static class MimeMessage extends SimpleMediatorRequest<String> {
        final String contentType;

        public MimeMessage(ActorRef requestHandler, ActorRef respondTo, String requestObject, String contentType) {
            super(requestHandler, respondTo, requestObject);
            this.contentType = contentType;
        }
    }

    public static class EnrichedMessage extends SimpleMediatorRequest<String> {
        public EnrichedMessage(ActorRef requestHandler, ActorRef respondTo, String requestObject) {
            super(requestHandler, respondTo, requestObject);
        }
    }

    public static class XDSbMimeProcessorResponse extends SimpleMediatorResponse<String> {
        final List<String> documents;

        public XDSbMimeProcessorResponse(MediatorRequestMessage originalRequest, String requestObject,
                List<String> documents) {
            super(originalRequest, requestObject);
            this.documents = documents;
        }

        public List<String> getDocuments() {
            return documents;
        }
    }

    public static class NoPreviousMimeMessage extends Exception {
        public NoPreviousMimeMessage() {
            super("No previous MimeMessage received");
        }
    }

    public static class SOAPPartNotFound extends Exception {
        public SOAPPartNotFound() {
            super("SOAP part wasn't found in mime multipart message");
        }
    }

    public static class UnprocessableContentFound extends Exception {
        public UnprocessableContentFound() {
            super(String.format("Unprocessable content found in SOAP part"));
        }
    }

    MimeMultipart mimeMessage;

    private String _soapPart;
    private List<String> _documents = new ArrayList<>(1);

    private void parseMimeMessage(String msg, String contentType)
            throws IOException, MessagingException, SOAPPartNotFound, UnprocessableContentFound {
        mimeMessage = new MimeMultipart(new ByteArrayDataSource(msg, contentType));
        for (int i = 0; i < mimeMessage.getCount(); i++) {
            BodyPart part = mimeMessage.getBodyPart(i);

            if (part.getContentType().contains("application/soap+xml")) {
                _soapPart = getValue(part);
            } else {
                _documents.add(getValue(part));
            }
        }

        if (_soapPart == null) {
            throw new SOAPPartNotFound();
        }
    }

    private String getValue(BodyPart part) throws IOException, MessagingException, UnprocessableContentFound {
        Object value = part.getContent();
        if (value instanceof String) {
            return (String) value;
        } else if (value instanceof InputStream) {
            return IOUtils.toString((InputStream) value);
        }
        throw new UnprocessableContentFound();
    }

    private String buildEnrichedMimeMessage(String enrichedSOAPMessage) throws MessagingException, IOException {
        for (int i = 0; i < mimeMessage.getCount(); i++) {
            BodyPart part = mimeMessage.getBodyPart(i);
            if (part.getContentType().contains("application/soap+xml")) {
                Enumeration copyOfHeaders = createCopyOfHeaders(part);
                part.setContent(enrichedSOAPMessage, part.getContentType());
                copyHeadersToPart(copyOfHeaders, part);
                break;
            }
        }

        ByteArrayOutputStream out = new ByteArrayOutputStream();
        mimeMessage.writeTo(out);
        mimeMessage = null;
        return out.toString();
    }

    private Enumeration createCopyOfHeaders(BodyPart part) throws MessagingException {
        Enumeration headers = part.getAllHeaders();
        InternetHeaders internetHeaders = new InternetHeaders();
        while (headers.hasMoreElements()) {
            Header header = (Header) headers.nextElement();
            internetHeaders.addHeader(header.getName(), header.getValue());
        }
        return internetHeaders.getAllHeaders();
    }

    private void copyHeadersToPart(Enumeration headers, BodyPart part) throws MessagingException {
        while (headers.hasMoreElements()) {
            Header header = (Header) headers.nextElement();
            part.setHeader(header.getName(), header.getValue());
        }
    }

    @Override
    public void onReceive(Object msg) throws Exception {
        if (msg instanceof MimeMessage) {
            try {
                parseMimeMessage(((MimeMessage) msg).getRequestObject(), ((MimeMessage) msg).contentType);
                ((MimeMessage) msg).getRespondTo().tell(
                        new XDSbMimeProcessorResponse((MediatorRequestMessage) msg, _soapPart, _documents),
                        getSelf());
            } catch (IOException | MessagingException | SOAPPartNotFound | UnprocessableContentFound ex) {
                ((MimeMessage) msg).getRequestHandler().tell(new ExceptError(ex), getSelf());
            }
        } else if (msg instanceof EnrichedMessage) {
            if (mimeMessage == null) {
                ((EnrichedMessage) msg).getRequestHandler().tell(new ExceptError(new NoPreviousMimeMessage()),
                        getSelf());
            } else {
                try {
                    String mime = buildEnrichedMimeMessage(((EnrichedMessage) msg).getRequestObject());
                    ((EnrichedMessage) msg).getRespondTo().tell(
                            new XDSbMimeProcessorResponse((MediatorRequestMessage) msg, mime, _documents),
                            getSelf());
                } catch (MessagingException | IOException ex) {
                    ((EnrichedMessage) msg).getRequestHandler().tell(new ExceptError(ex), getSelf());
                }
            }
        } else {
            unhandled(msg);
        }
    }
}