View Javadoc

1   /*
2    * $Id: AbstractMessageTransformer.java 19250 2010-08-30 16:53:14Z dirk.olmes $
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.transformer;
12  
13  import org.mule.DefaultMuleMessage;
14  import org.mule.api.MuleEvent;
15  import org.mule.api.MuleMessage;
16  import org.mule.api.transformer.DataType;
17  import org.mule.api.transformer.MessageTransformer;
18  import org.mule.api.transformer.TransformerException;
19  import org.mule.api.transformer.TransformerMessagingException;
20  import org.mule.config.i18n.CoreMessages;
21  import org.mule.config.i18n.Message;
22  import org.mule.transformer.types.DataTypeFactory;
23  import org.mule.transport.NullPayload;
24  import org.mule.util.ClassUtils;
25  import org.mule.util.StringMessageUtils;
26  
27  /**
28   * <code>AbstractMessageTransformer</code> is a transformer that has a reference
29   * to the current message. This message can be used to obtain properties associated
30   * with the current message which are useful to the transform. Note that when part of a
31   * transform chain, the MuleMessage payload reflects the pre-transform message state,
32   * unless there is no current event for this thread, then the message will be a new
33   * DefaultMuleMessage with the src as its payload. Transformers should always work on the
34   * src object not the message payload.
35   *
36   * @see org.mule.api.MuleMessage
37   * @see org.mule.DefaultMuleMessage
38   */
39  
40  public abstract class AbstractMessageTransformer extends AbstractTransformer implements MessageTransformer
41  {
42      /**
43       * @param dataType the type to check against
44       * @param exactMatch if set to true, this method will look for an exact match to
45       *            the data type, if false it will look for a compatible data type.
46       * @return whether the data type is supported
47       */
48      @Override
49      public boolean isSourceDataTypeSupported(DataType<?> dataType, boolean exactMatch)
50      {
51          //TODO RM* This is a bit of hack since we could just register MuleMessage as a supportedType, but this has some
52          //funny behaviour in certain ObjectToXml transformers
53          return (super.isSourceDataTypeSupported(dataType, exactMatch) || MuleMessage.class.isAssignableFrom(dataType.getType()));
54      }
55  
56      /**
57       * Perform a non-message aware transform. This should never be called
58       */
59      @Override
60      public final Object doTransform(Object src, String enc) throws TransformerException
61      {
62          throw new UnsupportedOperationException();
63      }
64  
65      /**
66       * Transform the message with no event specified.
67       */
68      @Override
69      public final Object transform(Object src, String enc) throws TransformerException
70      {
71          try
72          {
73              return transform(src, enc, null);
74          }
75          catch (TransformerMessagingException e)
76          {
77              // Try to avoid double-wrapping
78              Throwable cause = e.getCause();
79              if (cause instanceof TransformerException)
80              {
81                  TransformerException te = (TransformerException) cause;
82                  if (te.getTransformer() == this)
83                  {
84                      throw te;
85                  }
86              }
87              throw new TransformerException(e.getI18nMessage(), this, e);
88          }
89      }
90  
91      /**
92       * transform the specified message
93       * @param src the data to transform
94       * @param event the event currently being processed
95       * @return
96       * @throws TransformerMessagingException
97       */
98      public Object transform(Object src, MuleEvent event) throws TransformerMessagingException
99      {
100         return transform(src, getEncoding(src), event);
101     }
102 
103     /**
104      * transform the specified message
105      * @param src the data to transform
106      * @param enc
107      * @param event the event currently being processed
108      * @return
109      * @throws TransformerMessagingException
110      */
111     public final Object transform(Object src, String enc, MuleEvent event) throws TransformerMessagingException
112     {
113         DataType<?> sourceType = DataTypeFactory.create(src.getClass());
114         if (!isSourceDataTypeSupported(sourceType))
115         {
116             if (isIgnoreBadInput())
117             {
118                 logger.debug("Source type is incompatible with this transformer and property 'ignoreBadInput' is set to true, so the transformer chain will continue.");
119                 return src;
120             }
121             else
122             {
123                 Message msg = CoreMessages.transformOnObjectUnsupportedTypeOfEndpoint(getName(),
124                     src.getClass(), endpoint);
125                 /// FIXME
126                 throw new TransformerMessagingException(msg, event, this);
127             }
128         }
129         if (logger.isDebugEnabled())
130         {
131             logger.debug(String.format("Applying transformer %s (%s)", getName(), getClass().getName()));
132             logger.debug(String.format("Object before transform: %s", StringMessageUtils.toString(src)));
133         }
134 
135         MuleMessage message;
136         if (src instanceof MuleMessage)
137         {
138             message = (MuleMessage) src;
139         }
140         else if (muleContext.getConfiguration().isAutoWrapMessageAwareTransform())
141         {
142             message = new DefaultMuleMessage(src, muleContext);
143         }
144         else
145         {
146             if (event == null)
147             {
148                 throw new TransformerMessagingException(CoreMessages.noCurrentEventForTransformer(), event, this);
149             }
150             message = event.getMessage();
151             if (!message.getPayload().equals(src))
152             {
153                 throw new IllegalStateException("Transform payload does not match current event");
154             }
155         }
156 
157         Object result;
158         try
159         {
160             result = transformMessage(message, enc);
161         }
162         catch (TransformerException e)
163         {
164             throw new TransformerMessagingException(e.getI18nMessage(), event, this, e);
165         }
166 
167         if (result == null)
168         {
169             result = NullPayload.getInstance();
170         }
171 
172         if (logger.isDebugEnabled())
173         {
174             logger.debug(String.format("Object after transform: %s", StringMessageUtils.toString(result)));
175         }
176 
177         result = checkReturnClass(result, event);
178         return result;
179     }
180 
181     /**
182      * Check if the return class is supported by this transformer
183      * @param object
184      * @param event
185      * @return
186      * @throws TransformerMessagingException
187      */
188     protected Object checkReturnClass(Object object, MuleEvent event) throws TransformerMessagingException
189     {
190 
191         //Null is a valid return type
192         if(object==null || object instanceof NullPayload && isAllowNullReturn())
193         {
194             return object;
195         }
196 
197         if (returnType != null)
198         {
199             DataType<?> dt = DataTypeFactory.create(object.getClass());
200             if (!returnType.isCompatibleWith(dt))
201             {
202                 throw new TransformerMessagingException(
203                         CoreMessages.transformUnexpectedType(dt, returnType),
204                         event, this);
205             }
206         }
207 
208         if (logger.isDebugEnabled())
209         {
210             logger.debug("The transformed object is of expected type. Type is: " +
211                     ClassUtils.getSimpleName(object.getClass()));
212         }
213 
214         return object;
215     }
216 
217     /**
218      * Transform the message
219      * @param message
220      * @param outputEncoding
221      * @return
222      * @throws TransformerMessagingException
223      */
224     public abstract Object transformMessage(MuleMessage message, String outputEncoding) throws TransformerException;
225 }