View Javadoc

1   /*
2    * $Id: AbstractJmsTransformer.java 10489 2008-01-23 17:53:38Z dfeist $
3    * --------------------------------------------------------------------------------------
4    * Copyright (c) MuleSource, Inc.  All rights reserved.  http://www.mulesource.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.transport.jms.transformers;
12  
13  import org.mule.api.MuleMessage;
14  import org.mule.api.config.MuleProperties;
15  import org.mule.api.endpoint.ImmutableEndpoint;
16  import org.mule.api.transaction.Transaction;
17  import org.mule.api.transformer.DiscoverableTransformer;
18  import org.mule.api.transformer.TransformerException;
19  import org.mule.api.transport.Connector;
20  import org.mule.transaction.TransactionCoordination;
21  import org.mule.transformer.AbstractMessageAwareTransformer;
22  import org.mule.transport.jms.JmsConnector;
23  import org.mule.transport.jms.JmsConstants;
24  import org.mule.transport.jms.JmsMessageUtils;
25  import org.mule.util.ClassUtils;
26  
27  import java.util.Iterator;
28  
29  import javax.jms.Destination;
30  import javax.jms.JMSException;
31  import javax.jms.Message;
32  import javax.jms.Session;
33  
34  /**
35   * <code>AbstractJmsTransformer</code> is an abstract class that should be used for
36   * all transformers where a JMS message will be the transformed or transformee
37   * object. It provides services for compressing and uncompressing messages.
38   */
39  
40  public abstract class AbstractJmsTransformer extends AbstractMessageAwareTransformer implements DiscoverableTransformer
41  {
42  
43      private int priorityWeighting = DiscoverableTransformer.DEFAULT_PRIORITY_WEIGHTING;
44  
45      public AbstractJmsTransformer()
46      {
47          super();
48      }
49  
50      protected Message transformToMessage(MuleMessage message) throws TransformerException
51      {
52          Session session = null;
53          try
54          {
55              Message result;
56  
57              Object src = message.getPayload();
58              if (src instanceof Message)
59              {
60                  result = (Message) src;
61                  result.clearProperties();
62              }
63              else
64              {
65                  session = this.getSession();
66                  result = JmsMessageUtils.toMessage(src, session);
67              }
68              this.setJmsProperties(message, result);
69  
70              return result;
71          }
72          catch (TransformerException tex)
73          {
74              // rethrow
75              throw tex;
76          }
77          catch (Exception e)
78          {
79              throw new TransformerException(this, e);
80          }
81          finally
82          {
83              /*
84                  session.getTransacted() would be easier in most cases, but e.g. in Weblogic 8.x
85                  Java EE apps there could be some quirks, see http://forums.bea.com/thread.jspa?threadID=200007643
86                  to get a picture.
87  
88                  Though JmsTransaction has this session.getTransacted() validation already, we're taking extra precautions
89                  to cover XA cases and potentially to make up for a configuration error. E.g. omitting transaction
90                  configuration from an outbound endpoint or router. Note, XA support in Mule will deliberately
91                  fail with fanfares to signal this case, which is really a user error.
92                */
93  
94              if (session != null && endpoint != null) // endpoint can be null in some programmatic tests only in fact
95              {
96                  Transaction muleTx = TransactionCoordination.getInstance().getTransaction();
97  
98                  final JmsConnector connector = (JmsConnector) endpoint.getConnector();
99                  if (muleTx == null)
100                 {
101                     if (logger.isDebugEnabled())
102                     {
103                         logger.debug("Closing non-transacted jms session: " + session);
104                     }
105                     connector.closeQuietly(session);
106                 }
107                 else if (!muleTx.hasResource(connector.getConnection()))
108                 {
109                     // this is some other session from another connection, don't let it leak
110                     if (logger.isDebugEnabled())
111                     {
112                         logger.debug("Closing an orphaned, but transacted jms session: " + session +
113                                 ", transaction: " + muleTx);
114                     }
115                     connector.closeQuietly(session);
116                 }
117             }
118             // aggressively killing any session refs
119             session = null;
120         }
121     }
122 
123     protected Object transformFromMessage(Message source) throws TransformerException
124     {
125         try
126         {
127             if (logger.isDebugEnabled())
128             {
129                 logger.debug("Message type received is: " +
130                         ClassUtils.getSimpleName(source.getClass()));
131             }
132 
133             // Try to figure out our endpoint's JMS Specification and fall back to
134             // 1.0.2 if none is set.
135             String jmsSpec = JmsConstants.JMS_SPECIFICATION_102B;
136             ImmutableEndpoint endpoint = this.getEndpoint();
137             if (endpoint != null)
138             {
139                 Connector connector = endpoint.getConnector();
140                 if (connector instanceof JmsConnector)
141                 {
142                     jmsSpec = ((JmsConnector) connector).getSpecification();
143                 }
144             }
145 
146             return JmsMessageUtils.toObject(source, jmsSpec);
147         }
148         catch (Exception e)
149         {
150             throw new TransformerException(this, e);
151         }
152     }
153 
154     protected void setJmsProperties(MuleMessage umoMessage, Message msg) throws JMSException
155     {
156         for (Iterator iterator = umoMessage.getPropertyNames().iterator(); iterator.hasNext();)
157         {
158             String key = iterator.next().toString();
159 
160             if (!JmsConstants.JMS_PROPERTY_NAMES.contains(key))
161             {
162                 Object value = umoMessage.getProperty(key);
163 
164                 if (MuleProperties.MULE_CORRELATION_ID_PROPERTY.equals(key))
165                 {
166                     msg.setJMSCorrelationID(umoMessage.getCorrelationId());
167                 }
168 
169                 // We dont want to set the ReplyTo property again as it will be set
170                 // using JMSReplyTo
171                 if (!(MuleProperties.MULE_REPLY_TO_PROPERTY.equals(key) && value instanceof Destination))
172                 {
173                     // sanitize key as JMS header
174                     key = JmsMessageUtils.encodeHeader(key);
175 
176                     try
177                     {
178                         msg.setObjectProperty(key, value);
179                     }
180                     catch (JMSException e)
181                     {
182                         // Various JMS servers have slightly different rules to what
183                         // can be set as an object property on the message; therefore
184                         // we have to take a hit n' hope approach
185                         if (logger.isDebugEnabled())
186                         {
187                             logger.debug("Unable to set property '" + key + "' of type "
188                                     + ClassUtils.getSimpleName(value.getClass())
189                                     + "': " + e.getMessage());
190                         }
191                     }
192                 }
193             }
194         }
195     }
196 
197     protected Session getSession() throws TransformerException, JMSException
198     {
199         if (endpoint != null)
200         {
201             return ((JmsConnector) endpoint.getConnector()).getSession(endpoint);
202         }
203         else
204         {
205             throw new TransformerException(this, new IllegalStateException(
206                     "This transformer needs a valid endpoint"));
207         }
208     }
209 
210     public int getPriorityWeighting()
211     {
212         return priorityWeighting;
213     }
214 
215     public void setPriorityWeighting(int priorityWeighting)
216     {
217         this.priorityWeighting = priorityWeighting;
218     }
219 }