hermes.impl.DefaultXMLHelper.java Source code

Java tutorial

Introduction

Here is the source code for hermes.impl.DefaultXMLHelper.java

Source

/* 
 * Copyright 2003,2004 Colin Crist
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * 
 */

package hermes.impl;

import hermes.Domain;
import hermes.HermesException;
import hermes.MessageFactory;
import hermes.SystemProperties;
import hermes.browser.HermesBrowser;
import hermes.util.JMSUtils;
import hermes.xml.Entry;
import hermes.xml.MessageSet;
import hermes.xml.ObjectFactory;
import hermes.xml.Property;
import hermes.xml.XMLBytesMessage;
import hermes.xml.XMLMapMessage;
import hermes.xml.XMLMessage;
import hermes.xml.XMLObjectMessage;
import hermes.xml.XMLTextMessage;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.io.Reader;
import java.io.Serializable;
import java.io.StringReader;
import java.io.StringWriter;
import java.io.Writer;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Iterator;

import javax.jms.BytesMessage;
import javax.jms.JMSException;
import javax.jms.MapMessage;
import javax.jms.Message;
import javax.jms.MessageEOFException;
import javax.jms.ObjectMessage;
import javax.jms.TextMessage;
import javax.naming.NamingException;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import javax.xml.namespace.QName;
import javax.xml.transform.stream.StreamSource;

import org.apache.commons.codec.DecoderException;
import org.apache.commons.codec.EncoderException;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang.StringEscapeUtils;
import org.apache.log4j.Logger;
import org.apache.tools.ant.util.ReaderInputStream;

/**
 * Generic XML helper methods that are non-JMS specific. The serialisation is
 * very sub-optimal but okay for dealing withe a few thousands of messages per
 * file.
 * 
 * @author colincrist@hermesjms.com
 * @version $Id: DefaultXMLHelper.java,v 1.23 2006/01/14 12:59:12 colincrist Exp
 *          $
 */

public class DefaultXMLHelper implements XMLHelper {
    private static final Logger log = Logger.getLogger(DefaultXMLHelper.class);
    private static final int XML_TEXT_MESSAGE = 1;
    private static final int XML_BYTES_MESSGAE = 2;
    private static final int XML_OBJECT_MESSAGE = 3;
    private static final int XML_MAP_MESSAGE = 4;
    private static final String BASE64_CODEC = "Base64";
    private final ThreadLocal<Base64> base64EncoderTL = new ThreadLocal<Base64>() {
        @Override
        protected Base64 initialValue() {
            return new Base64();
        }
    };

    private final ThreadLocal<JAXBContext> contextTL = new ThreadLocal<JAXBContext>() {
        @Override
        protected JAXBContext initialValue() {
            try {
                return JAXBContext.newInstance("hermes.xml");
            } catch (JAXBException e) {
                log.error(e.getMessage(), e);
                return null;
            }
        }
    };

    public DefaultXMLHelper() {

    }

    private final ObjectFactory factory = new ObjectFactory();

    public boolean isBase64EncodeTextMessages() {
        if (HermesBrowser.getBrowser() != null) {
            try {
                return HermesBrowser.getBrowser().getConfig().isBase64EncodeMessages();
            } catch (HermesException ex) {
                log.error(ex.getMessage(), ex);
                return false;
            }
        } else {
            return Boolean.parseBoolean(System.getProperty(SystemProperties.BASE64_ENCODE_TEXT_MESSAGE, "false"));
        }
    }

    public ObjectFactory getFactory() {
        return factory;
    }

    public MessageSet readContent(InputStream istream) throws Exception {
        JAXBContext jc = contextTL.get();
        Unmarshaller u = jc.createUnmarshaller();
        JAXBElement<MessageSet> node = u.unmarshal(new StreamSource(istream), MessageSet.class);

        return node.getValue();
    }

    public MessageSet readContent(Reader reader) throws Exception {
        JAXBContext jc = contextTL.get();
        Unmarshaller u = jc.createUnmarshaller();
        JAXBElement<MessageSet> node = u.unmarshal(new StreamSource(new ReaderInputStream(reader)),
                MessageSet.class);

        return node.getValue();
    }

    public void saveContent(MessageSet messages, OutputStream ostream) throws Exception {
        JAXBContext jc = JAXBContext.newInstance("hermes.xml");
        Marshaller m = jc.createMarshaller();

        m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
        m.marshal(new JAXBElement<MessageSet>(new QName("", "content"), MessageSet.class, messages), ostream);
        ostream.flush();
    }

    public void saveContent(MessageSet messages, Writer writer) throws Exception {
        JAXBContext jc = JAXBContext.newInstance("hermes.xml");
        Marshaller m = jc.createMarshaller();

        m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
        m.marshal(new JAXBElement<MessageSet>(new QName("", "content"), MessageSet.class, messages), writer);
        writer.flush();
    }

    @Override
    public void toXML(Message message, OutputStream ostream) throws JMSException, IOException {
        final Collection<Message> c = new HashSet<Message>();
        c.add(message);

        toXML(c, ostream);
    }

    @Override
    public String toXML(Message message) throws JMSException {
        final Collection<Message> c = new HashSet<Message>();
        c.add(message);

        return toXML(c);
    }

    @Override
    public Collection fromXML(MessageFactory hermes, InputStream istream) throws JMSException {
        try {
            return fromMessageSet(hermes, readContent(istream));
        } catch (Exception ex) {
            log.error(ex.getMessage(), ex);

            throw new HermesException(ex);
        }
    }

    @Override
    public Collection fromXML(MessageFactory hermes, String document) throws JMSException {
        try {
            return fromMessageSet(hermes, readContent(new StringReader(document)));
        } catch (Exception ex) {
            log.error(ex.getMessage(), ex);

            throw new HermesException(ex);
        }
    }

    @Override
    public void toXML(Collection messages, OutputStream ostream) throws JMSException, IOException {
        try {
            MessageSet messageSet = toMessageSet(messages);
            saveContent(messageSet, ostream);
        } catch (Exception ex) {
            log.error(ex.getMessage(), ex);

            throw new HermesException(ex);
        }
    }

    @Override
    public String toXML(Collection messages) throws JMSException {
        try {

            StringWriter writer = new StringWriter();
            MessageSet messageSet = toMessageSet(messages);

            saveContent(messageSet, writer);

            return writer.getBuffer().toString();
        } catch (Exception ex) {
            log.error(ex.getMessage(), ex);

            throw new HermesException(ex);
        }
    }

    public Collection fromMessageSet(MessageFactory hermes, MessageSet messageSet)
            throws JMSException, IOException, ClassNotFoundException, DecoderException {
        Collection rval = new ArrayList();

        for (Iterator iter = messageSet.getEntry().iterator(); iter.hasNext();) {
            Entry entry = (Entry) iter.next();
            Message jmsMessage = null;

            switch (entry.getType()) {
            case XML_TEXT_MESSAGE:
                jmsMessage = createMessage(hermes, entry.getTextMessage());
                break;

            case XML_MAP_MESSAGE:
                jmsMessage = createMessage(hermes, entry.getMapMessage());
                break;

            case XML_BYTES_MESSGAE:
                jmsMessage = createMessage(hermes, entry.getBytesMessage());
                break;
            case XML_OBJECT_MESSAGE:
                jmsMessage = createMessage(hermes, entry.getObjectMessage());
                break;

            }

            if (jmsMessage != null) {
                rval.add(jmsMessage);
            }
        }

        return rval;
    }

    public MessageSet toMessageSet(Collection messages) throws JMSException {
        try {
            MessageSet messageSet = factory.createMessageSet();

            for (Iterator iter = messages.iterator(); iter.hasNext();) {
                Message jmsMessage = (Message) iter.next();
                Entry entry = factory.createEntry();
                XMLMessage xmlMessage = createXMLMessage(factory, jmsMessage);

                if (xmlMessage instanceof XMLTextMessage) {
                    entry.setType(XML_TEXT_MESSAGE);
                    entry.setTextMessage((XMLTextMessage) xmlMessage);

                } else if (xmlMessage instanceof XMLMapMessage) {
                    entry.setType(XML_MAP_MESSAGE);
                    entry.setMapMessage((XMLMapMessage) xmlMessage);

                } else if (xmlMessage instanceof XMLObjectMessage) {
                    entry.setType(XML_OBJECT_MESSAGE);
                    entry.setObjectMessage((XMLObjectMessage) xmlMessage);
                } else if (xmlMessage instanceof XMLBytesMessage) {
                    entry.setType(XML_BYTES_MESSGAE);
                    entry.setBytesMessage((XMLBytesMessage) xmlMessage);

                }

                messageSet.getEntry().add(entry);
            }

            return messageSet;
        } catch (Exception ex) {
            log.error(ex.getMessage(), ex);
            throw new HermesException(ex);
        }
    }

    public Message createMessage(MessageFactory hermes, XMLMessage message)
            throws JMSException, IOException, ClassNotFoundException, DecoderException {
        try {
            Message rval = hermes.createMessage();

            if (message instanceof XMLTextMessage) {
                rval = hermes.createTextMessage();

                XMLTextMessage textMessage = (XMLTextMessage) message;
                TextMessage textRval = (TextMessage) rval;

                if (BASE64_CODEC.equals(textMessage.getCodec())) {
                    byte[] bytes = base64EncoderTL.get().decode(textMessage.getText().getBytes());
                    textRval.setText(new String(bytes, "ASCII"));
                } else {
                    textRval.setText(textMessage.getText());
                }
            } else if (message instanceof XMLMapMessage) {
                rval = hermes.createMapMessage();

                XMLMapMessage mapMessage = (XMLMapMessage) message;
                MapMessage mapRval = (MapMessage) rval;

                for (Iterator iter = mapMessage.getBodyProperty().iterator(); iter.hasNext();) {
                    final Property property = (Property) iter.next();

                    if (property.getValue() == null) {
                        mapRval.setObject(property.getName(), null);
                    } else if (property.getType().equals(String.class.getName())) {
                        mapRval.setString(property.getName(), property.getValue());
                    } else if (property.getType().equals(Long.class.getName())) {
                        mapRval.setLong(property.getName(), Long.parseLong(property.getValue()));
                    } else if (property.getType().equals(Double.class.getName())) {
                        mapRval.setDouble(property.getName(), Double.parseDouble(property.getValue()));
                    } else if (property.getType().equals(Boolean.class.getName())) {
                        mapRval.setBoolean(property.getName(), Boolean.getBoolean(property.getValue()));
                    } else if (property.getType().equals(Character.class.getName())) {
                        mapRval.setChar(property.getName(), property.getValue().charAt(0));
                    } else if (property.getType().equals(Short.class.getName())) {
                        mapRval.setShort(property.getName(), Short.parseShort(property.getValue()));
                    } else if (property.getType().equals(Integer.class.getName())) {
                        mapRval.setInt(property.getName(), Integer.parseInt(property.getValue()));
                    }
                }
            } else if (message instanceof XMLBytesMessage) {
                rval = hermes.createBytesMessage();

                XMLBytesMessage bytesMessage = (XMLBytesMessage) message;
                BytesMessage bytesRval = (BytesMessage) rval;

                bytesRval.writeBytes(base64EncoderTL.get().decode(bytesMessage.getBytes().getBytes()));
            } else if (message instanceof XMLObjectMessage) {
                rval = hermes.createObjectMessage();

                XMLObjectMessage objectMessage = (XMLObjectMessage) message;
                ObjectMessage objectRval = (ObjectMessage) rval;
                ByteArrayInputStream bistream = new ByteArrayInputStream(
                        base64EncoderTL.get().decode(objectMessage.getObject().getBytes()));

                ObjectInputStream oistream = new ObjectInputStream(bistream);

                objectRval.setObject((Serializable) oistream.readObject());
            }

            //
            // JMS Header properties

            try {
                rval.setJMSDeliveryMode(message.getJMSDeliveryMode());
            } catch (JMSException ex) {
                log.error("unable to set JMSDeliveryMode to " + message.getJMSDeliveryMode() + ": "
                        + ex.getMessage());
            }

            try {
                rval.setJMSMessageID(message.getJMSMessageID());
            } catch (JMSException ex) {
                log.error("unable to set JMSMessageID: " + ex.getMessage(), ex);
            }

            try {
                if (message.getJMSExpiration() != null) {
                    rval.setJMSExpiration(message.getJMSExpiration());
                }
            } catch (JMSException ex) {
                log.error("unable to set JMSExpiration: " + ex.getMessage(), ex);
            }

            try {
                if (message.getJMSPriority() != null) {
                    rval.setJMSPriority(message.getJMSPriority());
                }
            } catch (JMSException ex) {
                log.error("unable to set JMSPriority: " + ex.getMessage(), ex);
            }

            try {
                if (message.getJMSTimestamp() != null) {
                    rval.setJMSTimestamp(message.getJMSTimestamp());
                }
            } catch (JMSException ex) {
                log.error("unable to set JMSTimestamp:" + ex.getMessage(), ex);
            }

            if (message.getJMSCorrelationID() != null) {
                rval.setJMSCorrelationID(message.getJMSCorrelationID());
            }

            if (message.getJMSReplyTo() != null && !message.getJMSReplyTo().equals("null")) {
                rval.setJMSReplyTo(hermes.getDestination(message.getJMSReplyTo(),
                        Domain.getDomain(message.getJMSReplyToDomain())));
            }

            if (message.getJMSType() != null) {
                rval.setJMSType(message.getJMSType());
            }

            if (message.getJMSDestination() != null) {
                if (message.isFromQueue()) {
                    rval.setJMSDestination(hermes.getDestination(message.getJMSDestination(), Domain.QUEUE));
                } else {
                    rval.setJMSDestination(hermes.getDestination(message.getJMSDestination(), Domain.TOPIC));
                }
            }

            for (Iterator iter = message.getHeaderProperty().iterator(); iter.hasNext();) {
                Property property = (Property) iter.next();

                if (property.getValue() == null) {
                    rval.setObjectProperty(property.getName(), null);
                } else if (property.getType().equals(String.class.getName())) {
                    rval.setStringProperty(property.getName(), StringEscapeUtils.unescapeXml(property.getValue()));
                } else if (property.getType().equals(Long.class.getName())) {
                    rval.setLongProperty(property.getName(), Long.parseLong(property.getValue()));
                } else if (property.getType().equals(Double.class.getName())) {
                    rval.setDoubleProperty(property.getName(), Double.parseDouble(property.getValue()));
                } else if (property.getType().equals(Boolean.class.getName())) {
                    rval.setBooleanProperty(property.getName(), Boolean.parseBoolean(property.getValue()));
                } else if (property.getType().equals(Short.class.getName())) {
                    rval.setShortProperty(property.getName(), Short.parseShort(property.getValue()));
                } else if (property.getType().equals(Integer.class.getName())) {
                    rval.setIntProperty(property.getName(), Integer.parseInt(property.getValue()));
                }
            }

            return rval;
        } catch (NamingException e) {
            throw new HermesException(e);
        }

    }

    public XMLMessage createXMLMessage(ObjectFactory factory, Message message)
            throws JMSException, IOException, EncoderException {
        try {
            XMLMessage rval = factory.createXMLMessage();

            if (message instanceof TextMessage) {
                rval = factory.createXMLTextMessage();

                XMLTextMessage textRval = (XMLTextMessage) rval;
                TextMessage textMessage = (TextMessage) message;

                if (isBase64EncodeTextMessages()) {
                    byte[] bytes = base64EncoderTL.get().encode(textMessage.getText().getBytes());
                    textRval.setText(new String(bytes, "ASCII"));
                    textRval.setCodec(BASE64_CODEC);
                } else {
                    textRval.setText(textMessage.getText());
                }
            } else if (message instanceof MapMessage) {
                rval = factory.createXMLMapMessage();

                XMLMapMessage mapRval = (XMLMapMessage) rval;
                MapMessage mapMessage = (MapMessage) message;

                for (Enumeration iter = mapMessage.getMapNames(); iter.hasMoreElements();) {
                    String propertyName = (String) iter.nextElement();
                    Object propertyValue = mapMessage.getObject(propertyName);
                    Property xmlProperty = factory.createProperty();

                    if (propertyValue != null) {
                        xmlProperty.setValue(propertyValue.toString());
                        xmlProperty.setType(propertyValue.getClass().getName());
                    }
                    xmlProperty.setName(propertyName);

                    mapRval.getBodyProperty().add(xmlProperty);
                }
            } else if (message instanceof BytesMessage) {
                rval = factory.createXMLBytesMessage();

                XMLBytesMessage bytesRval = (XMLBytesMessage) rval;
                BytesMessage bytesMessage = (BytesMessage) message;
                ByteArrayOutputStream bosream = new ByteArrayOutputStream();

                bytesMessage.reset();

                try {
                    for (;;) {
                        bosream.write(bytesMessage.readByte());
                    }
                } catch (MessageEOFException ex) {
                    // NOP
                }

                bytesRval.setBytes(new String(base64EncoderTL.get().encode(bosream.toByteArray())));
            } else if (message instanceof ObjectMessage) {
                rval = factory.createXMLObjectMessage();

                XMLObjectMessage objectRval = (XMLObjectMessage) rval;
                ObjectMessage objectMessage = (ObjectMessage) message;

                ByteArrayOutputStream bostream = new ByteArrayOutputStream();
                ObjectOutputStream oostream = new ObjectOutputStream(bostream);

                oostream.writeObject(objectMessage.getObject());
                oostream.flush();
                byte b[] = base64EncoderTL.get().encode(bostream.toByteArray());
                String s = new String(b, "ASCII");
                objectRval.setObject(s);
            }

            if (message.getJMSReplyTo() != null) {
                rval.setJMSReplyTo(JMSUtils.getDestinationName(message.getJMSReplyTo()));
                rval.setJMSReplyToDomain(Domain.getDomain(message.getJMSReplyTo()).getId());
            }

            // try/catch each individually as we sometime find some JMS
            // providers
            // can barf
            try {
                rval.setJMSDeliveryMode(message.getJMSDeliveryMode());
            } catch (JMSException ex) {
                log.error(ex.getMessage(), ex);
            }

            try {
                rval.setJMSExpiration(message.getJMSExpiration());
            } catch (JMSException ex) {
                log.error(ex.getMessage(), ex);
            }

            try {
                rval.setJMSMessageID(message.getJMSMessageID());
            } catch (JMSException ex) {
                log.error(ex.getMessage(), ex);
            }

            try {
                rval.setJMSPriority(message.getJMSPriority());
            } catch (JMSException ex) {
                log.error(ex.getMessage(), ex);
            }

            try {
                rval.setJMSRedelivered(message.getJMSRedelivered());
            } catch (JMSException ex) {
                log.error(ex.getMessage(), ex);
            } catch (IllegalStateException ex) {
                // http://hermesjms.com/forum/viewtopic.php?f=4&t=346

                log.error(ex.getMessage(), ex);
            }

            try {
                rval.setJMSTimestamp(message.getJMSTimestamp());
            } catch (JMSException ex) {
                log.error(ex.getMessage(), ex);
            }

            try {
                rval.setJMSType(message.getJMSType());
            } catch (JMSException ex) {
                log.error(ex.getMessage(), ex);
            }

            try {
                rval.setJMSCorrelationID(message.getJMSCorrelationID());
            } catch (JMSException ex) {
                log.error(ex.getMessage(), ex);
            }

            try {
                if (message.getJMSDestination() != null) {
                    rval.setJMSDestination(JMSUtils.getDestinationName(message.getJMSDestination()));
                    rval.setFromQueue(JMSUtils.isQueue(message.getJMSDestination()));
                }
            } catch (JMSException ex) {
                log.error(ex.getMessage(), ex);
            }

            for (final Enumeration iter = message.getPropertyNames(); iter.hasMoreElements();) {
                String propertyName = (String) iter.nextElement();

                if (!propertyName.startsWith("JMS")) {
                    Object propertyValue = message.getObjectProperty(propertyName);
                    Property property = factory.createProperty();

                    property.setName(propertyName);

                    if (propertyValue != null) {
                        property.setValue(StringEscapeUtils.escapeXml(propertyValue.toString()));
                        property.setType(propertyValue.getClass().getName());
                    }

                    rval.getHeaderProperty().add(property);
                }
            }

            return rval;
        } catch (Exception ex) {
            throw new HermesException(ex);
        }
    }

}