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