hermes.renderers.DefaultMessageRenderer.java Source code

Java tutorial

Introduction

Here is the source code for hermes.renderers.DefaultMessageRenderer.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.renderers;

import hermes.browser.dialog.message.MapMessagePayloadPanel;
import hermes.swing.MyTextArea;
import hermes.util.MessageUtils;

import java.awt.Font;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.PrintWriter;
import java.io.Serializable;
import java.io.StringWriter;
import java.lang.reflect.InvocationTargetException;
import java.nio.charset.Charset;
import java.util.Iterator;
import java.util.Map;

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.StreamMessage;
import javax.jms.TextMessage;
import javax.swing.JComponent;
import javax.swing.JOptionPane;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;

import org.apache.commons.beanutils.PropertyUtils;
import org.apache.commons.collections.map.LRUMap;
import org.apache.log4j.Logger;

/**
 * Tries to render the message in some simple way.
 * 
 * @author colincrist@hermesjms.com
 * @version $Id: DefaultMessageRenderer.java,v 1.4 2004/07/30 17:25:13
 *          colincrist Exp $
 */

public class DefaultMessageRenderer extends AbstractMessageRenderer {
    private static final Logger log = Logger.getLogger(DefaultMessageRenderer.class);
    private static final String BYTESISSTRING = "bytesIsString";
    private static final String BYTESISOBJECT = "bytesIsObject";
    private static final String BYTESENCODING = "bytesEncoding";
    private static final String BYTESISOBJECTSIZE = "bytesIsObjectBufferSize";
    private static final String TOSTRINGOBJECT = "toStringOnObjectMessage";
    private static final String MESSAGE_CACHE = "messageCache";
    private static final String BYTESISSTRING_INFO = "Treat a BytesMessage as a sequence of characters and convert to a String";
    private static final String BYTESISOBJECT_INFO = "Treat a BytesMessage as a Serialized Java object";
    private static final String BYTESISOBJECTSIZE_INFO = "Buffer size to use as temporary storage (ignored with JMS 1.1 providers as size is available on the message)";
    private static final String TOSTRINGOBJECT_INFO = "Just call toString() on any Object in an ObjectMessage";
    private static final String MESSAGE_CACHE_INFO = "The number of panels to cache - can speed up the user interface when switching between messags";
    private static final String BYTESENCODING_INFO = "The encoding to use when treating a BytesMessage as a String";

    private LRUMap panelCache;

    /**
     * Configuration bean for this renderer
     * 
     * @author colincrist@hermesjms.com last changed by: $Author: colincrist $
     * @version $Id: DefaultMessageRenderer.java,v 1.4 2004/07/30 17:25:13
     *          colincrist Exp $
     */

    public class MyConfig extends AbstractMessageRenderer.BasicConfig {
        private String name;
        private boolean bytesIsObject = false;
        private int bytesIsObjectBufferSize = 64 * 1024;
        private boolean toStringOnObjectMessage = false;
        private int messageCache = 100;
        private boolean bytesIsString = false;
        private String bytesEncoding = Charset.defaultCharset().name();

        @Override
        public String toString() {
            return name + ".MyConfig: " + "bytesIsObject=" + bytesIsObject + ", bytesIsObjectBufferSize="
                    + bytesIsObjectBufferSize + ", toStringOnObjectMessage=" + toStringOnObjectMessage
                    + ", messageCache=" + messageCache + ", bytesIsString=" + bytesIsString;
        }

        public int getMessageCache() {
            return messageCache;
        }

        public void setMessageCache(int messageCache) {
            this.messageCache = messageCache;
        }

        /**
         * @return Returns the bytesIsObject.
         */
        public boolean isBytesIsObject() {
            return bytesIsObject;
        }

        /**
         * @param bytesIsObject
         *            The bytesIsObject to set.
         */
        public void setBytesIsObject(boolean bytesIsObject) {
            this.bytesIsObject = bytesIsObject;
        }

        /**
         * @return Returns the bytesIsObjectSize.
         */
        public int getBytesIsObjectBufferSize() {
            return bytesIsObjectBufferSize;
        }

        /**
         * @param bytesIsObjectSize
         *            The bytesIsObjectSize to set.
         */
        public void setBytesIsObjectBufferSize(int bytesIsObjectBufferSize) {
            this.bytesIsObjectBufferSize = bytesIsObjectBufferSize;
        }

        /**
         * @return Returns the bytesEncoding.
         */
        public String getBytesEncoding() {
            return bytesEncoding;
        }

        /**
         * @param bytesEncoding
         *            The bytesEncoding to set.
         */
        public void setBytesEncoding(String bytesEncoding) {
            this.bytesEncoding = bytesEncoding;
        }

        /**
         * @return Returns the name.
         */
        @Override
        public String getName() {
            return name;
        }

        /**
         * @param name
         *            The name to set.
         */
        @Override
        public void setName(String name) {
            this.name = name;
        }

        @Override
        public String getPropertyDescription(String propertyName) {
            if (propertyName.equals(BYTESISOBJECT)) {
                return BYTESISOBJECT_INFO;
            }

            if (propertyName.equals(BYTESISOBJECTSIZE)) {
                return BYTESISOBJECTSIZE_INFO;
            }

            if (propertyName.equals(TOSTRINGOBJECT)) {
                return TOSTRINGOBJECT_INFO;
            }

            if (propertyName.equals(MESSAGE_CACHE)) {
                return MESSAGE_CACHE_INFO;
            }

            if (propertyName.equals(BYTESISSTRING)) {
                return BYTESISSTRING_INFO;
            }

            if (propertyName.equals(BYTESENCODING)) {
                return BYTESENCODING_INFO;
            }

            return propertyName;
        }

        /**
         * @return Returns the toStringOnObjectMessage.
         */
        public boolean isToStringOnObjectMessage() {
            return toStringOnObjectMessage;
        }

        /**
         * @param toStringOnObjectMessage
         *            The toStringOnObjectMessage to set.
         */
        public void setToStringOnObjectMessage(boolean toStringOnObjectMessage) {
            this.toStringOnObjectMessage = toStringOnObjectMessage;
        }

        public boolean isBytesIsString() {
            return bytesIsString;
        }

        public void setBytesIsString(boolean bytesIsString) {
            this.bytesIsString = bytesIsString;
        }
    }

    /**
     * DefaultMessageRenderer constructor comment.
     */
    public DefaultMessageRenderer() {
        super();
    }

    /**
     * Show the TextMessage in a JTextArea.
     * 
     * @param textMessage
     * @return
     * @throws JMSException
     */
    protected JComponent handleTextMessage(final TextMessage textMessage) throws JMSException {
        //
        // Show the text in a JTextArea, you can edit the message in place and
        // then drop it onto another queue/topic.

        final String text = textMessage.getText();
        final JTextArea textPane = new JTextArea();

        // final CharBuffer bytes = CharBuffer.wrap(text.subSequence(0,
        // text.length())) ;
        // final JTextArea textPane = new MyTextArea(new PlainDocument(new
        // MappedStringContent(bytes))) ;

        textPane.setEditable(false);
        textPane.setFont(Font.decode("Monospaced-PLAIN-12"));
        textPane.setLineWrap(true);
        textPane.setWrapStyleWord(true);

        textPane.append(text);

        textPane.getDocument().addDocumentListener(new DocumentListener() {
            public void doChange() {
                try {
                    textMessage.setText(textPane.getText());
                } catch (JMSException e) {
                    JOptionPane.showMessageDialog(textPane, "Unable to update the TextMessage: " + e.getMessage(),
                            "Error modifying message content", JOptionPane.ERROR_MESSAGE);

                    try {
                        textPane.setText(textMessage.getText());
                    } catch (JMSException e1) {
                        log.error(e1.getMessage(), e1);
                    }

                    textPane.setEditable(false);
                    textPane.getDocument().removeDocumentListener(this);
                }
            }

            @Override
            public void changedUpdate(DocumentEvent arg0) {
                doChange();
            }

            @Override
            public void insertUpdate(DocumentEvent arg0) {
                doChange();
            }

            @Override
            public void removeUpdate(DocumentEvent arg0) {
                doChange();
            }
        });

        textPane.setCaretPosition(0);

        return textPane;
    }

    /**
     * Depending on configuration, show the object via toString() or a list of
     * properties.
     * 
     * @param objectMessage
     * @return
     * @throws JMSException
     * @throws IllegalAccessException
     * @throws InvocationTargetException
     * @throws NoSuchMethodException
     */
    protected JComponent handleObjectMessage(final ObjectMessage objectMessage)
            throws JMSException, IllegalAccessException, InvocationTargetException, NoSuchMethodException {
        //
        // Unserialize the object and display all its properties

        Serializable obj = objectMessage.getObject();

        if (obj instanceof JComponent) {
            return (JComponent) obj;
        } else {
            JTextArea textPane = new JTextArea();
            StringBuffer buffer = new StringBuffer();
            MyConfig currentConfig = (MyConfig) getConfig();

            if (obj == null) {
                buffer.append("Payload is null");
            } else if (currentConfig.isToStringOnObjectMessage()) {
                buffer.append(obj.toString());
            } else {
                buffer.append(obj.toString()).append("\n\nProperty list\n");

                for (Iterator iter = PropertyUtils.describe(obj).entrySet().iterator(); iter.hasNext();) {
                    Map.Entry entry = (Map.Entry) iter.next();

                    buffer.append(entry.getKey().toString()).append("=").append(entry.getValue()).append("\n");
                }
            }

            textPane.setEditable(false);
            textPane.setText(buffer.toString());

            return textPane;
        }
    }

    /**
     * Show the MapMessage as a tree.
     * 
     * @param mapMessage
     * @return
     * @throws JMSException
     */
    protected JComponent handleMapMessage(MapMessage mapMessage) throws JMSException {
        return new MapMessagePayloadPanel(mapMessage, false);
    }

    /**
     * Show a BytesMessage either as a java object or just a size.
     * 
     * @param parent
     * 
     * @param bytesMessage
     * @return
     * @throws JMSException
     * @throws IOException
     * @throws ClassNotFoundException
     */
    protected JComponent handleBytesMessage(JScrollPane parent, BytesMessage bytesMessage)
            throws JMSException, IOException, ClassNotFoundException {
        final MyConfig currentConfig = (MyConfig) getConfig();

        JTextArea textPane = new MyTextArea();

        textPane.setEditable(false);
        textPane.setWrapStyleWord(true);
        textPane.setLineWrap(true);
        bytesMessage.reset();

        if (currentConfig.isBytesIsObject()) {
            final byte[] bytes = MessageUtils.asBytes(bytesMessage);
            final ByteArrayInputStream bistream = new ByteArrayInputStream(bytes);
            final ObjectInputStream oistream = new ObjectInputStream(bistream);
            final Object o = oistream.readObject();

            textPane.setText(o.toString());
        } else if (currentConfig.isBytesIsString()) {
            try {
                String text = new String(MessageUtils.asBytes(bytesMessage), currentConfig.getBytesEncoding());
                textPane.setText(text);
                return textPane;
            } catch (JMSException e) {
                textPane.setText(e.getMessage());
            }
        } else {
            HexMessageRenderer renderer = new HexMessageRenderer();
            textPane = (JTextArea) renderer.render(parent, bytesMessage); // Hack.
        }

        textPane.setCaretPosition(0);

        return textPane;
    }

    /**
     * List out all the properties in the stream message.
     * 
     * @param streamMessage
     * @return
     * @throws JMSException
     */
    protected JComponent handleStreamMessage(StreamMessage streamMessage) throws JMSException {
        JTextArea textPane = new JTextArea();
        StringBuffer buffer = new StringBuffer();

        textPane.setEditable(false);

        streamMessage.reset();

        try {
            for (;;) {
                buffer.append(streamMessage.readObject().toString()).append("\n");
            }
        } catch (MessageEOFException ex) {
            // NOP
        }

        return textPane;
    }

    /**
     * Render the message, delegates to typed methods.
     */
    @Override
    public JComponent render(JScrollPane parent, final Message m) {
        try {
            if (getPanelMap().containsKey(m)) {
                return (JComponent) getPanelMap().get(m);
            }

            JComponent rval = null;

            if (m instanceof TextMessage) {
                rval = handleTextMessage((TextMessage) m);
            } else if (m instanceof javax.jms.ObjectMessage) {
                rval = handleObjectMessage((ObjectMessage) m);
            } else if (m instanceof javax.jms.MapMessage) {
                rval = handleMapMessage((MapMessage) m);
            } else if (m instanceof BytesMessage) {
                rval = handleBytesMessage(parent, (BytesMessage) m);
            } else if (m instanceof StreamMessage) {
                rval = handleStreamMessage((StreamMessage) m);
            } else {
                JTextArea textPane = new JTextArea();

                textPane.setEditable(false);
                textPane.setText("Message has no Payload");

                rval = textPane;
            }

            getPanelMap().put(m, rval);

            return rval;

        } catch (Throwable ex) {
            final JTextArea textPane = new JTextArea();

            textPane.setEditable(false);

            final StringWriter string = new StringWriter();
            final PrintWriter writer = new PrintWriter(string);

            ex.printStackTrace(writer);
            writer.flush();

            textPane.setText("Unable to display message:\n" + string.toString());

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

            return textPane;
        }
    }

    /*
     * (non-Javadoc)
     * 
     * @see hermes.browser.MessageRenderer#createConfig()
     */
    @Override
    public Config createConfig() {
        return new MyConfig();
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * hermes.browser.MessageRenderer#setConfig(hermes.browser.MessageRenderer
     * .Config)
     */
    @Override
    public synchronized void setConfig(Config config) {
        final MyConfig currentConfig = (MyConfig) config;
        panelCache = new LRUMap(currentConfig.getMessageCache());
        super.setConfig(config);
    }

    public synchronized LRUMap getPanelMap() {
        if (panelCache == null) {
            final MyConfig currentConfig = (MyConfig) getConfig();
            panelCache = new LRUMap(currentConfig.getMessageCache());
        }

        return panelCache;
    }

    /**
     * This is the catch all renderer so will always render a message.
     */
    @Override
    public boolean canRender(Message message) {
        return true;
    }

    @Override
    public String getDisplayName() {
        return "Payload";
    }
}