Monday, 30 July 2012

Soap Web Service with attachment Over JMS

  • dependency
  • 
        com.sun.messaging.mq
        imqxm
        4.6-b01
    
    
        javaee
        javaee-api
        5
    
    
        xalan
        xalan
        2.7.0
    
    
        com.sun.messaging.mq
        jaxm-api
        4.6-b01
                
    
  • JMS message sender (Embedded SoapMessage with Attachment)
  • import com.google.common.io.Files;
    import com.sun.messaging.xml.MessageTransformer;
    
    import javax.activation.DataHandler;
    import javax.activation.FileDataSource;
    import javax.jms.*;
    import javax.naming.Context;
    import javax.naming.InitialContext;
    import javax.xml.soap.*;
    import java.io.File;
    import java.io.IOException;
    import java.nio.charset.Charset;
    import java.util.Hashtable;
    
    public class MockWebServiceOverJMSSender {
        private static final String CONNECTION_FACTORY_JNDI_NAME = "weblogic.jms.XAConnectionFactory";
        private static final String QUEUE_JNDI_NAME = "jms/TestQueueJNDI";
    
        public static void sendMessage() {
            try {
                QueueConnection connection = null;
                QueueSession session = null;
                QueueSender queueSender = null;
                try {
                    Hashtable<String,String> properties = new Hashtable();
                    properties.put(Context.INITIAL_CONTEXT_FACTORY, "weblogic.jndi.WLInitialContextFactory");
                    properties.put(Context.PROVIDER_URL, "t3://localhost:7001");
    
                    InitialContext context = new InitialContext(properties);
                    QueueConnectionFactory connectionFactory = (QueueConnectionFactory) context.lookup(CONNECTION_FACTORY_JNDI_NAME);
                    connection = connectionFactory.createQueueConnection();
                    session = connection.createQueueSession(false, 0);
                    Queue queue = (Queue) context.lookup(QUEUE_JNDI_NAME);
                    queueSender = session.createSender(queue);
    
                    MessageFactory messageFactory = MessageFactory.newInstance();
                    SOAPMessage soapMessage = messageFactory.createMessage();
                    soapMessage.setProperty(SOAPMessage.WRITE_XML_DECLARATION, "true");
                    SOAPPart soapPart = soapMessage.getSOAPPart();
                    SOAPEnvelope envelope = soapPart.getEnvelope();
                    SOAPBody soapBody = envelope.getBody();
    
                    soapBody.setTextContent(buildSoapBodyContent());
    
                    AttachmentPart attachment = buildSoapAttachment(soapMessage);
                    soapMessage.addAttachmentPart(attachment);
    
                    soapMessage.saveChanges();
                    Message message = MessageTransformer.SOAPMessageIntoJMSMessage(soapMessage, session);
                    queueSender.send(message);
                } finally {
                    queueSender.close();
                    session.close();
                    connection.close();
                }
            } catch (Exception e) {
                e.printStackTrace();
                System.exit(0);
            }
        }
    
        private static String buildSoapBodyContent() throws IOException {
            String responseFile = "c:/temp/PoliceAVOApplicationResponse-Non-provisional.xml";
            return Files.toString(new File(responseFile), Charset.forName("UTF-8"));
        }
    
        private static AttachmentPart buildSoapAttachment(SOAPMessage soapMessage) {
            DataHandler dh = new DataHandler(new FileDataSource("c:/temp/test_avo.pdf"));
            return soapMessage.createAttachmentPart(dh);
        }
    
        public static void main(String args[]) {
            sendMessage();
        }
    
  • JMS consumer(parse message body & save attachment to disk)
  • import au.gov.nsw.police.nodi.common.IOHelper;
    import com.google.common.io.Files;
    import com.sun.messaging.xml.MessageTransformer;
    import org.w3c.dom.Document;
    import org.xml.sax.SAXException;
    
    import javax.jms.*;
    import javax.naming.Context;
    import javax.naming.InitialContext;
    import javax.xml.parsers.DocumentBuilder;
    import javax.xml.parsers.DocumentBuilderFactory;
    import javax.xml.parsers.ParserConfigurationException;
    import javax.xml.soap.*;
    import javax.xml.xpath.*;
    import java.io.ByteArrayInputStream;
    import java.io.File;
    import java.io.IOException;
    import java.io.InputStream;
    import java.util.Date;
    import java.util.Hashtable;
    import java.util.Iterator;
    
    public class MockJMSMessageConsumer {
        private static final String CONNECTION_FACTORY_JNDI_NAME = "weblogic.jms.XAConnectionFactory";
        private static final String QUEUE_JNDI_NAME = "jms/TestQueueJNDI";
    
        private static void consumeMessage() {
            try {
                QueueConnection connection = null;
                QueueSession session = null;
                QueueReceiver queueReceiver = null;
                try {
                    Hashtable<String, String> properties = new Hashtable();
                    properties.put(Context.INITIAL_CONTEXT_FACTORY, "weblogic.jndi.WLInitialContextFactory");
                    properties.put(Context.PROVIDER_URL, "t3://localhost:7001");
    
                    InitialContext context = new InitialContext(properties);
                    QueueConnectionFactory connectionFactory = (QueueConnectionFactory) context.lookup(CONNECTION_FACTORY_JNDI_NAME);
                    connection = connectionFactory.createQueueConnection();
                    session = connection.createQueueSession(false, 0);
                    Queue queue = (Queue) context.lookup(QUEUE_JNDI_NAME);
                    queueReceiver = session.createReceiver(queue);
                    connection.start();
    
                    while (true) {
                        Message message = queueReceiver.receive(1);
                        MessageFactory messageFactory = MessageFactory.newInstance();
    
                        if (message != null) {
                            SOAPMessage soapMessage = MessageTransformer.SOAPMessageFromJMSMessage(message, messageFactory);
                            onMessage(soapMessage);
                        }
                    }
                } finally {
                    queueReceiver.close();
                    session.close();
                    connection.close();
                }
            } catch (Exception e) {
                e.printStackTrace(System.err);
                System.exit(0);
            }
        }
    
        private static void onMessage(SOAPMessage soapMessage) {
            try {
                System.out.println("Start to processing message from ESB...");
                SOAPBody soapBody = soapMessage.getSOAPPart().getEnvelope().getBody();
    
                Iterator iterator = soapMessage.getAttachments();
                if (iterator.hasNext()) {
                    AttachmentPart attachmentPart = (AttachmentPart) iterator.next();
                    System.out.println("here");
                    parseMetadataFromSoapMessage(soapBody, attachmentPart);
                }
                System.out.println("Finish to processing message from ESB");
            } catch (Throwable e) {
                e.printStackTrace();
            }
        }
    
    
        private static void parseMetadataFromSoapMessage(SOAPBody soapBody, AttachmentPart attachmentPart) throws IOException, SAXException, ParserConfigurationException, XPathExpressionException, SOAPException {
            String content = soapBody.getTextContent();
            Document doc = buildDocumentFromString(content);
    
            XPath xPath = createXPath();
            String courtReferenceNumber = getStringValueWithGiveXPath(xPath, doc, "/n1:PublishDocumentMessage/@ProceedingNumber");
            String courtName = getStringValueWithGiveXPath(xPath, doc, "/n1:PublishDocumentMessage/n1:Listing/Court/@Name");
            String eventNumber = getStringValueWithGiveXPath(xPath, doc, "/n1:PublishDocumentMessage/n1:QuestionsAndAnswers/n1:DataField[@Name='IDF POLAPPEVENTNO']/@Value");
            String cni = getStringValueWithGiveXPath(xPath, doc, "/n1:PublishDocumentMessage/n1:Participant[n1:ParticipantID[@ParticipantRole='DEFENDANT']]/n1:CrimeIndividual/common:IndividualDetails/@CNI");
            System.out.println("court reference number: " + courtReferenceNumber);
            System.out.println("court name: " + courtName);
            System.out.println("event number: " + eventNumber);
            System.out.println("cni: " + cni);
    
            saveAttachmentToDisk(attachmentPart);
        }
    
        private static Document buildDocumentFromString(String content) throws ParserConfigurationException, SAXException, IOException {
            DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory.newInstance();
            docBuilderFactory.setNamespaceAware(true);
            DocumentBuilder docBuilder = docBuilderFactory.newDocumentBuilder();
            InputStream inputStream = new ByteArrayInputStream(content.getBytes());
            return docBuilder.parse(inputStream);
        }
    
        private static XPath createXPath() {
            XPathFactory xPathfactory = XPathFactory.newInstance();
            XPath xpath = xPathfactory.newXPath();
            xpath.setNamespaceContext(new AVONamespaceContext());
    
            return xpath;
        }
    
        private static String getStringValueWithGiveXPath(XPath xpath, Document document, String expression) throws XPathExpressionException {
            XPathExpression xPathExpression = xpath.compile(expression);
            return (String) xPathExpression.evaluate(document, XPathConstants.STRING);
        }
    
        private static void saveAttachmentToDisk(AttachmentPart attachmentPart) throws IOException, SOAPException {
            byte[] pdfFile= IOHelper.readInputStream(attachmentPart.getDataHandler().getInputStream());
            Date now = new Date();
            Files.write(faxImages, new File("c:/temp/" + now.getTime() + ".pdf"));
        }
    
        public static void main(String args[]) {
            consumeMessage();
        }
    
  • help class
  • import javax.xml.XMLConstants;
    import javax.xml.namespace.NamespaceContext;
    import java.util.Iterator;
    
    public class AVONamespaceContext implements NamespaceContext {
        public String getNamespaceURI(String prefix) {
            if (prefix == null) throw new NullPointerException("Invalid Namespace Prefix");
            else if (prefix.equals(XMLConstants.DEFAULT_NS_PREFIX)) {
                return "http://www.w3.org/2001/XMLSchema-instance";
            } else if ("n1".equals(prefix)) {
                return "http://cats.agd.nsw.gov.au/PublishDocumentMessage/v1_0";
            } else if ("common".equals(prefix)) {
                return "http://cats.agd.nsw.gov.au/DocumentLodgementInterfaces/Common/v1_0";
            } else if ("cim".equals(prefix)) {
                return "http://cim.justicesector.nsw.gov.au/Common/1";
            } else if ("as4590".equals(prefix)) {
                return "http://cim.justicesector.nsw.gov.au/as459";
            } else {
                return XMLConstants.NULL_NS_URI;
            }
        }
    
        public String getPrefix(String namespaceURI) {
            return null;
        }
    
        public Iterator getPrefixes(String namespaceURI) {
            return null;
        }
    }
    
  • Another Solution
  • You don't need to dependent the above dependencies. You just implement your own transformer. My sample as follow:
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    
    import javax.jms.BytesMessage;
    import javax.jms.JMSException;
    import javax.jms.Message;
    import javax.jms.Session;
    import javax.xml.messaging.JAXMException;
    import javax.xml.soap.*;
    import java.io.*;
    import java.util.Enumeration;
    import java.util.Hashtable;
    import java.util.Iterator;
    
    import static com.google.common.base.Throwables.getStackTraceAsString;
    
    /**
     * The Rcode>Transformer</code> class encapsulates the functionality
     * to transform SOAP and JMS messages.
     */
    public class MessageTransformer {
        private static final Logger log = LoggerFactory.getLogger(MessageTransformer.class);
        private MessageTransformer() {
        }
    
        /**
         * Transforms a <code>javax.xml.soap.SOAPMessage</code> message
         * into a <code>javax.jms.Message</code> message.
         *
         * @param soapMessage the SOAPMessage to be converted to the JMS Message.
         * @param session     The JMS Session to be used to construct the JMS Message.
         * @throws JAXMException If any error is encountered when transforming the message.
         */
        public static Message SOAPMessageIntoJMSMessage(SOAPMessage soapMessage, Session session) throws JAXMException {
            try {
                /**
                 * Construct a bytes message object.
                 * This is to make sure the utility works across all vendors.
                 */
                BytesMessage bytesMessage = session.createBytesMessage();
    
                /**
                 * This is here to make sure that RI's bad SOAP implementation
                 * will get updated for internal buffers.
                 */
                soapMessage.saveChanges();
    
                writeMimeHeaders(soapMessage, bytesMessage);
                writeSOAPBody(soapMessage, bytesMessage);
    
                return bytesMessage;
            } catch (JAXMException JAXMe) {
                throw JAXMe;
            } catch (Exception e) {
                log.error(getStackTraceAsString(e));
                throw new JAXMException(e);
            }
        }
    
        private static void writeMimeHeaders(SOAPMessage soapMessage, BytesMessage bytesMessage) throws Exception {
            MimeHeaders mimeHeaders = soapMessage.getMimeHeaders();
            Hashtable hashtable = convertMimeHeadersToHashtable(mimeHeaders);
    
            ByteArrayOutputStream mimeOut = writeHashtableToByteArrayOutputStream(hashtable);
    
            byte[] mimeHeadersBytes = mimeOut.toByteArray();
            int mimeHeadersLength = mimeHeadersBytes.length;
            bytesMessage.writeInt(mimeHeadersLength);
            bytesMessage.writeBytes(mimeHeadersBytes);
            mimeOut.close();
            log.debug("SOAP to JMS mime headers length: {}", mimeHeadersLength);
        }
    
        /**
         * Convert MimeHeaders to Hashtable.  The hashtable is then used to write
         * to JMS BytesMessage.
         */
        private static Hashtable convertMimeHeadersToHashtable(MimeHeaders mimeHeaders) {
            Hashtable hashtable = new Hashtable();
            Iterator it = mimeHeaders.getAllHeaders();
            while (it.hasNext()) {
                MimeHeader mimeHeader = (MimeHeader) it.next();
                hashtable.put(mimeHeader.getName(), mimeHeader.getValue());
            }
    
            return hashtable;
        }
    
        private static ByteArrayOutputStream writeHashtableToByteArrayOutputStream(Hashtable hashtable) throws IOException {
            ByteArrayOutputStream mimeOut = new ByteArrayOutputStream();
            ObjectOutputStream objectOutputStream = new ObjectOutputStream(mimeOut);
            objectOutputStream.writeObject(hashtable);
            objectOutputStream.flush();
            objectOutputStream.close();
            return mimeOut;
        }
    
        private static void writeSOAPBody(SOAPMessage soapMessage, BytesMessage bytesMessage) throws Exception {
            ByteArrayOutputStream bodyOutput = new ByteArrayOutputStream();
            soapMessage.writeTo(bodyOutput);
    
            byte[] bodyBytes = bodyOutput.toByteArray();
            int bodyLength = bodyBytes.length;
            bytesMessage.writeInt(bodyLength);
            bytesMessage.writeBytes(bodyBytes);
    
            bodyOutput.close();
            log.debug("SOAP to JMS body length: {}", bodyLength);
        }
    
    
        /**
         * Extracts a <code>javax.xml.soap.SOAPMessage</code> object from the
         * <code>javax.jms.Message</code> object into which it was transformed
         * using the <code>SOAPMessageIntoJMSMessage</code> method.
         * <p/>* The <code>MessageFactory</code> parameter is used to construct the
         * <code>javax.xml.soap.SOAPMessage</code> object.
         * <p/>* If <code>MessageFactory</code> is <code>null</code> then the
         * default SOAP MessageFactory will be used to construct the
         * SOAP message.
         *
         * @param message        The JMS message from which the SOAP message is to be extracted.
         * @param messageFactory The SOAP MessageFactory to be used to contruct the SOAP message.
         * @throws JAXMException If any error is encountered when extracting the message.
         */
        public static SOAPMessage extractSOAPMessageFromJMSMessage(Message message, MessageFactory messageFactory) throws JAXMException {
            BytesMessage bytesMessage = (BytesMessage) message;
            try {
                MimeHeaders mimeHeaders = readMimeHeaders(bytesMessage);
                ByteArrayInputStream bodyByteArrayInputStream = readSoapBodyToByteArrayInputStream(bytesMessage);
    
                return constructSoapMessage(messageFactory, mimeHeaders, bodyByteArrayInputStream);
            } catch (Exception e) {
                throw new JAXMException(e);
            }
        }
    
        private static MimeHeaders readMimeHeaders(BytesMessage bytesMessage) throws JMSException, IOException, ClassNotFoundException {
            int mimeHeadersLength = bytesMessage.readInt();
            byte[] mimeHeadersBytes = new byte[mimeHeadersLength];
            bytesMessage.readBytes(mimeHeadersBytes, mimeHeadersLength);
    
            ByteArrayInputStream mimeHeadersByteArrayInputStream = new ByteArrayInputStream(mimeHeadersBytes);
            ObjectInputStream objectInputStream = new ObjectInputStream(mimeHeadersByteArrayInputStream);
            Hashtable hashtable = (Hashtable) objectInputStream.readObject();
            return convertHashtableToMimeHeaders(hashtable);
        }
    
        private static MimeHeaders convertHashtableToMimeHeaders(Hashtable hashtable) {
            MimeHeaders mimeHeaders = new MimeHeaders();
    
            Enumeration enm = hashtable.keys();
            while (enm.hasMoreElements()) {
                Object key = enm.nextElement();
                mimeHeaders.addHeader((String) key, (String) hashtable.get(key));
                log.debug("mime-header: {} = {}", key, hashtable.get(key));
            }
    
            return mimeHeaders;
        }
    
        private static ByteArrayInputStream readSoapBodyToByteArrayInputStream(BytesMessage bytesMessage) throws JMSException {
            int bodyLength = bytesMessage.readInt();
            byte[] buf = new byte[bodyLength];
            bytesMessage.readBytes(buf, bodyLength);
    
            return new ByteArrayInputStream(buf);
        }
    
        private static SOAPMessage constructSoapMessage(MessageFactory messageFactory, MimeHeaders mimeHeaders,
                                                        ByteArrayInputStream bodyByteArrayInputStream) throws SOAPException, IOException {
            if (messageFactory == null) {
                messageFactory = getMessageFactory();
            }
    
            return messageFactory.createMessage(mimeHeaders, bodyByteArrayInputStream);
        }
    
        private static MessageFactory getMessageFactory() throws SOAPException {
            return MessageFactory.newInstance();
        }
    }
    
  • reference
  • SOAP over Java Message Service 1.0

No comments:

Post a Comment