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.module.jca;
8   
9   import org.mule.module.jca.i18n.JcaMessages;
10  import org.mule.security.MuleCredentials;
11  
12  import java.io.PrintWriter;
13  import java.util.ArrayList;
14  import java.util.HashSet;
15  import java.util.Iterator;
16  import java.util.List;
17  import java.util.Set;
18  
19  import javax.resource.NotSupportedException;
20  import javax.resource.ResourceException;
21  import javax.resource.spi.ConnectionEvent;
22  import javax.resource.spi.ConnectionEventListener;
23  import javax.resource.spi.ConnectionRequestInfo;
24  import javax.resource.spi.ManagedConnection;
25  import javax.resource.spi.ManagedConnectionMetaData;
26  import javax.resource.spi.security.PasswordCredential;
27  import javax.security.auth.Subject;
28  import javax.transaction.xa.XAResource;
29  
30  /**
31   * <code>MuleManagedConnection</code> TODO
32   */
33  public class MuleManagedConnection implements ManagedConnection
34  {
35      private MuleManagedConnectionFactory mcf;
36      private List listeners = new ArrayList();
37      private Set connectionSet;
38      private PrintWriter logWriter;
39      private boolean destroyed;
40  
41      private PasswordCredential passCred;
42  
43      /**
44       * Constructor.
45       * 
46       * @param mcf the ManagedConnectionFactory that created this instance
47       * @param subject security context as JAAS subject
48       * @param cxRequestInfo ConnectionRequestInfo instance
49       * @throws javax.resource.ResourceException in case of any error
50       */
51  
52      MuleManagedConnection(MuleManagedConnectionFactory mcf,
53                            Subject subject,
54                            ConnectionRequestInfo cxRequestInfo) throws ResourceException
55      {
56          this.mcf = mcf;
57  
58          // Note: this will select the credential that matches this MC's MCF.
59          // The credential's MCF is set by the application server.
60          this.passCred = RaHelper.getPasswordCredential(mcf, subject, cxRequestInfo);
61  
62          connectionSet = new HashSet();
63      }
64  
65      /**
66       * Creates a new connection handle to the Mail Server represented by the
67       * ManagedConnection instance. This connection handle is used by the application
68       * code to refer to the underlying physical connection.
69       * 
70       * @param subject security context as JAAS subject
71       * @param connectionRequestInfo ConnectionRequestInfo instance
72       * @return Connection instance representing the connection handle
73       * @throws ResourceException if the method fails to get a connection
74       */
75  
76      public Object getConnection(Subject subject, ConnectionRequestInfo connectionRequestInfo)
77          throws ResourceException
78      {
79  
80          checkIfDestroyed();
81  
82          PasswordCredential pc = RaHelper.getPasswordCredential(mcf, subject, connectionRequestInfo);
83  
84          if (!passCred.equals(pc))
85          {
86              // TODO change the message, we are not dealing with an endpoint here
87              throw new javax.resource.spi.SecurityException(
88                  JcaMessages.authDeniedOnEndpoint(this).getMessage());
89          }
90  
91          String user;
92          String password;
93          MuleConnectionRequestInfo info = (MuleConnectionRequestInfo)connectionRequestInfo;
94  
95          user = info.getUserName();
96          password = info.getPassword();
97          if (user == null)
98          {
99              // Use default values
100             user = mcf.getUsername();
101             password = mcf.getPassword();
102         }
103         MuleCredentials creds = null;
104         if (user != null)
105         {
106             if (password == null)
107             {
108                 password = "";
109             }
110             creds = new MuleCredentials(user, password.toCharArray());
111         }
112 
113         // TODO Get muleContext from ResourceAdaptor somehow 
114         // (MULE-2916 MuleContext should not be a static singleton instance)
115         MuleConnection connection = new DefaultMuleConnection(this, null, creds);
116         addConnection(connection);
117         return connection;
118     }
119 
120     /**
121      * Destroys the physical connection.
122      * 
123      * @throws ResourceException if the method fails to destroy the connection
124      */
125 
126     public void destroy() throws ResourceException
127     {
128         if (destroyed)
129         {
130             return;
131         }
132         destroyed = true;
133 
134         invalidateConnections();
135     }
136 
137     /**
138      * Initiates a cleanup of the client-specific state maintained by a
139      * ManagedConnection instance. The cleanup should invalidate all connection
140      * handles created using this ManagedConnection instance.
141      * 
142      * @throws ResourceException if the cleanup fails
143      */
144 
145     public void cleanup() throws ResourceException
146     {
147         checkIfDestroyed();
148 
149         invalidateConnections();
150     }
151 
152     private void invalidateConnections()
153     {
154         Iterator it = connectionSet.iterator();
155         while (it.hasNext())
156         {
157             DefaultMuleConnection connection = (DefaultMuleConnection)it.next();
158             connection.invalidate();
159         }
160         connectionSet.clear();
161     }
162 
163     /**
164      * Used by the container to change the association of an application-level
165      * connection handle with a ManagedConnection instance. The container should find
166      * the right ManagedConnection instance and call the associateConnection method.
167      * 
168      * @param connection application-level connection handle
169      * @throws ResourceException if the attempt to change the association fails
170      */
171 
172     public void associateConnection(Object connection) throws ResourceException
173     {
174         checkIfDestroyed();
175 
176         if (connection instanceof MuleConnection)
177         {
178             MuleConnection cnn = (MuleConnection)connection;
179             cnn.associateConnection(this);
180         }
181         else
182         {
183             throw new IllegalStateException(
184                 JcaMessages.objectMarkedInvalid(DefaultMuleConnection.class.getName() + ": "
185                                 + (connection == null ? "null" : connection.getClass().getName())).toString());
186         }
187     }
188 
189     /**
190      * Adds a connection event listener to the ManagedConnection instance. The
191      * registered ConnectionEventListener instances are notified of connection close
192      * and error events as well as local-transaction-related events on the Managed
193      * Connection.
194      * 
195      * @param listener a new ConnectionEventListener to be registered
196      */
197 
198     public void addConnectionEventListener(ConnectionEventListener listener)
199     {
200         listeners.add(listener);
201     }
202 
203     /**
204      * Removes an already registered connection event listener from the
205      * ManagedConnection instance.
206      * 
207      * @param listener already registered connection event listener to be removed
208      */
209 
210     public void removeConnectionEventListener(ConnectionEventListener listener)
211     {
212         listeners.remove(listener);
213     }
214 
215     /**
216      * Returns a javax.transaction.xa.XAresource instance. An application server
217      * enlists this XAResource instance with the Transaction Manager if the
218      * ManagedConnection instance is being used in a JTA transaction that is being
219      * coordinated by the Transaction Manager. <p/> Because this implementation does
220      * not support transactions, the method throws an exception.
221      * 
222      * @return the XAResource instance
223      * @throws ResourceException if transactions are not supported
224      */
225     // TODO
226     public XAResource getXAResource() throws ResourceException
227     {
228         throw new NotSupportedException("getXAResource");
229     }
230 
231     /**
232      * Returns a javax.resource.spi.LocalTransaction instance. The LocalTransaction
233      * interface is used by the container to manage local transactions for a RM
234      * instance. <p/> Because this implementation does not support transactions, the
235      * method throws an exception.
236      * 
237      * @return javax.resource.spi.LocalTransaction instance
238      * @throws ResourceException if transactions are not supported
239      */
240 
241     public javax.resource.spi.LocalTransaction getLocalTransaction() throws ResourceException
242     {
243         throw new NotSupportedException("getLocalTransaction");
244     }
245 
246     /**
247      * Gets the metadata information for this connection's underlying EIS resource
248      * manager instance. The ManagedConnectionMetaData interface provides information
249      * about the underlying EIS instance associated with the ManagedConnection
250      * instance.
251      * 
252      * @return ManagedConnectionMetaData ManagedConnectionMetaData instance
253      * @throws ResourceException if the metadata cannot be retrieved
254      */
255 
256     public ManagedConnectionMetaData getMetaData() throws ResourceException
257     {
258         checkIfDestroyed();
259         return new MuleManagedConnectionMetaData(this);
260     }
261 
262     /**
263      * Sets the log writer for this ManagedConnection instance. The log writer is a
264      * character output stream to which all logging and tracing messages for this
265      * ManagedConnection instance will be printed.
266      * 
267      * @param out character output stream to be associated
268      * @throws ResourceException if the method fails
269      */
270 
271     public void setLogWriter(PrintWriter out) throws ResourceException
272     {
273         this.logWriter = out;
274     }
275 
276     /**
277      * Gets the log writer for this ManagedConnection instance.
278      * 
279      * @return the character output stream associated with this ManagedConnection
280      *         instance
281      * @throws ResourceException if the method fails
282      */
283 
284     public PrintWriter getLogWriter() throws ResourceException
285     {
286         return logWriter;
287     }
288 
289     /**
290      * Gets the user name of the user associated with the ManagedConnection instance.
291      * 
292      * @return the username for this connection
293      */
294 
295     public String getUsername()
296     {
297         if (passCred != null)
298         {
299             return passCred.getUserName();
300         }
301         else
302         {
303             return null;
304         }
305     }
306 
307     /**
308      * Gets the password for the user associated with the ManagedConnection instance.
309      * 
310      * @return the password for this connection
311      */
312 
313     public PasswordCredential getPasswordCredential()
314     {
315         return passCred;
316     }
317 
318     /**
319      * Associate connection handle with the physical connection.
320      * 
321      * @param connection connection handle
322      */
323 
324     public void addConnection(MuleConnection connection)
325     {
326         connectionSet.add(connection);
327     }
328 
329     /**
330      * Check validation of the physical connection.
331      * 
332      * @throws ResourceException if the connection has been destroyed
333      */
334 
335     private void checkIfDestroyed() throws ResourceException
336     {
337         if (destroyed)
338         {
339             throw new ResourceException(
340                 JcaMessages.objectIsDisposed("MuleManagedConnection").toString());
341         }
342     }
343 
344     /**
345      * Removes the associated connection handle from the connections set to the
346      * physical connection.
347      * 
348      * @param connection the connection handle
349      */
350 
351     public void removeConnection(MuleConnection connection)
352     {
353         connectionSet.remove(connection);
354     }
355 
356     /**
357      * Checks validation of the physical connection.
358      * 
359      * @return true if the connection has been destroyed; false otherwise
360      */
361 
362     boolean isDestroyed()
363     {
364         return destroyed;
365     }
366 
367     /**
368      * Returns the ManagedConnectionFactory that created this instance of
369      * ManagedConnection.
370      * 
371      * @return the ManagedConnectionFactory for this connection
372      */
373 
374     public MuleManagedConnectionFactory getManagedConnectionFactory()
375     {
376         return this.mcf;
377     }
378 
379     void fireBeginEvent()
380     {
381         ConnectionEvent event = new ConnectionEvent(MuleManagedConnection.this,
382             ConnectionEvent.LOCAL_TRANSACTION_STARTED);
383         Iterator iterator = listeners.iterator();
384         while (iterator.hasNext())
385         {
386             ConnectionEventListener l = (ConnectionEventListener)iterator.next();
387             l.localTransactionStarted(event);
388         }
389     }
390 
391     void fireCommitEvent()
392     {
393         ConnectionEvent event = new ConnectionEvent(MuleManagedConnection.this,
394             ConnectionEvent.LOCAL_TRANSACTION_COMMITTED);
395         Iterator iterator = listeners.iterator();
396         while (iterator.hasNext())
397         {
398             ConnectionEventListener l = (ConnectionEventListener)iterator.next();
399             l.localTransactionCommitted(event);
400         }
401     }
402 
403     void fireRollbackEvent()
404     {
405         ConnectionEvent event = new ConnectionEvent(MuleManagedConnection.this,
406             ConnectionEvent.LOCAL_TRANSACTION_ROLLEDBACK);
407         Iterator iterator = listeners.iterator();
408         while (iterator.hasNext())
409         {
410             ConnectionEventListener l = (ConnectionEventListener)iterator.next();
411             l.localTransactionRolledback(event);
412         }
413     }
414 
415     void fireCloseEvent(MuleConnection connection)
416     {
417         ConnectionEvent event = new ConnectionEvent(MuleManagedConnection.this,
418             ConnectionEvent.CONNECTION_CLOSED);
419         event.setConnectionHandle(connection);
420 
421         Iterator iterator = listeners.iterator();
422         while (iterator.hasNext())
423         {
424             ConnectionEventListener l = (ConnectionEventListener)iterator.next();
425             l.connectionClosed(event);
426         }
427     }
428 
429     void fireErrorOccurredEvent(Exception error)
430     {
431         ConnectionEvent event = new ConnectionEvent(MuleManagedConnection.this,
432             ConnectionEvent.CONNECTION_ERROR_OCCURRED, error);
433         Iterator iterator = listeners.iterator();
434         while (iterator.hasNext())
435         {
436             ConnectionEventListener l = (ConnectionEventListener)iterator.next();
437             l.connectionErrorOccurred(event);
438         }
439     }
440 
441 }