001    /** 
002     * 
003     * Copyright 2004 Protique Ltd
004     * 
005     * Licensed under the Apache License, Version 2.0 (the "License"); 
006     * you may not use this file except in compliance with the License. 
007     * You may obtain a copy of the License at 
008     * 
009     * http://www.apache.org/licenses/LICENSE-2.0
010     * 
011     * Unless required by applicable law or agreed to in writing, software
012     * distributed under the License is distributed on an "AS IS" BASIS, 
013     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
014     * See the License for the specific language governing permissions and 
015     * limitations under the License. 
016     * 
017     **/
018    
019    package org.activemq.message;
020    
021    
022    import java.io.DataInput;
023    import java.io.DataOutput;
024    import java.io.IOException;
025    import java.io.InputStream;
026    import java.io.OutputStream;
027    import java.io.Serializable;
028    
029    import javax.jms.JMSException;
030    import javax.jms.MessageFormatException;
031    import javax.jms.MessageNotWriteableException;
032    import javax.jms.ObjectMessage;
033    
034    import org.activemq.util.SerializationHelper;
035    
036    /**
037     * An <CODE>ObjectMessage</CODE> object is used to send a message that contains
038     * a serializable object in the Java programming language ("Java object").
039     * It inherits from the <CODE>Message</CODE> interface and adds a body
040     * containing a single reference to an object. Only <CODE>Serializable</CODE>
041     * Java objects can be used.
042     * <p/>
043     * <P>If a collection of Java objects must be sent, one of the
044     * <CODE>Collection</CODE> classes provided since JDK 1.2 can be used.
045     * <p/>
046     * <P>When a client receives an <CODE>ObjectMessage</CODE>, it is in read-only
047     * mode. If a client attempts to write to the message at this point, a
048     * <CODE>MessageNotWriteableException</CODE> is thrown. If
049     * <CODE>clearBody</CODE> is called, the message can now be both read from and
050     * written to.
051     *
052     * @see javax.jms.Session#createObjectMessage()
053     * @see javax.jms.Session#createObjectMessage(Serializable)
054     * @see javax.jms.BytesMessage
055     * @see javax.jms.MapMessage
056     * @see javax.jms.Message
057     * @see javax.jms.StreamMessage
058     * @see javax.jms.TextMessage
059     */
060    
061    public class ActiveMQObjectMessage extends ActiveMQMessage implements ObjectMessage {
062    
063        private Serializable object;
064    
065    
066        /**
067         * Return the type of Packet
068         *
069         * @return integer representation of the type of Packet
070         */
071    
072        public int getPacketType() {
073            return ACTIVEMQ_OBJECT_MESSAGE;
074        }
075    
076        /**
077         * @return Returns a shallow copy of the message instance
078         * @throws JMSException
079         */
080    
081        public ActiveMQMessage shallowCopy() throws JMSException {
082            ActiveMQObjectMessage other = new ActiveMQObjectMessage();
083            this.initializeOther(other);
084            other.object = this.object;
085            return other;
086        }
087    
088        /**
089         * @return Returns a deep copy of the message - note the header fields are only shallow copied
090         * @throws JMSException
091         */
092    
093        public ActiveMQMessage deepCopy() throws JMSException {
094            return shallowCopy();
095        }
096    
097        /**
098         * Clears out the message body. Clearing a message's body does not clear
099         * its header values or property entries.
100         * <p/>
101         * <P>If this message body was read-only, calling this method leaves
102         * the message body in the same state as an empty body in a newly
103         * created message.
104         *
105         * @throws JMSException if the JMS provider fails to clear the message
106         *                      body due to some internal error.
107         */
108    
109        public void clearBody() throws JMSException {
110            super.clearBody();
111            this.object = null;
112        }
113    
114    
115        /**
116         * Sets the serializable object containing this message's data.
117         * It is important to note that an <CODE>ObjectMessage</CODE>
118         * contains a snapshot of the object at the time <CODE>setObject()</CODE>
119         * is called; subsequent modifications of the object will have no
120         * effect on the <CODE>ObjectMessage</CODE> body.
121         *
122         * @param newObject the message's data
123         * @throws JMSException if the JMS provider fails to set the object
124         *                      due to some internal error.
125         * @throws javax.jms.MessageFormatException
126         *                      if object serialization fails.
127         * @throws javax.jms.MessageNotWriteableException
128         *                      if the message is in read-only
129         *                      mode.
130         */
131    
132        public void setObject(Serializable newObject) throws JMSException {
133            if (super.readOnlyMessage) {
134                throw new MessageNotWriteableException("The message is read-only");
135            }
136            try {
137                setBodyAsBytes(null);
138                this.object = newObject;
139                getBodyAsBytes(); // This serializes the object.
140                    } catch (IOException e) {
141                            throw (MessageFormatException)new MessageFormatException("Could not serialize the object: "+e.getMessage()).initCause(e);
142                    }
143        }
144    
145        public void setObjectPayload(Object newObject) {
146            this.object = (Serializable) newObject;
147        }
148    
149    
150        /**
151         * Gets the serializable object containing this message's data. The
152         * default value is null.
153         *
154         * @return the serializable object containing this message's data
155         * @throws JMSException
156         */
157    
158        public Serializable getObject() throws JMSException {
159            if (this.object == null) {
160                try {
161                    super.buildBodyFromBytes();
162                }
163                catch (IOException ioe) {
164                    throw createFailedToBuildBodyException(ioe);
165                }
166            }
167            return this.object;
168        }
169    
170        /**
171         * Prepare a message body for delivery
172         * @throws JMSException
173         */
174        public void prepareMessageBody() throws JMSException{
175            try {
176                convertBodyToBytes();
177                this.object = null;
178            }
179            catch (IOException ioe) {
180                throw createFailedToBuildBodyException(ioe);
181            }
182        }
183    
184        /**
185         * Used serialize the message body to an output stream
186         *
187         * @param dataOut
188         * @throws IOException
189         */
190    
191        public void writeBody(DataOutput dataOut) throws IOException {
192            SerializationHelper.writeObject((OutputStream)dataOut,this.object);
193        }
194    
195        /**
196         * Used to help build the body from an input stream
197         *
198         * @param dataIn
199         * @throws IOException
200         */
201    
202        public void readBody(DataInput dataIn) throws IOException {
203            try {
204                this.object = (Serializable) SerializationHelper.readObject((InputStream)dataIn);
205            }
206            catch (ClassNotFoundException ex) {
207                throw new IOException(ex.getMessage());
208            }
209        }
210    
211        public String toString() {
212            String objValue = "null";
213            try {
214                if (!isMessagePart()){
215                    Object obj = getObject();
216                    if (obj != null){
217                        objValue = obj.toString();
218                    }
219                }else {
220                    objValue = "message part";
221                }
222            }
223            catch (JMSException e) {
224                object = e;
225            }
226            return super.toString() + " ActiveMQObjectMessage{ " +
227                    "object = " + objValue +
228                    " }";
229        }
230    
231        protected JMSException createFailedToBuildBodyException(IOException ioe) {
232            JMSException jmsEx = new JMSException("Failed to build body from bytes. Reason: " + ioe);
233            jmsEx.setLinkedException(ioe);
234            return jmsEx;
235        }
236    }