View Javadoc

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