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