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.transport.jms;
8   
9   import org.mule.api.MuleMessage;
10  import org.mule.api.context.notification.TransactionNotificationListener;
11  import org.mule.api.endpoint.InboundEndpoint;
12  import org.mule.api.transaction.Transaction;
13  import org.mule.api.transaction.TransactionConfig;
14  import org.mule.context.notification.TransactionNotification;
15  import org.mule.transaction.TransactionCoordination;
16  import org.mule.transport.AbstractMessageRequester;
17  import org.mule.transport.jms.filters.JmsSelectorFilter;
18  import org.mule.util.StringUtils;
19  
20  import javax.jms.Destination;
21  import javax.jms.Message;
22  import javax.jms.MessageConsumer;
23  import javax.jms.Session;
24  
25  /**
26   * <code>JmsMessageDispatcher</code> is responsible for dispatching messages to JMS
27   * destinations. All JMS semantics apply and settings such as replyTo and QoS
28   * properties are read from the event properties or defaults are used (according to
29   * the JMS specification)
30   */
31  public class JmsMessageRequester extends AbstractMessageRequester
32  {
33  
34      private JmsConnector connector;
35  
36      public JmsMessageRequester(InboundEndpoint endpoint)
37      {
38          super(endpoint);
39          this.connector = (JmsConnector) endpoint.getConnector();
40      }
41  
42      @Override
43      protected void doConnect() throws Exception
44      {
45          // template method
46      }
47  
48      @Override
49      protected void doDisconnect() throws Exception
50      {
51          // template method
52      }
53  
54      /**
55       * Make a specific request to the underlying transport
56       *
57       * @param timeout the maximum time the operation should block before returning.
58       *            The call should return immediately if there is data available. If
59       *            no data becomes available before the timeout elapses, null will be
60       *            returned
61       * @return the result of the request wrapped in a MuleMessage object. Null will be
62       *         returned if no data was avaialable
63       * @throws Exception if the call to the underlying protocal cuases an exception
64       */
65      @Override
66      protected MuleMessage doRequest(long timeout) throws Exception
67      {
68          Session session = null;
69          MessageConsumer consumer = null;
70          boolean cleanupListenerRegistered = false;
71  
72          try
73          {
74              final boolean topic = connector.getTopicResolver().isTopic(endpoint);
75  
76              JmsSupport support = connector.getJmsSupport();
77              final TransactionConfig transactionConfig = endpoint.getTransactionConfig();
78              final Transaction tx = TransactionCoordination.getInstance().getTransaction();
79              boolean transacted = transactionConfig != null && transactionConfig.isTransacted();
80  
81              session = connector.getSession(transacted, topic);
82  
83              if (transacted && !tx.isXA())
84              {
85                  // register a session close listener
86                  final Session finalSession = session;
87                  getConnector().getMuleContext().registerListener(new TransactionNotificationListener<TransactionNotification>()
88                  {
89                      public void onNotification(TransactionNotification txNotification)
90                      {
91                          final int txAction = txNotification.getAction();
92                          final String txId = txNotification.getTransactionStringId();
93                          if ((txAction == TransactionNotification.TRANSACTION_COMMITTED || txAction == TransactionNotification.TRANSACTION_ROLLEDBACK) &&
94                              txId.equals(tx.getId())) {
95                              connector.closeQuietly(finalSession);
96                          }
97                      }
98                  }, tx.getId());
99  
100                 cleanupListenerRegistered = true;
101             }
102 
103             Destination dest = support.createDestination(session, endpoint);
104 
105             // Extract jms selector
106             String selector = null;
107             if (endpoint.getFilter() != null && endpoint.getFilter() instanceof JmsSelectorFilter)
108             {
109                 final String expressionTemplate = ((JmsSelectorFilter) endpoint.getFilter()).getExpression();
110                 if (StringUtils.isNotBlank(expressionTemplate))
111                 {
112                     selector = connector.getMuleContext().getExpressionManager().parse(expressionTemplate, null);
113                 }
114             }
115             else if (endpoint.getProperties() != null)
116             {
117                 // still allow the selector to be set as a property on the endpoint
118                 // to be backward compatable
119                 final String expressionTemplate = (String) endpoint.getProperty(JmsConstants.JMS_SELECTOR_PROPERTY);
120                 if (StringUtils.isNotBlank(expressionTemplate))
121                 {
122                     selector = connector.getMuleContext().getExpressionManager().parse(expressionTemplate, null);
123                 }
124             }
125             String tempDurable = (String) endpoint.getProperties().get(JmsConstants.DURABLE_PROPERTY);
126             boolean durable = connector.isDurable();
127             if (tempDurable != null)
128             {
129                 durable = Boolean.valueOf(tempDurable);
130             }
131 
132             // Get the durable subscriber name if there is one
133             String durableName = (String) endpoint.getProperties().get(JmsConstants.DURABLE_NAME_PROPERTY);
134             if (durableName == null && durable && topic)
135             {
136                 durableName = "mule." + connector.getName() + "." + endpoint.getEndpointURI().getAddress();
137                 if (logger.isDebugEnabled())
138                 {
139                     logger.debug("Jms Connector for this receiver is durable but no durable name has been specified. Defaulting to: "
140                              + durableName);
141                 }
142             }
143 
144             // Create consumer
145             consumer = support.createConsumer(session, dest, selector, connector.isNoLocal(), durableName,
146                 topic, endpoint);
147 
148             Message message;
149 
150             if (timeout == JmsMessageDispatcher.RECEIVE_NO_WAIT)
151             {
152                 message = consumer.receiveNoWait();
153             }
154             else if (timeout == JmsMessageDispatcher.RECEIVE_WAIT_INDEFINITELY)
155             {
156                 message = consumer.receive();
157             }
158             else
159             {
160                 message = consumer.receive(timeout);
161             }
162 
163             if (message == null)
164             {
165                 return null;
166             }
167 
168             message = connector.preProcessMessage(message, session);
169             return createMuleMessage(message, endpoint.getEncoding());
170         }
171         finally
172         {
173             if (!cleanupListenerRegistered)
174             {
175                 connector.closeQuietly(consumer);
176                 connector.closeSessionIfNoTransactionActive(session);
177             }
178         }
179     }
180 
181     @Override
182     protected void doDispose()
183     {
184         // template method
185     }
186 
187 }