View Javadoc

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