View Javadoc

1   /*
2    * $Id: AbstractMessageTransformer.java 20813 2010-12-21 11:37:48Z 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      public Object transform(Object src, MuleEvent event) throws TransformerMessagingException
92      {
93          return transform(src, getEncoding(src), event);
94      }
95  
96      public final Object transform(Object src, String enc, MuleEvent event) throws TransformerMessagingException
97      {
98          DataType<?> sourceType = DataTypeFactory.create(src.getClass());
99          if (!isSourceDataTypeSupported(sourceType))
100         {
101             if (isIgnoreBadInput())
102             {
103                 logger.debug("Source type is incompatible with this transformer and property 'ignoreBadInput' is set to true, so the transformer chain will continue.");
104                 return src;
105             }
106             else
107             {
108                 Message msg = CoreMessages.transformOnObjectUnsupportedTypeOfEndpoint(getName(),
109                     src.getClass(), endpoint);
110                 /// FIXME
111                 throw new TransformerMessagingException(msg, event, this);
112             }
113         }
114         if (logger.isDebugEnabled())
115         {
116             logger.debug(String.format("Applying transformer %s (%s)", getName(), getClass().getName()));
117             logger.debug(String.format("Object before transform: %s", StringMessageUtils.toString(src)));
118         }
119 
120         MuleMessage message;
121         if (src instanceof MuleMessage)
122         {
123             message = (MuleMessage) src;
124         }
125         else if (muleContext.getConfiguration().isAutoWrapMessageAwareTransform())
126         {
127             message = new DefaultMuleMessage(src, muleContext);
128         }
129         else
130         {
131             if (event == null)
132             {
133                 throw new TransformerMessagingException(CoreMessages.noCurrentEventForTransformer(), event, this);
134             }
135             message = event.getMessage();
136             if (!message.getPayload().equals(src))
137             {
138                 throw new IllegalStateException("Transform payload does not match current event");
139             }
140         }
141 
142         Object result;
143         try
144         {
145             result = transformMessage(message, enc);
146         }
147         catch (TransformerException e)
148         {
149             throw new TransformerMessagingException(e.getI18nMessage(), event, this, e);
150         }
151 
152         if (result == null)
153         {
154             result = NullPayload.getInstance();
155         }
156 
157         if (logger.isDebugEnabled())
158         {
159             logger.debug(String.format("Object after transform: %s", StringMessageUtils.toString(result)));
160         }
161 
162         result = checkReturnClass(result, event);
163         return result;
164     }
165 
166     /**
167      * Check if the return class is supported by this transformer
168      */
169     protected Object checkReturnClass(Object object, MuleEvent event) throws TransformerMessagingException
170     {
171 
172         //Null is a valid return type
173         if(object==null || object instanceof NullPayload && isAllowNullReturn())
174         {
175             return object;
176         }
177 
178         if (returnType != null)
179         {
180             DataType<?> dt = DataTypeFactory.create(object.getClass());
181             if (!returnType.isCompatibleWith(dt))
182             {
183                 throw new TransformerMessagingException(
184                         CoreMessages.transformUnexpectedType(dt, returnType),
185                         event, this);
186             }
187         }
188 
189         if (logger.isDebugEnabled())
190         {
191             logger.debug("The transformed object is of expected type. Type is: " +
192                     ClassUtils.getSimpleName(object.getClass()));
193         }
194 
195         return object;
196     }
197 
198     /**
199      * Transform the message
200      */
201     public abstract Object transformMessage(MuleMessage message, String outputEncoding) throws TransformerException;
202 }