View Javadoc

1   /*
2    * $Id: DefaultMuleMessage.java 22982 2011-09-19 13:58:50Z evangelinamrm $
3    * --------------------------------------------------------------------------------------
4    * Copyright (c) MuleSoft, Inc.  All rights reserved.  http://www.mulesoft.com
5    *
6    * The software in this package is published under the terms of the CPAL v1.0
7    * license, a copy of which has been included with this distribution in the
8    * LICENSE.txt file.
9    */
10  
11  package org.mule;
12  
13  import org.mule.api.ExceptionPayload;
14  import org.mule.api.MuleContext;
15  import org.mule.api.MuleEvent;
16  import org.mule.api.MuleException;
17  import org.mule.api.MuleMessage;
18  import org.mule.api.MuleRuntimeException;
19  import org.mule.api.ThreadSafeAccess;
20  import org.mule.api.config.MuleProperties;
21  import org.mule.api.transformer.DataType;
22  import org.mule.api.transformer.MessageTransformer;
23  import org.mule.api.transformer.Transformer;
24  import org.mule.api.transformer.TransformerException;
25  import org.mule.api.transport.OutputHandler;
26  import org.mule.api.transport.PropertyScope;
27  import org.mule.config.MuleManifest;
28  import org.mule.config.i18n.CoreMessages;
29  import org.mule.transformer.types.DataTypeFactory;
30  import org.mule.transformer.types.MimeTypes;
31  import org.mule.transport.NullPayload;
32  import org.mule.util.ClassUtils;
33  import org.mule.util.ObjectUtils;
34  import org.mule.util.StringMessageUtils;
35  import org.mule.util.StringUtils;
36  import org.mule.util.UUID;
37  import org.mule.util.store.DeserializationPostInitialisable;
38  
39  import java.io.File;
40  import java.io.FileInputStream;
41  import java.io.IOException;
42  import java.io.InputStream;
43  import java.io.ObjectInputStream;
44  import java.io.ObjectOutputStream;
45  import java.io.Reader;
46  import java.io.Serializable;
47  import java.net.URL;
48  import java.util.ArrayList;
49  import java.util.Arrays;
50  import java.util.Collections;
51  import java.util.HashMap;
52  import java.util.List;
53  import java.util.Map;
54  import java.util.Set;
55  import java.util.concurrent.ConcurrentHashMap;
56  import java.util.concurrent.CopyOnWriteArrayList;
57  import java.util.concurrent.atomic.AtomicBoolean;
58  import java.util.concurrent.atomic.AtomicReference;
59  
60  import javax.activation.DataHandler;
61  import javax.activation.FileDataSource;
62  
63  import org.apache.commons.logging.Log;
64  import org.apache.commons.logging.LogFactory;
65  
66  /**
67   * <code>DefaultMuleMessage</code> is a wrapper that contains a payload and properties
68   * associated with the payload.
69   */
70  public class DefaultMuleMessage implements MuleMessage, ThreadSafeAccess, DeserializationPostInitialisable
71  {
72      protected static final String NOT_SET = "<not set>";
73  
74      private static final long serialVersionUID = 1541720810851984845L;
75      private static final Log logger = LogFactory.getLog(DefaultMuleMessage.class);
76      private static final List<Class<?>> consumableClasses = new ArrayList<Class<?>>();
77  
78      /**
79       * The default UUID for the message. If the underlying transport has the notion of a
80       * message id, this uuid will be ignored
81       */
82      private String id = UUID.getUUID();
83      private String rootId = id;
84  
85      private transient Object payload;
86      private transient Object originalPayload;
87  
88      /**
89       * If an exception occurs while processing this message an exception payload
90       * will be attached here
91       */
92      private ExceptionPayload exceptionPayload;
93  
94      /**
95       * Scoped properties for this message
96       */
97      private MessagePropertiesContext properties = new MessagePropertiesContext();
98  
99      /**
100      * Collection of attachments that were attached to the incoming message
101      */
102     private transient Map<String, DataHandler> inboundAttachments = new ConcurrentHashMap<String, DataHandler>();
103 
104     /**
105      * Collection of attachments that will be sent out with this message
106      */
107     private transient Map<String, DataHandler> outboundAttachments = new ConcurrentHashMap<String, DataHandler>();
108 
109     private transient byte[] cache;
110     protected transient MuleContext muleContext;
111 
112     // these are transient because serialisation generates a new instance
113     // so we allow mutation again (and we can't serialize threads anyway)
114     private transient AtomicReference<Thread> ownerThread = null;
115     private transient AtomicBoolean mutable = null;
116 
117     private DataType<?> dataType;
118 
119     static
120     {
121         addToConsumableClasses("javax.xml.stream.XMLStreamReader");
122         addToConsumableClasses("javax.xml.transform.stream.StreamSource");
123         consumableClasses.add(OutputHandler.class);
124         consumableClasses.add(InputStream.class);
125         consumableClasses.add(Reader.class);
126     }
127 
128     private static void addToConsumableClasses(String className)
129     {
130         try
131         {
132             consumableClasses.add(ClassUtils.loadClass(className, DefaultMuleMessage.class));
133         }
134         catch (ClassNotFoundException e)
135         {
136             // ignore
137         }
138     }
139 
140     public DefaultMuleMessage(Object message, MuleContext muleContext)
141     {
142         this(message, (Map<String, Object>) null, muleContext);
143     }
144 
145     public DefaultMuleMessage(Object message, Map<String, Object> outboundProperties, MuleContext muleContext)
146     {
147         this(message, outboundProperties, null, muleContext);
148     }
149 
150     public DefaultMuleMessage(Object message, Map<String, Object> outboundProperties, Map<String, DataHandler> attachments, MuleContext muleContext)
151     {
152         this(message, null, outboundProperties, attachments, muleContext);
153     }
154 
155     public DefaultMuleMessage(Object message, Map<String, Object> inboundProperties,
156                               Map<String, Object> outboundProperties, Map<String, DataHandler> attachments,
157                               MuleContext muleContext)
158     {
159         setMuleContext(muleContext);
160 
161         if (message instanceof MuleMessage)
162         {
163             MuleMessage muleMessage = (MuleMessage) message;
164             setPayload(muleMessage.getPayload());
165             copyMessageProperties(muleMessage);
166         }
167         else
168         {
169             setPayload(message);
170             originalPayload = message;
171         }
172         addProperties(inboundProperties, PropertyScope.INBOUND);
173         addProperties(outboundProperties);
174 
175         //Add inbound attachments
176         if (attachments != null)
177         {
178             inboundAttachments = attachments;
179         }
180 
181         resetAccessControl();
182     }
183 
184     public DefaultMuleMessage(Object message, MuleMessage previous, MuleContext muleContext)
185     {
186         id = previous.getUniqueId();
187         rootId = previous.getMessageRootId();
188         setMuleContext(muleContext);
189         setEncoding(previous.getEncoding());
190 
191         if (message instanceof MuleMessage)
192         {
193             MuleMessage payloadMessage = (MuleMessage) message;
194             setPayload(payloadMessage.getPayload());
195             copyMessageProperties(payloadMessage);
196         }
197         else
198         {
199             setPayload(message);
200             copyMessageProperties(previous);
201         }
202         originalPayload = previous.getPayload();
203 
204         if (previous.getExceptionPayload() != null)
205         {
206             setExceptionPayload(previous.getExceptionPayload());
207         }
208 
209         copyAttachments(previous);
210 
211         resetAccessControl();
212     }
213 
214     private void copyMessageProperties(MuleMessage muleMessage)
215     {
216         // explicitly copy INBOUND message properties over. This cannot be done in the loop below
217         Map<String, Object> inboundProperties =
218                 ((DefaultMuleMessage) muleMessage).properties.getScopedProperties(PropertyScope.INBOUND);
219         addInboundProperties(inboundProperties);
220 
221         for (PropertyScope scope : PropertyScope.ALL_SCOPES)
222         {
223             try
224             {
225                 for (String name : muleMessage.getPropertyNames(scope))
226                 {
227                     Object value = muleMessage.getProperty(name, scope);
228                     if (value != null)
229                     {
230                         setProperty(name, value, scope);
231                     }
232                 }
233             }
234             catch (IllegalArgumentException iae)
235             {
236                 // ignore non-registered property scope
237             }
238         }
239     }
240 
241     private void copyAttachments(MuleMessage previous)
242     {
243         if (previous.getInboundAttachmentNames().size() > 0)
244         {
245             for (String name : previous.getInboundAttachmentNames())
246             {
247                 try
248                 {
249                     inboundAttachments.put(name, previous.getInboundAttachment(name));
250                 }
251                 catch (Exception e)
252                 {
253                     throw new MuleRuntimeException(CoreMessages.failedToReadAttachment(name), e);
254                 }
255             }
256         }
257 
258         if (previous.getOutboundAttachmentNames().size() > 0)
259         {
260             for (String name : previous.getOutboundAttachmentNames())
261             {
262                 try
263                 {
264                     addOutboundAttachment(name, previous.getOutboundAttachment(name));
265                 }
266                 catch (Exception e)
267                 {
268                     throw new MuleRuntimeException(CoreMessages.failedToReadAttachment(name), e);
269                 }
270             }
271         }
272     }
273 
274     public DefaultMuleMessage(MuleMessage message)
275     {
276         this(message.getPayload(), message, message.getMuleContext());
277     }
278 
279     private void setMuleContext(MuleContext context)
280     {
281         if (context == null)
282         {
283             throw new IllegalArgumentException(CoreMessages.objectIsNull("muleContext").getMessage());
284         }
285         muleContext = context;
286     }
287 
288     /**
289      * {@inheritDoc}
290      */
291     @Override
292     public <T> T getPayload(Class<T> outputType) throws TransformerException
293     {
294         return getPayload(DataTypeFactory.create(outputType), getEncoding());
295     }
296 
297 
298     /**
299      * {@inheritDoc}
300      */
301     @Override
302     public <T> T getPayload(DataType<T> outputType) throws TransformerException
303     {
304         return getPayload(outputType, getEncoding());
305     }
306 
307     @Override
308     public MuleContext getMuleContext()
309     {
310         return muleContext;
311     }
312 
313     /**
314      * Will attempt to obtain the payload of this message with the desired Class type. This will
315      * try and resolve a transformer that can do this transformation. If a transformer cannot be
316      * found an exception is thrown. Any transformers added to the registry will be checked for
317      * compatability.
318      *
319      * @param resultType the desired return type
320      * @param encoding   the encoding to use if required
321      * @return The converted payload of this message. Note that this method will not alter the
322      *         payload of this message <b>unless</b> the payload is an {@link InputStream} in which
323      *         case the stream will be read and the payload will become the fully read stream.
324      * @throws TransformerException if a transformer cannot be found or there is an error during
325      *                              transformation of the payload.
326      * @since 3.0
327      */
328     @SuppressWarnings("unchecked")
329     protected <T> T getPayload(DataType<T> resultType, String encoding) throws TransformerException
330     {
331         // Handle null by ignoring the request
332         if (resultType == null)
333         {
334             throw new IllegalArgumentException(CoreMessages.objectIsNull("resultType").getMessage());
335         }
336 
337         DataType source = DataTypeFactory.createFromObject(this);
338 
339         // If no conversion is necessary, just return the payload as-is
340         if (resultType.isCompatibleWith(source))
341         {
342             return (T) getPayload();
343         }
344 
345         // The transformer to execute on this message
346         Transformer transformer = muleContext.getRegistry().lookupTransformer(source, resultType);
347         if (transformer == null)
348         {
349             throw new TransformerException(CoreMessages.noTransformerFoundForMessage(source, resultType));
350         }
351 
352         // Pass in the message itself
353         Object result = transformer.transform(this, encoding);
354 
355         // Unless we disallow Object.class as a valid return type we need to do this extra check
356         if (!resultType.getType().isAssignableFrom(result.getClass()))
357         {
358             throw new TransformerException(CoreMessages.transformOnObjectNotOfSpecifiedType(resultType, result));
359         }
360 
361         // If the payload is a stream and we've consumed it, then we should set the payload on the
362         // message. This is the only time this method will alter the payload on the message
363         if (isPayloadConsumed(source.getType()))
364         {
365             setPayload(result);
366         }
367 
368         return (T) result;
369     }
370 
371     /**
372      * Checks if the payload has been consumed for this message. This only applies to Streaming payload types
373      * since once the stream has been read, the payload of the message should be updated to represent the data read
374      * from the stream
375      *
376      * @param inputCls the input type of the message payload
377      * @return true if the payload message type was stream-based, false otherwise
378      */
379     protected boolean isPayloadConsumed(Class<?> inputCls)
380     {
381         return InputStream.class.isAssignableFrom(inputCls) || isConsumedFromAdditional(inputCls);
382     }
383 
384     private boolean isConsumedFromAdditional(Class<?> inputCls)
385     {
386         if (consumableClasses.isEmpty())
387         {
388             return false;
389         }
390 
391         for (Class<?> c : consumableClasses)
392         {
393             if (c.isAssignableFrom(inputCls))
394             {
395                 return true;
396             }
397         }
398         return false;
399     }
400 
401     /**
402      * {@inheritDoc}
403      */
404     @Override
405     public Object getOriginalPayload()
406     {
407         return originalPayload;
408     }
409 
410     public void setInboundProperty(String key, Object value)
411     {
412         setProperty(key, value, PropertyScope.INBOUND);
413     }
414 
415     @Override
416     public void setInvocationProperty(String key, Object value)
417     {
418         setProperty(key, value, PropertyScope.INVOCATION);
419     }
420 
421     @Override
422     public void setOutboundProperty(String key, Object value)
423     {
424         setProperty(key, value, PropertyScope.OUTBOUND);
425     }
426 
427     @Override
428     public void setSessionProperty(String key, Object value)
429     {
430         setProperty(key, value, PropertyScope.SESSION);
431     }
432 
433     /**
434      * {@inheritDoc}
435      */
436     @Override
437     public void setProperty(String key, Object value, PropertyScope scope)
438     {
439         assertAccess(WRITE);
440         if (key != null)
441         {
442             if (value != null)
443             {
444                 properties.setProperty(key, value, scope);
445             }
446             else
447             {
448                 logger.warn("setProperty(key, value) called with null value; removing key: " + key
449                         + "; please report the following stack trace to " + MuleManifest.getDevListEmail(),
450                         new Throwable());
451                 properties.removeProperty(key);
452             }
453         }
454         else
455         {
456             logger.warn("setProperty(key, value) ignored because of null key for object: " + value
457                     + "; please report the following stack trace to " + MuleManifest.getDevListEmail(),
458                     new Throwable());
459         }
460     }
461 
462     /**
463      * {@inheritDoc}
464      */
465     @Override
466     @Deprecated
467     public Object getProperty(String key)
468     {
469         assertAccess(READ);
470         return properties.getProperty(key, PropertyScope.OUTBOUND);
471     }
472 
473 
474     /**
475      * {@inheritDoc}
476      */
477     @Override
478     public Object removeProperty(String key)
479     {
480         //TODO
481         //logger.warn("MuleMessage.removeProperty() method is deprecated, use MuleMessage.removeProperty(String, PropertyScope) instead.  This method will be removed in the next point release");
482         //return removeProperty(key, PropertyScope.OUTBOUND);
483         assertAccess(WRITE);
484         return properties.removeProperty(key);
485     }
486 
487     /**
488      * {@inheritDoc}
489      */
490     @Override
491     public Object removeProperty(String key, PropertyScope scope)
492     {
493         assertAccess(WRITE);
494         return properties.removeProperty(key, scope);
495     }
496 
497     /**
498      * Set a property on the message. This method will now set a value on the outbound scope only.
499      *
500      * @param key   the key on which to associate the value
501      * @param value the property value
502      * @see #setInboundProperty(String, Object)
503      * @see #setInvocationProperty(String, Object)
504      * @see #setOutboundProperty(String, Object)
505      * @see #setSessionProperty(String, Object)
506      * @deprecated use {@link #setProperty(String, Object, org.mule.api.transport.PropertyScope)} or
507      *             preferrably any of the scope-specific set methods.
508      */
509     @Override
510     @Deprecated
511     public void setProperty(String key, Object value)
512     {
513         assertAccess(WRITE);
514         if (key != null)
515         {
516             if (value != null)
517             {
518                 properties.setProperty(key, value, PropertyScope.OUTBOUND);
519             }
520             else
521             {
522                 logger.warn("setProperty(key, value) called with null value; removing key: " + key
523                         + "; please report the following stack trace to " + MuleManifest.getDevListEmail(),
524                         new Throwable());
525                 properties.removeProperty(key);
526             }
527         }
528         else
529         {
530             logger.warn("setProperty(key, value) ignored because of null key for object: " + value
531                     + "; please report the following stack trace to " + MuleManifest.getDevListEmail(),
532                     new Throwable());
533         }
534     }
535 
536     /**
537      * {@inheritDoc}
538      */
539     @Override
540     public final String getPayloadAsString() throws Exception
541     {
542         assertAccess(READ);
543         return getPayloadAsString(getEncoding());
544     }
545 
546      /**
547      * {@inheritDoc}
548      */
549     @Override
550     public String getPayloadForLogging(String encoding)
551     {
552         try
553         {
554             return getPayloadAsString(encoding);
555         }
556         catch (Exception e)
557         {
558             // TODO Auto-generated catch block
559             return  "[Messaage could not be converted to string]";
560         }
561     }
562 
563     /**
564      * {@inheritDoc}
565      */
566     @Override
567     public String getPayloadForLogging()
568     {
569         try
570         {
571             return getPayloadAsString();
572         }
573         catch (Exception e)
574         {
575             // TODO Auto-generated catch block
576             return  "[Messaage could not be converted to string]";
577         }
578     }
579 
580     /**
581      * {@inheritDoc}
582      */
583     @Override
584     public byte[] getPayloadAsBytes() throws Exception
585     {
586         assertAccess(READ);
587         if (cache != null)
588         {
589             return cache;
590         }
591         byte[] result = getPayload(DataType.BYTE_ARRAY_DATA_TYPE);
592         if (muleContext.getConfiguration().isCacheMessageAsBytes())
593         {
594             cache = result;
595         }
596         return result;
597     }
598 
599     /**
600      * {@inheritDoc}
601      */
602     @Override
603     public String getPayloadAsString(String encoding) throws Exception
604     {
605         assertAccess(READ);
606         if (cache != null)
607         {
608             return new String(cache, encoding);
609         }
610         String result = getPayload(DataType.STRING_DATA_TYPE, encoding);
611         if (muleContext.getConfiguration().isCacheMessageAsBytes())
612         {
613             cache = result.getBytes(encoding);
614         }
615         return result;
616     }
617 
618     /**
619      * {@inheritDoc}
620      *
621      * @deprecated use {@link #getPropertyNames(org.mule.api.transport.PropertyScope)}
622      */
623     @Override
624     @Deprecated
625     public Set<String> getPropertyNames()
626     {
627         //TODO logger.warn("MuleMessage.getPropertyNames() method is deprecated, use MuleMessage.getOutboundPropertyNames() instead.  This method will be removed in the next point release");
628         //return getOutboundPropertyNames();
629         assertAccess(READ);
630         return properties.getPropertyNames();
631     }
632 
633     /**
634      * {@inheritDoc}
635      */
636     @Override
637     public Set<String> getPropertyNames(PropertyScope scope)
638     {
639         assertAccess(READ);
640         if (PropertyScope.SESSION.equals(scope))
641         {
642             if (RequestContext.getEvent() != null)
643             {
644                 return RequestContext.getEvent().getSession().getPropertyNamesAsSet();
645             }
646             else
647             {
648                 return Collections.emptySet();
649             }
650         }
651         else
652         {
653             return properties.getScopedProperties(scope).keySet();
654         }
655     }
656 
657     @Override
658     public Set<String> getInvocationPropertyNames()
659     {
660         return getPropertyNames(PropertyScope.INVOCATION);
661     }
662 
663     @Override
664     public Set<String> getInboundPropertyNames()
665     {
666         return getPropertyNames(PropertyScope.INBOUND);
667     }
668 
669     @Override
670     public Set<String> getOutboundPropertyNames()
671     {
672         return getPropertyNames(PropertyScope.OUTBOUND);
673     }
674 
675     @Override
676     public Set<String> getSessionPropertyNames()
677     {
678         return getPropertyNames(PropertyScope.SESSION);
679     }
680 
681     //** {@inheritDoc} */
682 
683     /**
684      * {@inheritDoc}
685      */
686     @Override
687     public String getUniqueId()
688     {
689         assertAccess(READ);
690         return id;
691     }
692 
693     public void setUniqueId(String uid)
694     {
695         assertAccess(WRITE);
696         id = uid;
697     }
698 
699     @Override
700     public String getMessageRootId()
701     {
702         assertAccess(READ);
703         return rootId;
704     }
705 
706     @Override
707     public void setMessageRootId(String rid)
708     {
709         assertAccess(WRITE);
710         rootId = rid;
711     }
712 
713     @Override
714     public void propagateRootId(MuleMessage parent)
715     {
716         assertAccess(WRITE);
717         if (parent != null)
718         {
719             rootId = parent.getMessageRootId();
720         }
721     }
722 
723     /**
724      * {@inheritDoc}
725      */
726     @Override
727     public Object getProperty(String name, Object defaultValue)
728     {
729         //TODO logger.warn("MuleMessage.getProperty() method is deprecated, use MuleMessage.getOutboundProperty() instead.  This method will be removed in the next point release");
730         //return getOutboundProperty(name, defaultValue);
731         assertAccess(READ);
732         return properties.getProperty(name, defaultValue);
733     }
734 
735     /**
736      * {@inheritDoc}
737      */
738     @Override
739     @SuppressWarnings("unchecked")
740     public <T> T getProperty(String name, PropertyScope scope)
741     {
742         assertAccess(READ);
743         return (T) properties.getProperty(name, scope);
744     }
745 
746     @Override
747     public <T> T getInboundProperty(String name, T defaultValue)
748     {
749         return getProperty(name, PropertyScope.INBOUND, defaultValue);
750     }
751 
752     @Override
753     public <T> T getInboundProperty(String name)
754     {
755         return getProperty(name, PropertyScope.INBOUND, (T) null);
756     }
757 
758     @Override
759     public <T> T getInvocationProperty(String name, T defaultValue)
760     {
761         return getProperty(name, PropertyScope.INVOCATION, defaultValue);
762     }
763 
764     @Override
765     public <T> T getInvocationProperty(String name)
766     {
767         return getInvocationProperty(name, (T) null);
768     }
769 
770     @Override
771     public <T> T getOutboundProperty(String name, T defaultValue)
772     {
773         return getProperty(name, PropertyScope.OUTBOUND, defaultValue);
774     }
775 
776     @Override
777     public <T> T getOutboundProperty(String name)
778     {
779         return getOutboundProperty(name, (T) null);
780     }
781 
782     @Override
783     public <T> T getSessionProperty(String name, T defaultValue)
784     {
785         return getProperty(name, PropertyScope.SESSION, defaultValue);
786     }
787 
788     @Override
789     public <T> T getSessionProperty(String name)
790     {
791         return getSessionProperty(name, (T) null);
792     }
793 
794     /**
795      * {@inheritDoc}
796      */
797     @Override
798     @SuppressWarnings("unchecked")
799     public <T> T getProperty(String name, PropertyScope scope, T defaultValue)
800     {
801         assertAccess(READ);
802         T result;
803 
804         //Note that we need to keep the (redundant) casts in here because the compiler compiler complains
805         //about primitive types being cast to a generic type
806         if (defaultValue instanceof Boolean)
807         {
808             result = (T) (Boolean) ObjectUtils.getBoolean(getProperty(name, scope), (Boolean) defaultValue);
809         }
810         else if (defaultValue instanceof Byte)
811         {
812             result = (T) (Byte) ObjectUtils.getByte(getProperty(name, scope), (Byte) defaultValue);
813         }
814         else if (defaultValue instanceof Integer)
815         {
816             result = (T) (Integer) ObjectUtils.getInt(getProperty(name, scope), (Integer) defaultValue);
817         }
818         else if (defaultValue instanceof Short)
819         {
820             result = (T) (Short) ObjectUtils.getShort(getProperty(name, scope), (Short) defaultValue);
821         }
822         else if (defaultValue instanceof Long)
823         {
824             result = (T) (Long) ObjectUtils.getLong(getProperty(name, scope), (Long) defaultValue);
825         }
826         else if (defaultValue instanceof Float)
827         {
828             result = (T) (Float) ObjectUtils.getFloat(getProperty(name, scope), (Float) defaultValue);
829         }
830         else if (defaultValue instanceof Double)
831         {
832             result = (T) (Double) ObjectUtils.getDouble(getProperty(name, scope), (Double) defaultValue);
833         }
834         else if (defaultValue instanceof String)
835         {
836             result = (T) ObjectUtils.getString(getProperty(name, scope), (String) defaultValue);
837         }
838         else
839         {
840             Object temp = getProperty(name, scope);
841             if (temp == null)
842             {
843                 return defaultValue;
844             }
845             else if (defaultValue == null)
846             {
847                 return (T) temp;
848             }
849             //If defaultValue is set and the result is not null, then validate that they are assignable
850             else if (defaultValue.getClass().isAssignableFrom(temp.getClass()))
851             {
852                 result = (T) temp;
853             }
854             else
855             {
856                 throw new IllegalArgumentException(CoreMessages.objectNotOfCorrectType(temp.getClass(), defaultValue.getClass()).getMessage());
857             }
858         }
859         return result;
860     }
861 
862     /**
863      * {@inheritDoc}
864      */
865     @Override
866     public void setCorrelationId(String id)
867     {
868         assertAccess(WRITE);
869         if (StringUtils.isNotBlank(id))
870         {
871             setProperty(MuleProperties.MULE_CORRELATION_ID_PROPERTY, id, PropertyScope.OUTBOUND);
872         }
873         else
874         {
875             removeProperty(MuleProperties.MULE_CORRELATION_ID_PROPERTY);
876         }
877     }
878 
879     /**
880      * {@inheritDoc}
881      */
882     @Override
883     public String getCorrelationId()
884     {
885         assertAccess(READ);
886         String correlationId = getOutboundProperty(MuleProperties.MULE_CORRELATION_ID_PROPERTY);
887         if (correlationId == null)
888         {
889             correlationId = getInboundProperty(MuleProperties.MULE_CORRELATION_ID_PROPERTY);
890         }
891 
892         return correlationId;
893     }
894 
895     /**
896      * {@inheritDoc}
897      */
898     @Override
899     public void setReplyTo(Object replyTo)
900     {
901         assertAccess(WRITE);
902         if (replyTo != null)
903         {
904             setProperty(MuleProperties.MULE_REPLY_TO_PROPERTY, replyTo, PropertyScope.OUTBOUND);
905         }
906         else
907         {
908             removeProperty(MuleProperties.MULE_REPLY_TO_PROPERTY);
909             removeProperty(MuleProperties.MULE_REPLY_TO_PROPERTY, PropertyScope.INBOUND);
910         }
911     }
912 
913     /**
914      * {@inheritDoc}
915      */
916     @Override
917     public Object getReplyTo()
918     {
919         assertAccess(READ);
920         Object replyTo = getProperty(MuleProperties.MULE_REPLY_TO_PROPERTY, PropertyScope.OUTBOUND);
921         if (replyTo == null)
922         {
923             // fallback to inbound, use the requestor's setting if the invocation didn't set any
924             replyTo = getProperty(MuleProperties.MULE_REPLY_TO_PROPERTY, PropertyScope.INBOUND);
925         }
926         return replyTo;
927     }
928 
929     /**
930      * {@inheritDoc}
931      */
932     @Override
933     public int getCorrelationSequence()
934     {
935         assertAccess(READ);
936         // need to wrap with another getInt() as some transports operate on it as a String
937         Object correlationSequence = findPropertyInSpecifiedScopes(MuleProperties.MULE_CORRELATION_SEQUENCE_PROPERTY,
938                                                                    PropertyScope.OUTBOUND,
939                                                                    PropertyScope.INBOUND);
940         return ObjectUtils.getInt(correlationSequence, -1);
941     }
942 
943     /**
944      * {@inheritDoc}
945      */
946     @Override
947     public void setCorrelationSequence(int sequence)
948     {
949         assertAccess(WRITE);
950         setOutboundProperty(MuleProperties.MULE_CORRELATION_SEQUENCE_PROPERTY, sequence);
951     }
952 
953     /**
954      * {@inheritDoc}
955      */
956     @Override
957     public int getCorrelationGroupSize()
958     {
959         assertAccess(READ);
960         // need to wrap with another getInt() as some transports operate on it as a String
961         Object correlationGroupSize = findPropertyInSpecifiedScopes(MuleProperties.MULE_CORRELATION_GROUP_SIZE_PROPERTY,
962                                                                     PropertyScope.OUTBOUND,
963                                                                     PropertyScope.INBOUND);
964         return ObjectUtils.getInt(correlationGroupSize, -1);
965     }
966 
967     /**
968      * {@inheritDoc}
969      */
970     @Override
971     public void setCorrelationGroupSize(int size)
972     {
973         assertAccess(WRITE);
974         setOutboundProperty(MuleProperties.MULE_CORRELATION_GROUP_SIZE_PROPERTY, size);
975     }
976 
977     /**
978      * {@inheritDoc}
979      */
980     @Override
981     public ExceptionPayload getExceptionPayload()
982     {
983         assertAccess(READ);
984         return exceptionPayload;
985     }
986 
987     /**
988      * {@inheritDoc}
989      */
990     @Override
991     public void setExceptionPayload(ExceptionPayload exceptionPayload)
992     {
993         assertAccess(WRITE);
994         this.exceptionPayload = exceptionPayload;
995     }
996 
997     @Override
998     public String toString()
999     {
1000         assertAccess(READ);
1001         StringBuffer buf = new StringBuffer(120);
1002         final String nl = System.getProperty("line.separator");
1003 
1004         // format message for multi-line output, single-line is not readable
1005         buf.append(nl);
1006         buf.append(getClass().getName());
1007         buf.append(nl);
1008         buf.append("{");
1009         buf.append(nl);
1010         buf.append("  id=").append(getUniqueId());
1011         buf.append(nl);
1012         buf.append("  payload=").append(getPayload().getClass().getName());
1013         buf.append(nl);
1014         buf.append("  correlationId=").append(StringUtils.defaultString(getCorrelationId(), NOT_SET));
1015         buf.append(nl);
1016         buf.append("  correlationGroup=").append(getCorrelationGroupSize());
1017         buf.append(nl);
1018         buf.append("  correlationSeq=").append(getCorrelationSequence());
1019         buf.append(nl);
1020         buf.append("  encoding=").append(getEncoding());
1021         buf.append(nl);
1022         buf.append("  exceptionPayload=").append(ObjectUtils.defaultIfNull(exceptionPayload, NOT_SET));
1023         buf.append(nl);
1024         buf.append(StringMessageUtils.headersToString(this));
1025         // no new line here, as headersToString() adds one
1026         buf.append('}');
1027         return buf.toString();
1028     }
1029 
1030     /**
1031      * {@inheritDoc}
1032      */
1033     @Override
1034     @Deprecated
1035     public void addAttachment(String name, DataHandler dataHandler) throws Exception
1036     {
1037         logger.warn("MuleMessage.addAttachment() method is deprecated, use MuleMessage.addOutboundAttachment() instead.  This method will be removed in the next point release");
1038         addOutboundAttachment(name, dataHandler);
1039     }
1040 
1041     /**
1042      * {@inheritDoc}
1043      */
1044     @Override
1045     @Deprecated
1046     public void removeAttachment(String name) throws Exception
1047     {
1048         logger.warn("MuleMessage.removeAttachment() method is deprecated, use MuleMessage.removeOutboundAttachment() instead.  This method will be removed in the next point release");
1049         removeOutboundAttachment(name);
1050     }
1051 
1052     /**
1053      * {@inheritDoc}
1054      */
1055     @Override
1056     @Deprecated
1057     public DataHandler getAttachment(String name)
1058     {
1059         logger.warn("MuleMessage.getAttachment() method is deprecated, use MuleMessage.getInboundAttachment() instead.  This method will be removed in the next point release");
1060         return getInboundAttachment(name);
1061     }
1062 
1063     /**
1064      * {@inheritDoc}
1065      */
1066     @Override
1067     @Deprecated
1068     public Set<String> getAttachmentNames()
1069     {
1070         logger.warn("MuleMessage.getAttachmentNames() method is deprecated, use MuleMessage.getInboundAttachmentNames() instead.  This method will be removed in the next point release");
1071         return getInboundAttachmentNames();
1072     }
1073 
1074     @Override
1075     public void addOutboundAttachment(String name, DataHandler dataHandler) throws Exception
1076     {
1077         assertAccess(WRITE);
1078         outboundAttachments.put(name, dataHandler);
1079     }
1080 
1081     ///TODO this should not be here, but needed so that a message factory can add attachments
1082     //This is not part of the API
1083 
1084     public void addInboundAttachment(String name, DataHandler dataHandler) throws Exception
1085     {
1086         assertAccess(WRITE);
1087         inboundAttachments.put(name, dataHandler);
1088     }
1089 
1090     @Override
1091     public void addOutboundAttachment(String name, Object object, String contentType) throws Exception
1092     {
1093         assertAccess(WRITE);
1094         DataHandler dh;
1095         if (object instanceof File)
1096         {
1097             if (contentType != null)
1098             {
1099                 dh = new DataHandler(new FileInputStream((File) object), contentType);
1100 
1101             }
1102             else
1103             {
1104                 dh = new DataHandler(new FileDataSource((File) object));
1105             }
1106         }
1107         else if (object instanceof URL)
1108         {
1109             if (contentType != null)
1110             {
1111                 dh = new DataHandler(((URL) object).openStream(), contentType);
1112             }
1113             else
1114             {
1115                 dh = new DataHandler((URL) object);
1116             }
1117         }
1118         else
1119         {
1120             dh = new DataHandler(object, contentType);
1121         }
1122         outboundAttachments.put(name, dh);
1123     }
1124 
1125     @Override
1126     public void removeOutboundAttachment(String name) throws Exception
1127     {
1128         assertAccess(WRITE);
1129         outboundAttachments.remove(name);
1130     }
1131 
1132     @Override
1133     public DataHandler getInboundAttachment(String name)
1134     {
1135         assertAccess(READ);
1136         return inboundAttachments.get(name);
1137     }
1138 
1139     @Override
1140     public DataHandler getOutboundAttachment(String name)
1141     {
1142         assertAccess(READ);
1143         return outboundAttachments.get(name);
1144     }
1145 
1146     @Override
1147     public Set<String> getInboundAttachmentNames()
1148     {
1149         assertAccess(READ);
1150         return Collections.unmodifiableSet(inboundAttachments.keySet());
1151     }
1152 
1153     @Override
1154     public Set<String> getOutboundAttachmentNames()
1155     {
1156         assertAccess(READ);
1157         return Collections.unmodifiableSet(outboundAttachments.keySet());
1158     }
1159 
1160     @Override
1161     @SuppressWarnings("unchecked")
1162     public <T> T findPropertyInAnyScope(String name, T defaultValue)
1163     {
1164         Object value = findPropertyInSpecifiedScopes(name,
1165                                                      PropertyScope.OUTBOUND,
1166                                                      PropertyScope.INVOCATION,
1167                                                      PropertyScope.SESSION,
1168                                                      PropertyScope.INBOUND);
1169         if (value == null)
1170         {
1171             return defaultValue;
1172         }
1173         return (T) value;
1174     }
1175 
1176     /**
1177      * {@inheritDoc}
1178      */
1179     @Override
1180     public String getEncoding()
1181     {
1182         assertAccess(READ);
1183         String encoding = null;
1184         if (dataType != null)
1185         {
1186             encoding = dataType.getEncoding();
1187         }
1188         if (encoding != null)
1189         {
1190             return encoding;
1191         }
1192         encoding = getOutboundProperty(MuleProperties.MULE_ENCODING_PROPERTY);
1193         if (encoding != null)
1194         {
1195             return encoding;
1196         }
1197         else
1198         {
1199             return System.getProperty(MuleProperties.MULE_ENCODING_SYSTEM_PROPERTY);
1200         }
1201     }
1202 
1203     /**
1204      * {@inheritDoc}
1205      */
1206     @Override
1207     public void setEncoding(String encoding)
1208     {
1209         assertAccess(WRITE);
1210         if (encoding != null)
1211         {
1212             setOutboundProperty(MuleProperties.MULE_ENCODING_PROPERTY, encoding);
1213         }
1214     }
1215 
1216     /**
1217      * @param mimeType
1218      * @since 3.0
1219      */
1220     public void setMimeType(String mimeType)
1221     {
1222         assertAccess(WRITE);
1223         if (mimeType != null && !mimeType.equals(MimeTypes.ANY))
1224         {
1225             String encoding = getEncoding();
1226             if (encoding != null)
1227             {
1228                 mimeType = mimeType + ";charset=" + encoding;
1229             }
1230             setOutboundProperty(MuleProperties.CONTENT_TYPE_PROPERTY, mimeType);
1231         }
1232     }
1233 
1234     /**
1235      * {@inheritDoc}
1236      */
1237     @Override
1238     public void addProperties(Map<String, Object> props)
1239     {
1240         addProperties(props, properties.getDefaultScope());
1241     }
1242 
1243     /**
1244      * {@inheritDoc}
1245      */
1246     @Override
1247     public void addProperties(Map<String, Object> props, PropertyScope scope)
1248     {
1249         assertAccess(WRITE);
1250         if (props != null)
1251         {
1252             synchronized (props)
1253             {
1254                 for (Map.Entry<String, Object> entry : props.entrySet())
1255                 {
1256                     setProperty(entry.getKey(), entry.getValue(), scope);
1257                 }
1258             }
1259         }
1260     }
1261 
1262     public void addInboundProperties(Map<String, Object> props)
1263     {
1264         properties.addInboundProperties(props);
1265     }
1266 
1267     /**
1268      * {@inheritDoc}
1269      */
1270     @Override
1271     public void clearProperties()
1272     {
1273         assertAccess(WRITE);
1274         //Inbound scope is read-only
1275         properties.clearProperties(PropertyScope.INVOCATION);
1276         properties.clearProperties(PropertyScope.OUTBOUND);
1277     }
1278 
1279     /**
1280      * {@inheritDoc}
1281      */
1282     @Override
1283     public void clearProperties(PropertyScope scope)
1284     {
1285         assertAccess(WRITE);
1286         properties.clearProperties(scope);
1287     }
1288 
1289 
1290     /**
1291      * {@inheritDoc}
1292      */
1293     @Override
1294     public Object getPayload()
1295     {
1296         return payload;
1297     }
1298 
1299     /**
1300      * {@inheritDoc}
1301      */
1302     @Override
1303     public synchronized void setPayload(Object payload)
1304     {
1305         if (payload == null)
1306         {
1307             this.payload = NullPayload.getInstance();
1308         }
1309         else
1310         {
1311             this.payload = payload;
1312         }
1313         cache = null;
1314     }
1315 
1316     /**
1317      * {@inheritDoc}
1318      */
1319     @Override
1320     public void release()
1321     {
1322         cache = null;
1323     }
1324 
1325     /**
1326      * {@inheritDoc}
1327      */
1328     @Override
1329     public void applyTransformers(MuleEvent event, List<? extends Transformer> transformers) throws MuleException
1330     {
1331         applyTransformers(event, transformers, null);
1332     }
1333 
1334     /**
1335      * {@inheritDoc}
1336      */
1337     @Override
1338     public void applyTransformers(MuleEvent event, Transformer... transformers) throws MuleException
1339     {
1340         applyTransformers(event, Arrays.asList(transformers), null);
1341     }
1342 
1343     @Override
1344     public void applyTransformers(MuleEvent event, List<? extends Transformer> transformers, Class<?> outputType) throws MuleException
1345     {
1346         if (!transformers.isEmpty())
1347         {
1348             applyAllTransformers(event, transformers);
1349         }
1350 
1351         if (null != outputType && !getPayload().getClass().isAssignableFrom(outputType))
1352         {
1353             setPayload(getPayload(DataTypeFactory.create(outputType)));
1354         }
1355     }
1356 
1357     protected void applyAllTransformers(MuleEvent event, List<? extends Transformer> transformers) throws MuleException
1358     {
1359         if (!transformers.isEmpty())
1360         {
1361             for (Transformer transformer : transformers)
1362             {
1363                 if (getPayload() == null)
1364                 {
1365                     if (transformer.isAcceptNull())
1366                     {
1367                         setPayload(NullPayload.getInstance());
1368                         setDataType(null);
1369                     }
1370                     else
1371                     {
1372                         if (logger.isDebugEnabled())
1373                         {
1374                             logger.debug("Transformer " + transformer +
1375                                     " doesn't support the null payload, exiting from transformer chain.");
1376                         }
1377                         break;
1378                     }
1379                 }
1380 
1381                 Class<?> srcCls = getPayload().getClass();
1382                 if (transformer.isSourceDataTypeSupported(DataTypeFactory.create(srcCls)))
1383                 {
1384                     Object result;
1385                     if (transformer instanceof MessageTransformer)
1386                     {
1387                         result = ((MessageTransformer) transformer).transform(this, event);
1388                     }
1389                     else
1390                     {
1391                         result = transformer.transform(this);
1392                     }
1393                     // Update the RequestContext with the result of the transformation.
1394                     RequestContext.internalRewriteEvent(this, false);
1395 
1396                     if (originalPayload == null && muleContext.getConfiguration().isCacheMessageOriginalPayload())
1397                     {
1398                         originalPayload = payload;
1399                     }
1400 
1401                     if (result instanceof MuleMessage)
1402                     {
1403                         if (!result.equals(this))
1404                         {
1405                             // Only copy the payload and properties of mule message
1406                             // transformer result if the message is a different
1407                             // instance
1408                             synchronized (this)
1409                             {
1410                                 MuleMessage resultMessage = (MuleMessage) result;
1411                                 setPayload(resultMessage.getPayload());
1412                                 originalPayload = resultMessage.getOriginalPayload();
1413                                 copyMessageProperties(resultMessage);
1414                                 copyAttachments(resultMessage);
1415                             }
1416                         }
1417                     }
1418                     else
1419                     {
1420                         setPayload(result);
1421                     }
1422                     setDataType(transformer.getReturnDataType());
1423                 }
1424                 else
1425                 {
1426                     if (logger.isDebugEnabled())
1427                     {
1428                         logger.debug("Transformer " + transformer + " doesn't support the source payload: " + srcCls);
1429                     }
1430                     if (!transformer.isIgnoreBadInput())
1431                     {
1432                         if (logger.isDebugEnabled())
1433                         {
1434                             logger.debug("Exiting from transformer chain (ignoreBadInput = false)");
1435                         }
1436                         break;
1437                     }
1438                 }
1439             }
1440         }
1441     }
1442 
1443     protected void setDataType(DataType<?> dt)
1444     {
1445         dataType = dt;
1446         setEncoding(dt == null ? null : dt.getEncoding());
1447         setMimeType(dt == null ? null : dt.getMimeType());
1448     }
1449 
1450     //////////////////////////////// ThreadSafeAccess Impl ///////////////////////////////
1451 
1452     /**
1453      * {@inheritDoc}
1454      */
1455     @Override
1456     public ThreadSafeAccess newThreadCopy()
1457     {
1458         return new DefaultMuleMessage(this);
1459     }
1460 
1461     /**
1462      * {@inheritDoc}
1463      */
1464     @Override
1465     public void resetAccessControl()
1466     {
1467         // just reset the internal state here as this method is explicitly intended not to
1468         // be used from the outside
1469         if (ownerThread != null)
1470         {
1471             ownerThread.set(null);
1472         }
1473         if (mutable != null)
1474         {
1475             mutable.set(true);
1476         }
1477     }
1478 
1479     /**
1480      * {@inheritDoc}
1481      */
1482     @Override
1483     public void assertAccess(boolean write)
1484     {
1485         if (AccessControl.isAssertMessageAccess())
1486         {
1487             initAccessControl();
1488             setOwner();
1489             checkMutable(write);
1490         }
1491     }
1492 
1493     private synchronized void initAccessControl()
1494     {
1495         if (null == ownerThread)
1496         {
1497             ownerThread = new AtomicReference<Thread>();
1498         }
1499         if (null == mutable)
1500         {
1501             mutable = new AtomicBoolean(true);
1502         }
1503     }
1504 
1505     private void setOwner()
1506     {
1507         if (null == ownerThread.get())
1508         {
1509             ownerThread.compareAndSet(null, Thread.currentThread());
1510         }
1511     }
1512 
1513     private void checkMutable(boolean write)
1514     {
1515 
1516         // IF YOU SEE AN EXCEPTION THAT IS RAISED FROM WITHIN THIS CODE
1517         // ============================================================
1518         //
1519         // First, understand that the exception here is not the "real" problem.  These exceptions
1520         // give early warning of a much more serious issue that results in unreliable and unpredictable
1521         // code - more than one thread is attempting to change the contents of a message.
1522         //
1523         // Having said that, you can disable these exceptions by defining
1524         // MuleProperties.MULE_THREAD_UNSAFE_MESSAGES_PROPERTY (mule.disable.threadsafemessages)
1525         // (i.e., by adding -Dmule.disable.threadsafemessages=true to the java command line).
1526         //
1527         // To remove the underlying cause, however, you probably need to do one of:
1528         //
1529         // - make sure that the message you are using correctly implements the ThreadSafeAccess
1530         //   interface
1531         //
1532         // - make sure that dispatcher and receiver classes copy ThreadSafeAccess instances when
1533         //   they are passed between threads
1534 
1535         Thread currentThread = Thread.currentThread();
1536         if (currentThread.equals(ownerThread.get()))
1537         {
1538             if (write && !mutable.get())
1539             {
1540                 if (isDisabled())
1541                 {
1542                     logger.warn("Writing to immutable message (exception disabled)");
1543                 }
1544                 else
1545                 {
1546                     throw newException("Cannot write to immutable message");
1547                 }
1548             }
1549         }
1550         else
1551         {
1552             if (write)
1553             {
1554                 if (isDisabled())
1555                 {
1556                     logger.warn("Non-owner writing to message (exception disabled)");
1557                 }
1558                 else
1559                 {
1560                     throw newException("Only owner thread can write to message: "
1561                             + ownerThread.get() + "/" + Thread.currentThread());
1562                 }
1563             }
1564         }
1565     }
1566 
1567     protected boolean isDisabled()
1568     {
1569         return !AccessControl.isFailOnMessageScribbling();
1570     }
1571 
1572     protected IllegalStateException newException(String message)
1573     {
1574         IllegalStateException exception = new IllegalStateException(message);
1575         logger.warn("Message access violation", exception);
1576         return exception;
1577     }
1578 
1579     /**
1580      * Determines if the payload of this message is consumable i.e. it can't be read
1581      * more than once. This is here temporarily without adding to MuleMessage
1582      * interface until MULE-4256 is implemented.
1583      */
1584     public boolean isConsumable()
1585     {
1586         return isConsumedFromAdditional(this.getPayload().getClass());
1587     }
1588 
1589     public static class SerializedDataHandler implements Serializable
1590     {
1591         private static final long serialVersionUID = 1L;
1592 
1593         private DataHandler handler;
1594         private String contentType;
1595         private Object contents;
1596 
1597         public SerializedDataHandler(String name, DataHandler handler, MuleContext muleContext) throws IOException
1598         {
1599             if (handler != null && !(handler instanceof Serializable))
1600             {
1601                 contentType = handler.getContentType();
1602                 Object theContent = handler.getContent();
1603                 if (theContent instanceof Serializable)
1604                 {
1605                     contents = theContent;
1606                 }
1607                 else
1608                 {
1609                     try
1610                     {
1611                         DataType source = DataTypeFactory.createFromObject(theContent);
1612                         Transformer transformer = muleContext.getRegistry().lookupTransformer(source, DataType.BYTE_ARRAY_DATA_TYPE);
1613                         if (transformer == null)
1614                         {
1615                             throw new TransformerException(CoreMessages.noTransformerFoundForMessage(source, DataType.BYTE_ARRAY_DATA_TYPE));
1616                         }
1617                         contents = transformer.transform(theContent);
1618                     }
1619                     catch(TransformerException ex)
1620                     {
1621                         String message = String.format(
1622                                 "Unable to serialize the attachment %s, which is of type %s with contents of type %s",
1623                                 name, handler.getClass(), theContent.getClass());
1624                         logger.error(message);
1625                         throw new IOException(message);
1626                     }
1627                 }
1628             }
1629             else
1630             {
1631                 this.handler = handler;
1632             }
1633         }
1634 
1635         public DataHandler getHandler()
1636         {
1637             return contents != null ? new DataHandler(contents, contentType) : handler;
1638         }
1639     }
1640 
1641     private void writeObject(ObjectOutputStream out) throws Exception
1642     {
1643         out.defaultWriteObject();
1644         if (payload instanceof Serializable)
1645         {
1646             out.writeBoolean(true);
1647             out.writeObject(payload);
1648         }
1649         else
1650         {
1651             out.writeBoolean(false);
1652             byte[] serializablePayload = getPayloadAsBytes();
1653             out.writeInt(serializablePayload.length);
1654             out.write(serializablePayload);
1655         }
1656         out.writeObject(serializeAttachments(inboundAttachments));
1657         out.writeObject(serializeAttachments(outboundAttachments));
1658 
1659         // TODO: we don't serialize the originalPayload for now
1660     }
1661 
1662     private Map<String, SerializedDataHandler> serializeAttachments(Map<String, DataHandler> attachments) throws IOException
1663     {
1664         Map<String, SerializedDataHandler> toWrite;
1665         if (attachments == null)
1666         {
1667             toWrite = null;
1668         }
1669         else
1670         {
1671             toWrite = new HashMap<String, SerializedDataHandler>(attachments.size());
1672             for (Map.Entry<String, DataHandler> entry : attachments.entrySet())
1673             {
1674                 String name = entry.getKey();
1675                 toWrite.put(name, new SerializedDataHandler(name, entry.getValue(), muleContext));
1676             }
1677         }
1678 
1679         return toWrite;
1680     }
1681 
1682     private Map<String, DataHandler> deserializeAttachments(Map<String, SerializedDataHandler> attachments) throws IOException
1683     {
1684         Map<String, DataHandler> toReturn;
1685         if (attachments == null)
1686         {
1687             toReturn = null;
1688         }
1689         else
1690         {
1691             toReturn = new HashMap<String, DataHandler>(attachments.size());
1692             for (Map.Entry<String, SerializedDataHandler> entry : attachments.entrySet())
1693             {
1694                 toReturn.put(entry.getKey(), entry.getValue().getHandler());
1695             }
1696         }
1697 
1698         return toReturn;
1699     }
1700 
1701     private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException
1702     {
1703         in.defaultReadObject();
1704 
1705         boolean payloadWasSerialized = in.readBoolean();
1706         if (payloadWasSerialized)
1707         {
1708             payload = in.readObject();
1709         }
1710         else
1711         {
1712             int payloadSize = in.readInt();
1713             byte[] serializedPayload = new byte[payloadSize];
1714             in.read(serializedPayload);
1715             payload = serializedPayload;
1716         }
1717         inboundAttachments = deserializeAttachments((Map<String, SerializedDataHandler>)in.readObject());
1718         outboundAttachments = deserializeAttachments((Map<String, SerializedDataHandler>)in.readObject());
1719     }
1720 
1721     /**
1722      * Invoked after deserialization. This is called when the marker interface
1723      * {@link org.mule.util.store.DeserializationPostInitialisable} is used. This will get invoked
1724      * after the object has been deserialized passing in the current mulecontext when using either
1725      * {@link org.mule.transformer.wire.SerializationWireFormat},
1726      * {@link org.mule.transformer.wire.SerializedMuleMessageWireFormat} or the
1727      * {@link org.mule.transformer.simple.ByteArrayToSerializable} transformer.
1728      *
1729      * @param context the current muleContext instance
1730      * @throws MuleException if there is an error initializing
1731      */
1732     public void initAfterDeserialisation(MuleContext context) throws MuleException
1733     {
1734         this.muleContext = context;
1735     }
1736 
1737     @Override
1738     public DataType<?> getDataType()
1739     {
1740         return dataType;
1741     }
1742 
1743     /**
1744      * {@inheritDoc}
1745      */
1746     @Override
1747     @Deprecated
1748     public int getIntProperty(String name, int defaultValue)
1749     {
1750         assertAccess(READ);
1751         logger.warn("MuleMessage.getIntProperty() method is deprecated, use MuleMessage.getInboundProperty() instead.  This method will be removed in the next point release");
1752         return getInboundProperty(name, defaultValue);
1753     }
1754 
1755     /**
1756      * {@inheritDoc}
1757      */
1758     @Override
1759     @Deprecated
1760     public long getLongProperty(String name, long defaultValue)
1761     {
1762         assertAccess(READ);
1763         logger.warn("MuleMessage.getLongProperty() method is deprecated, use MuleMessage.getInboundProperty() instead.  This method will be removed in the next point release");
1764         return getInboundProperty(name, defaultValue);
1765     }
1766 
1767     /**
1768      * {@inheritDoc}
1769      */
1770     @Override
1771     @Deprecated
1772     public double getDoubleProperty(String name, double defaultValue)
1773     {
1774         assertAccess(READ);
1775         logger.warn("MuleMessage.getDoubleProperty() method is deprecated, use MuleMessage.getInboundProperty() instead.  This method will be removed in the next point release");
1776         return getInboundProperty(name, defaultValue);
1777     }
1778 
1779     /**
1780      * {@inheritDoc}
1781      */
1782     @Override
1783     @Deprecated
1784     public boolean getBooleanProperty(String name, boolean defaultValue)
1785     {
1786         assertAccess(READ);
1787         logger.warn("MuleMessage.getBooleanProperty() method is deprecated, use MuleMessage.getInboundProperty() instead.  This method will be removed in the next point release");
1788         return getInboundProperty(name, defaultValue);
1789     }
1790 
1791     /**
1792      * {@inheritDoc}
1793      */
1794     @Override
1795     @Deprecated
1796     public void setBooleanProperty(String name, boolean value)
1797     {
1798         assertAccess(WRITE);
1799         logger.warn("MuleMessage.setBooleanProperty() method is deprecated, use MuleMessage.setOutboundProperty() instead.  This method will be removed in the next point release");
1800         setOutboundProperty(name, value);
1801     }
1802 
1803     /**
1804      * {@inheritDoc}
1805      */
1806     @Override
1807     @Deprecated
1808     public void setIntProperty(String name, int value)
1809     {
1810         assertAccess(WRITE);
1811         logger.warn("MuleMessage.setIntProperty() method is deprecated, use MuleMessage.setOutboundProperty() instead.  This method will be removed in the next point release");
1812         setOutboundProperty(name, value);
1813     }
1814 
1815     /**
1816      * {@inheritDoc}
1817      */
1818     @Override
1819     @Deprecated
1820     public void setLongProperty(String name, long value)
1821     {
1822         assertAccess(WRITE);
1823         logger.warn("MuleMessage.setLongProperty() method is deprecated, use MuleMessage.setOutboundProperty() instead.  This method will be removed in the next point release");
1824         setOutboundProperty(name, value);
1825     }
1826 
1827     /**
1828      * {@inheritDoc}
1829      */
1830     @Override
1831     @Deprecated
1832     public void setDoubleProperty(String name, double value)
1833     {
1834         assertAccess(WRITE);
1835         logger.warn("MuleMessage.setDoubleProperty() method is deprecated, use MuleMessage.setOutboundProperty() instead.  This method will be removed in the next point release");
1836         setOutboundProperty(name, value);
1837     }
1838 
1839     /**
1840      * {@inheritDoc}
1841      */
1842     @Override
1843     @Deprecated
1844     public String getStringProperty(String name, String defaultValue)
1845     {
1846         assertAccess(READ);
1847         logger.warn("MuleMessage.getStringProperty() method is deprecated, use MuleMessage.getInboundProperty() instead.  This method will be removed in the next point release");
1848         return getInboundProperty(name, defaultValue);
1849     }
1850 
1851     /**
1852      * {@inheritDoc}
1853      */
1854     @Override
1855     @Deprecated
1856     public void setStringProperty(String name, String value)
1857     {
1858         assertAccess(WRITE);
1859         logger.warn("MuleMessage.setStringProperty() method is deprecated, use MuleMessage.setOutboundProperty() instead.  This method will be removed in the next point release");
1860         setOutboundProperty(name, value);
1861     }
1862 
1863     /**
1864      * Find property in one of the specified scopes, in order
1865      */
1866     @SuppressWarnings("unchecked")
1867     public <T> T findPropertyInSpecifiedScopes(String name, PropertyScope... scopesToSearch)
1868     {
1869         for (PropertyScope scope : scopesToSearch)
1870         {
1871             Object result = getProperty(name, scope);
1872             if (result != null)
1873             {
1874                 return (T) result;
1875             }
1876         }
1877         return null;
1878     }
1879 
1880     @Override
1881     public MuleMessage createInboundMessage() throws Exception
1882     {
1883         DefaultMuleMessage newMessage =  new DefaultMuleMessage(getPayload(), this, getMuleContext());
1884         copyToInbound(newMessage);
1885         return newMessage;
1886     }
1887 
1888     /**
1889      * copy outbound artifacts to inbound artifacts in the new message
1890      */
1891     protected void copyToInbound(DefaultMuleMessage newMessage) throws Exception
1892     {
1893         // Copy message, but put all outbound properties and attachments on inbound scope.
1894         // We ignore inbound and invocation scopes since the VM receiver needs to behave the
1895         // same way as any other receiver in Mule and would only receive inbound headers
1896         // and attachments
1897         Map<String, DataHandler> attachments = new HashMap<String, DataHandler>(3);
1898         for (String name : getOutboundAttachmentNames())
1899         {
1900             attachments.put(name, getOutboundAttachment(name));
1901         }
1902 
1903         Map<String, Object> newInboundProperties = new HashMap<String, Object>(3);
1904         for (String name : getOutboundPropertyNames())
1905         {
1906             newInboundProperties.put(name, getOutboundProperty(name));
1907         }
1908 
1909         newMessage.clearProperties(PropertyScope.INBOUND);
1910         newMessage.clearProperties(PropertyScope.INVOCATION);
1911         newMessage.clearProperties(PropertyScope.OUTBOUND);
1912 
1913         for (String s : newInboundProperties.keySet())
1914         {
1915             newMessage.setInboundProperty(s, newInboundProperties.get(s));
1916         }
1917 
1918         newMessage.inboundAttachments.clear();
1919         newMessage.outboundAttachments.clear();
1920 
1921         for (String s : attachments.keySet())
1922         {
1923             newMessage.addInboundAttachment(s, attachments.get(s));
1924         }
1925 
1926         newMessage.setCorrelationId(getCorrelationId());
1927         newMessage.setCorrelationGroupSize(getCorrelationGroupSize());
1928         newMessage.setCorrelationSequence(getCorrelationSequence());
1929         newMessage.setReplyTo(getReplyTo());
1930         newMessage.setEncoding(getEncoding());
1931     }
1932 }