View Javadoc

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