View Javadoc

1   /*
2    * $Id: OracleJmsSupport.java 7963 2007-08-21 08:53:15Z dirk.olmes $
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.oracle.jms;
12  
13  import org.mule.providers.jms.Jms102bSupport;
14  import org.mule.providers.jms.JmsConnector;
15  import org.mule.util.ClassUtils;
16  
17  import java.util.Map;
18  
19  import javax.jms.Connection;
20  import javax.jms.ConnectionFactory;
21  import javax.jms.Destination;
22  import javax.jms.JMSException;
23  import javax.jms.MessageConsumer;
24  import javax.jms.Queue;
25  import javax.jms.QueueSession;
26  import javax.jms.Session;
27  import javax.jms.Topic;
28  import javax.jms.TopicSession;
29  import javax.naming.Context;
30  
31  import oracle.jms.AQjmsSession;
32  
33  /**
34   * Extends the standard Mule JMS Provider with functionality specific to Oracle's JMS
35   * implementation based on Advanced Queueing (Oracle AQ). Oracle 9i supports the JMS
36   * 1.0.2b specification while Oracle 10g supports JMS 1.1
37   * 
38   * @see OracleJmsConnector
39   * @see org.mule.providers.jms.Jms102bSupport
40   * @see <a href="http://otn.oracle.com/pls/db102/">Streams Advanced Queuing</a>
41   * @see <a
42   *      href="http://www.lc.leidenuniv.nl/awcourse/oracle/appdev.920/a96587/jcreate.htm#103729">Oracle9i
43   *      J2EE Compliance</a>
44   */
45  public class OracleJmsSupport extends Jms102bSupport
46  {
47  
48      /**
49       * Since we can't access the endpoint's properties directly from the scope of
50       * this class, we save a copy of the properties in this local variable for easy
51       * reference.
52       */
53      private Map endpointProperties;
54  
55      public OracleJmsSupport(JmsConnector connector,
56                              Context context,
57                              boolean jndiDestinations,
58                              boolean forceJndiDestinations)
59      {
60          super(connector, context, jndiDestinations, forceJndiDestinations);
61      }
62  
63      /**
64       * Returns an OracleJmsConnection to masquerade the fact that there might be
65       * several javax.jms.Connections open (one per session).
66       * 
67       * @see OracleJmsConnection
68       */
69      public Connection createConnection(ConnectionFactory connectionFactory) throws JMSException
70      {
71          return createConnection(connectionFactory, /* username */null, /* password */null);
72      }
73  
74      /**
75       * Returns an OracleJmsConnection to masquerade the fact that there might be
76       * several javax.jms.Connections open (one per session).
77       * 
78       * @see OracleJmsConnection
79       */
80      public javax.jms.Connection createConnection(ConnectionFactory connectionFactory,
81                                                   String username,
82                                                   String password) throws JMSException
83      {
84          return new OracleJmsConnection((OracleJmsConnector) connector);
85      }
86  
87      /**
88       * In order to receive messages from a queue whose payload is an ADT (Oracle
89       * Advanced Data Type), we must pass the payload factory as a parameter when
90       * creating the receiver/subscriber.
91       * 
92       * @see OracleJmsConnector#PAYLOADFACTORY_PROPERTY
93       */
94      public MessageConsumer createConsumer(Session session,
95                                            Destination destination,
96                                            String messageSelector,
97                                            boolean noLocal,
98                                            String durableName,
99                                            boolean topic) throws JMSException
100     {
101 
102         Object payloadFactory = getPayloadFactory();
103         if (payloadFactory == null)
104         {
105             return super.createConsumer(session, destination, messageSelector, noLocal, durableName, topic);
106         }
107         else
108         {
109             if (topic && session instanceof TopicSession)
110             {
111                 if (durableName == null)
112                 {
113                     return ((AQjmsSession) session).createSubscriber((Topic) destination, messageSelector,
114                         noLocal);
115                 }
116                 else
117                 {
118                     return ((AQjmsSession) session).createDurableSubscriber((Topic) destination,
119                         durableName, messageSelector, noLocal, payloadFactory);
120                 }
121             }
122             else if (session instanceof QueueSession)
123             {
124                 if (messageSelector != null)
125                 {
126                     return ((AQjmsSession) session).createReceiver((Queue) destination, messageSelector,
127                         payloadFactory);
128                 }
129                 else
130                 {
131                     return ((AQjmsSession) session).createReceiver((Queue) destination, payloadFactory);
132                 }
133             }
134             else
135             {
136                 throw new IllegalArgumentException("Session and domain type do not match");
137             }
138         }
139     }
140 
141     /**
142      * The standard Oracle JMS classes ({@code oracle.jms}) do not support dynamic
143      * (i.e., run-time) creation of queues. This is only possible through the
144      * (non-standard) administrative classes ({@code oracle.AQ}). Therefore this
145      * method, which calls {@code AQjmsSession.createQueue(name)} or
146      * {@code AQjmsSession.createTopic(name)} will inevitably fail. The failure
147      * <i>should</i> produce a {@code JMSException} but for some reason it doesn't
148      * (maybe an Oracle bug) and just returns null. In this case, we generate the
149      * appropriate exception.
150      */
151     public Destination createDestination(Session session, String name, boolean topic) throws JMSException
152     {
153         Destination dest = super.createDestination(session, name, topic);
154         if (dest != null)
155         {
156             return dest;
157         }
158         else
159         {
160             throw new JMSException(
161                     "Oracle JMS was unable to bind to the "
162                             + (topic ? "topic" : "queue")
163                             + ": "
164                             + name
165                             + " but gives no exception nor error message to explain why (that's what you get for using proprietary software...)");
166         }
167     }
168 
169     /**
170      * The standard Oracle JMS classes ({@code oracle.jms}) do not support dynamic
171      * (i.e., run-time) creation of queues. This is only possible through the
172      * (non-standard) administrative classes ({@code oracle.AQ}). Therefore this
173      * method, which calls {@code AQjmsSession.createQueue(name)} or
174      * {@code AQjmsSession.createTopic(name)} will inevitably fail. The failure
175      * <i>should</i> produce a {@code JMSException} but for some reason it doesn't
176      * (maybe an Oracle bug) and just returns null. In this case, we generate the
177      * appropriate exception.
178      */
179     public Destination createTemporaryDestination(Session session, boolean topic) throws JMSException
180     {
181         Destination dest = super.createTemporaryDestination(session, topic);
182         if (dest != null)
183         {
184             return dest;
185         }
186         else
187         {
188             throw new JMSException("Unable to create temporary " + (topic ? "topic" : "queue"));
189         }
190     }
191 
192     /**
193      * Get the payload factory class, if defined, from the connector or endpoint's
194      * properties.
195      * 
196      * @see OracleJmsConnector#PAYLOADFACTORY_PROPERTY
197      */
198     public Object getPayloadFactory() throws JMSException
199     {
200 
201         // Get the global property set on the connector, if any.
202         String payloadFactoryClass = ((OracleJmsConnector) connector).getPayloadFactory();
203 
204         // If the property has been set for this endpoint, it overrides the global
205         // setting.
206         if ((endpointProperties != null)
207             && (endpointProperties.get(OracleJmsConnector.PAYLOADFACTORY_PROPERTY) != null))
208         {
209             payloadFactoryClass = (String) endpointProperties.get(OracleJmsConnector.PAYLOADFACTORY_PROPERTY);
210         }
211 
212         Object payloadFactory = null;
213         if (payloadFactoryClass != null)
214         {
215             Throwable ex = null;
216             try
217             {
218                 // TODO ClassUtils call is more suitable here
219                 payloadFactory = ClassUtils.loadClass(payloadFactoryClass, this.getClass()).newInstance();
220             }
221             catch (ClassNotFoundException e)
222             {
223                 ex = e;
224             }
225             catch (IllegalAccessException e)
226             {
227                 ex = e;
228             }
229             catch (InstantiationException e)
230             {
231                 ex = e;
232             }
233             if (ex != null)
234             {
235                 throw new JMSException("Unable to instantiate payload factory class " + payloadFactoryClass
236                         + ": " + ex.getMessage());
237             }
238         }
239         return payloadFactory;
240     }
241 
242     public Map getEndpointProperties()
243     {
244         return endpointProperties;
245     }
246 
247     public void setEndpointProperties(Map endpointProperties)
248     {
249         this.endpointProperties = endpointProperties;
250     }
251 
252 }