1 /*
2 * JBoss, Home of Professional Open Source.
3 * Copyright 2006, Red Hat Middleware LLC, and individual contributors
4 * as indicated by the @author tags. See the copyright.txt file in the
5 * distribution for a full listing of individual contributors.
6 *
7 * This is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU Lesser General Public License as
9 * published by the Free Software Foundation; either version 2.1 of
10 * the License, or (at your option) any later version.
11 *
12 * This software is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this software; if not, write to the Free
19 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
20 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
21 */
22 package org.jboss.resource.connectionmanager;
23
24 import java.io.PrintWriter;
25 import java.io.Serializable;
26 import java.util.Collection;
27 import java.util.HashMap;
28 import java.util.HashSet;
29 import java.util.Iterator;
30 import java.util.LinkedList;
31 import java.util.List;
32 import java.util.Map;
33 import java.util.Set;
34
35 import javax.management.MBeanNotificationInfo;
36 import javax.management.MBeanServer;
37 import javax.management.Notification;
38 import javax.management.ObjectName;
39 import javax.resource.ResourceException;
40 import javax.resource.spi.ConnectionEvent;
41 import javax.resource.spi.ConnectionManager;
42 import javax.resource.spi.ConnectionRequestInfo;
43 import javax.resource.spi.ManagedConnection;
44 import javax.resource.spi.ManagedConnectionFactory;
45 import javax.security.auth.Subject;
46 import javax.transaction.RollbackException;
47 import javax.transaction.SystemException;
48 import javax.transaction.Transaction;
49 import javax.transaction.TransactionManager;
50
51 import org.jboss.deployers.spi.DeploymentException;
52 import org.jboss.logging.Logger;
53 import org.jboss.logging.util.LoggerPluginWriter;
54 import org.jboss.mx.util.JMXExceptionDecoder;
55 import org.jboss.mx.util.MBeanServerLocator;
56 import org.jboss.resource.JBossResourceException;
57 import org.jboss.security.SubjectFactory;
58 import org.jboss.system.ServiceMBeanSupport;
59 import org.jboss.tm.TransactionTimeoutConfiguration;
60 import org.jboss.util.NestedRuntimeException;
61 import org.jboss.util.NotImplementedException;
62
63 /**
64 * The BaseConnectionManager2 is an abstract base class for JBoss ConnectionManager
65 * implementations. It includes functionality to obtain managed connections from
66 * a ManagedConnectionPool mbean, find the Subject from a SubjectSecurityDomain,
67 * and interact with the CachedConnectionManager for connections held over
68 * transaction and method boundaries. Important mbean references are to a
69 * ManagedConnectionPool supplier (typically a JBossManagedConnectionPool), and a
70 * RARDeployment representing the ManagedConnectionFactory.
71 *
72 *
73 * @author <a href="mailto:d_jencks@users.sourceforge.net">David Jencks</a>
74 * @author <a href="mailto:E.Guib@ceyoniq.com">Erwin Guib</a>
75 * @author <a href="mailto:adrian@jboss.org">Adrian Brock</a>
76 * @author <a href="weston.price@jboss.com">Weston Price</a>
77 * @author Anil.Saldhana@redhat.com
78 *
79 * @version $Revision: 73692 $
80 */
81 @SuppressWarnings("unchecked")
82 public abstract class BaseConnectionManager2 extends ServiceMBeanSupport
83 implements
84 BaseConnectionManager2MBean,
85 ConnectionCacheListener,
86 ConnectionListenerFactory,
87 TransactionTimeoutConfiguration,
88 JTATransactionChecker
89 {
90 /**
91 * Note that this copy has a trailing / unlike the original in
92 * JaasSecurityManagerService.
93 */
94 private static final String SECURITY_MGR_PATH = "java:/jaas/";
95
96 public static final String STOPPING_NOTIFICATION = "jboss.jca.connectionmanagerstopping";
97
98 protected ObjectName managedConnectionPoolName;
99
100 protected ManagedConnectionPool poolingStrategy;
101
102 protected String jndiName;
103
104 protected String securityDomainJndiName;
105
106 protected SubjectFactory subjectFactory;
107
108 protected ObjectName jaasSecurityManagerService;
109
110 protected ObjectName ccmName;
111
112 protected CachedConnectionManager ccm;
113
114 protected boolean trace;
115
116 /**
117 * Rethrow a throwable as resource exception
118 *
119 * @deprecated use JBossResourceException.rethrowAsResourceException
120 */
121 protected static void rethrowAsResourceException(String message, Throwable t) throws ResourceException
122 {
123 JBossResourceException.rethrowAsResourceException(message, t);
124 }
125
126 /**
127 * Default BaseConnectionManager2 managed constructor for use by subclass mbeans.
128 */
129 public BaseConnectionManager2()
130 {
131 super();
132 trace = log.isTraceEnabled();
133 }
134
135 /**
136 * Creates a new <code>BaseConnectionManager2</code> instance.
137 * for TESTING ONLY! not a managed operation.
138 * @param ccm a <code>CachedConnectionManager</code> value
139 * @param poolingStrategy a <code>ManagedConnectionPool</code> value
140 */
141 public BaseConnectionManager2(CachedConnectionManager ccm, ManagedConnectionPool poolingStrategy)
142 {
143 super();
144 this.ccm = ccm;
145 this.poolingStrategy = poolingStrategy;
146 trace = log.isTraceEnabled();
147 }
148
149 /**
150 * For testing
151 */
152 public ManagedConnectionPool getPoolingStrategy()
153 {
154 return poolingStrategy;
155 }
156
157 public String getJndiName()
158 {
159 return jndiName;
160 }
161
162 public void setJndiName(String jndiName)
163 {
164 this.jndiName = jndiName;
165 }
166
167 public ObjectName getManagedConnectionPool()
168 {
169 return managedConnectionPoolName;
170 }
171
172 public void setManagedConnectionPool(ObjectName newManagedConnectionPool)
173 {
174 this.managedConnectionPoolName = newManagedConnectionPool;
175 }
176
177 public void setCachedConnectionManager(ObjectName ccmName)
178 {
179 this.ccmName = ccmName;
180 }
181
182 public ObjectName getCachedConnectionManager()
183 {
184 return ccmName;
185 }
186
187 public void setSecurityDomainJndiName(String securityDomainJndiName)
188 {
189 if (securityDomainJndiName != null && securityDomainJndiName.startsWith(SECURITY_MGR_PATH))
190 {
191 securityDomainJndiName = securityDomainJndiName.substring(SECURITY_MGR_PATH.length());
192 log.warn("WARNING: UPDATE YOUR SecurityDomainJndiName! REMOVE " + SECURITY_MGR_PATH);
193 }
194 this.securityDomainJndiName = securityDomainJndiName;
195 }
196
197 public String getSecurityDomainJndiName()
198 {
199 return securityDomainJndiName;
200 }
201
202 public SubjectFactory getSubjectFactory()
203 {
204 return subjectFactory;
205 }
206
207 public void setSubjectFactory(SubjectFactory subjectFactory)
208 {
209 this.subjectFactory = subjectFactory;
210 }
211
212 /**
213 * @deprecated
214 */
215 public ObjectName getJaasSecurityManagerService()
216 {
217 return this.jaasSecurityManagerService;
218 }
219
220 /**
221 * @deprecated Maintained for legacy
222 */
223 public void setJaasSecurityManagerService(final ObjectName jaasSecurityManagerService)
224 {
225 this.jaasSecurityManagerService = jaasSecurityManagerService;
226 }
227
228 public ManagedConnectionFactory getManagedConnectionFactory()
229 {
230 return poolingStrategy.getManagedConnectionFactory();
231 }
232
233 public BaseConnectionManager2 getInstance()
234 {
235 return this;
236 }
237
238 public long getTimeLeftBeforeTransactionTimeout(boolean errorRollback) throws RollbackException
239 {
240 return -1;
241 }
242
243 public int getTransactionTimeout() throws SystemException
244 {
245 throw new NotImplementedException("NYI: getTransactionTimeout()");
246 }
247
248 public void checkTransactionActive() throws RollbackException, SystemException
249 {
250 // Nothing
251 }
252
253 //ServiceMBeanSupport
254
255 protected void startService() throws Exception
256 {
257 try
258 {
259 ccm = (CachedConnectionManager) server.getAttribute(ccmName, "Instance");
260 }
261 catch (Exception e)
262 {
263 JMXExceptionDecoder.rethrow(e);
264 }
265
266 if (ccm == null)
267 throw new DeploymentException("cached ConnectionManager not found: " + ccmName);
268
269 if (managedConnectionPoolName == null)
270 throw new DeploymentException("managedConnectionPool not set!");
271 try
272 {
273 poolingStrategy = (ManagedConnectionPool) server.getAttribute(managedConnectionPoolName,
274 "ManagedConnectionPool");
275 }
276 catch (Exception e)
277 {
278 JMXExceptionDecoder.rethrow(e);
279 }
280
281 poolingStrategy.setConnectionListenerFactory(this);
282
283 // Give it somewhere to tell people things
284 String categoryName = poolingStrategy.getManagedConnectionFactory().getClass().getName() + "." + jndiName;
285 Logger log = Logger.getLogger(categoryName);
286 PrintWriter logWriter = new LoggerPluginWriter(log.getLoggerPlugin());
287 try
288 {
289 poolingStrategy.getManagedConnectionFactory().setLogWriter(logWriter);
290 }
291 catch (ResourceException re)
292 {
293 log.warn("Unable to set log writer '" + logWriter + "' on " + "managed connection factory", re);
294 log.warn("Linked exception:", re.getLinkedException());
295 }
296
297 if (poolingStrategy instanceof PreFillPoolSupport)
298 {
299
300 PreFillPoolSupport prefill = (PreFillPoolSupport) poolingStrategy;
301
302 if(prefill.shouldPreFill()){
303
304 prefill.prefill();
305
306 }
307
308 }
309
310 }
311
312 protected void stopService() throws Exception
313 {
314 //notify the login modules the mcf is going away, they need to look it up again later.
315 sendNotification(new Notification(STOPPING_NOTIFICATION, getServiceName(), getNextNotificationSequenceNumber()));
316 /*
317 * if (jaasSecurityManagerService != null && securityDomainJndiName != null)
318 server.invoke(jaasSecurityManagerService, "flushAuthenticationCache", new Object[] { securityDomainJndiName }, new String[] { String.class.getName() });
319 */
320 poolingStrategy.setConnectionListenerFactory(null);
321
322 poolingStrategy = null;
323 subjectFactory = null;
324 ccm = null;
325 }
326
327 /**
328 * Public for use in testing pooling functionality by itself.
329 * called by both allocateConnection and reconnect.
330 *
331 * @param subject a <code>Subject</code> value
332 * @param cri a <code>ConnectionRequestInfo</code> value
333 * @return a <code>ManagedConnection</code> value
334 * @exception ResourceException if an error occurs
335 */
336 public ConnectionListener getManagedConnection(Subject subject, ConnectionRequestInfo cri) throws ResourceException
337 {
338 return getManagedConnection(null, subject, cri);
339 }
340
341 /**
342 * Get the managed connection from the pool
343 *
344 * @param transaction the transaction for track by transaction
345 * @param subject the subject
346 * @param cri the ConnectionRequestInfo
347 * @return a managed connection
348 * @exception ResourceException if an error occurs
349 */
350 protected ConnectionListener getManagedConnection(Transaction transaction, Subject subject, ConnectionRequestInfo cri)
351 throws ResourceException
352 {
353 return poolingStrategy.getConnection(transaction, subject, cri);
354 }
355
356 public void returnManagedConnection(ConnectionListener cl, boolean kill)
357 {
358 ManagedConnectionPool localStrategy = cl.getManagedConnectionPool();
359 if (localStrategy != poolingStrategy)
360 kill = true;
361
362 try
363 {
364 if (kill == false && cl.getState() == ConnectionListener.NORMAL)
365 cl.tidyup();
366 }
367 catch (Throwable t)
368 {
369 log.warn("Error during tidyup " + cl, t);
370 kill = true;
371 }
372
373 try
374 {
375 localStrategy.returnConnection(cl, kill);
376 }
377 catch (ResourceException re)
378 {
379 // We can receive notification of an error on the connection
380 // before it has been assigned to the pool. Reduce the noise for
381 // these errors
382 if (kill)
383 log.debug("resourceException killing connection (error retrieving from pool?)", re);
384 else
385 log.warn("resourceException returning connection: " + cl.getManagedConnection(), re);
386 }
387 }
388
389 public int getConnectionCount()
390 {
391 return poolingStrategy.getConnectionCount();
392 }
393
394 // implementation of javax.resource.spi.ConnectionManager interface
395
396 public Object allocateConnection(ManagedConnectionFactory mcf, ConnectionRequestInfo cri) throws ResourceException
397 {
398 if (poolingStrategy == null)
399 throw new ResourceException(
400 "You are trying to use a connection factory that has been shut down: ManagedConnectionFactory is null.");
401
402 //it is an explicit spec requirement that equals be used for matching rather than ==.
403 if (!poolingStrategy.getManagedConnectionFactory().equals(mcf))
404 throw new ResourceException("Wrong ManagedConnectionFactory sent to allocateConnection!");
405
406 // Pick a managed connection from the pool
407 Subject subject = getSubject();
408 ConnectionListener cl = getManagedConnection(subject, cri);
409
410 // Tell each connection manager the managed connection is active
411 reconnectManagedConnection(cl);
412
413 // Ask the managed connection for a connection
414 Object connection = null;
415 try
416 {
417 connection = cl.getManagedConnection().getConnection(subject, cri);
418 }
419 catch (Throwable t)
420 {
421 try {
422 managedConnectionDisconnected(cl);
423 }
424 catch (ResourceException re)
425 {
426 log.trace("Get exception from managedConnectionDisconnected, maybe delist() have problem" + re);
427 returnManagedConnection(cl, true);
428 }
429 JBossResourceException.rethrowAsResourceException(
430 "Unchecked throwable in ManagedConnection.getConnection() cl=" + cl, t);
431 }
432
433 // Associate managed connection with the connection
434 registerAssociation(cl, connection);
435 if (ccm != null)
436 ccm.registerConnection(this, cl, connection, cri);
437 return connection;
438 }
439
440 // ConnectionCacheListener implementation
441
442 public void transactionStarted(Collection conns) throws SystemException
443 {
444 //reimplement in subclasses
445 }
446
447 public void reconnect(Collection conns, Set unsharableResources) throws ResourceException
448 {
449 // if we have an unshareable connection the association was not removed
450 // nothing to do
451 if (unsharableResources.contains(jndiName))
452 {
453 log.trace("reconnect for unshareable connection: nothing to do");
454 return;
455 }
456
457 Map criToCLMap = new HashMap();
458 for (Iterator i = conns.iterator(); i.hasNext();)
459 {
460 ConnectionRecord cr = (ConnectionRecord) i.next();
461 if (cr.cl != null)
462 {
463 //This might well be an error.
464 log.warn("reconnecting a connection handle that still has a managedConnection! "
465 + cr.cl.getManagedConnection() + " " + cr.connection);
466 }
467 ConnectionListener cl = (ConnectionListener) criToCLMap.get(cr.cri);
468 if (cl == null)
469 {
470 cl = getManagedConnection(getSubject(), cr.cri);
471 criToCLMap.put(cr.cri, cl);
472 //only call once per managed connection, when we get it.
473 reconnectManagedConnection(cl);
474 }
475
476 cl.getManagedConnection().associateConnection(cr.connection);
477 registerAssociation(cl, cr.connection);
478 cr.setConnectionListener(cl);
479 }
480 criToCLMap.clear();//not needed logically, might help the gc.
481 }
482
483 public void disconnect(Collection crs, Set unsharableResources) throws ResourceException
484 {
485 // if we have an unshareable connection do not remove the association
486 // nothing to do
487 if (unsharableResources.contains(jndiName))
488 {
489 log.trace("disconnect for unshareable connection: nothing to do");
490 return;
491 }
492
493 Set cls = new HashSet();
494 for (Iterator i = crs.iterator(); i.hasNext();)
495 {
496 ConnectionRecord cr = (ConnectionRecord) i.next();
497 ConnectionListener cl = cr.cl;
498 cr.setConnectionListener(null);
499 unregisterAssociation(cl, cr.connection);
500 if (!cls.contains(cl))
501 {
502 cls.add(cl);
503 }
504 }
505 for (Iterator i = cls.iterator(); i.hasNext();)
506 disconnectManagedConnection((ConnectionListener) i.next());
507 }
508
509 // implementation of javax.management.NotificationBroadcaster interface
510
511 public MBeanNotificationInfo[] getNotificationInfo()
512 {
513 // TODO: implement this javax.management.NotificationBroadcaster method
514 return super.getNotificationInfo();
515 }
516
517 //protected methods
518
519 //does NOT put the mc back in the pool if no more handles. Doing so would introduce a race condition
520 //whereby the mc got back in the pool while still enlisted in the tx.
521 //The mc could be checked out again and used before the delist occured.
522 protected void unregisterAssociation(ConnectionListener cl, Object c) throws ResourceException
523 {
524 cl.unregisterConnection(c);
525 }
526
527 /**
528 * Invoked to reassociate a managed connection
529 *
530 * @param cl the managed connection
531 */
532 protected void reconnectManagedConnection(ConnectionListener cl) throws ResourceException
533 {
534 try
535 {
536 //WRONG METHOD NAME!!
537 managedConnectionReconnected(cl);
538 }
539 catch (Throwable t)
540 {
541 disconnectManagedConnection(cl);
542 JBossResourceException.rethrowAsResourceException("Unchecked throwable in managedConnectionReconnected() cl="
543 + cl, t);
544 }
545 }
546
547 /**
548 * Invoked when a managed connection is no longer associated
549 *
550 * @param cl the managed connection
551 */
552 protected void disconnectManagedConnection(ConnectionListener cl)
553 {
554 try
555 {
556 managedConnectionDisconnected(cl);
557 }
558 catch (Throwable t)
559 {
560 log.warn("Unchecked throwable in managedConnectionDisconnected() cl=" + cl, t);
561 }
562 }
563
564 protected final CachedConnectionManager getCcm()
565 {
566 return ccm;
567 }
568
569 /**
570 * For polymorphism.<p>
571 *
572 * Do not invoke directly use reconnectManagedConnection
573 * which does the relevent exception handling
574 */
575 protected void managedConnectionReconnected(ConnectionListener cl) throws ResourceException
576 {
577 }
578
579 /**
580 * For polymorphism.<p>
581 *
582 * Do not invoke directly use disconnectManagedConnection
583 * which does the relevent exception handling
584 */
585 protected void managedConnectionDisconnected(ConnectionListener cl) throws ResourceException
586 {
587 }
588
589 private void registerAssociation(ConnectionListener cl, Object c) throws ResourceException
590 {
591 cl.registerConnection(c);
592 }
593
594 private Subject getSubject()
595 {
596 Subject subject = null;
597 if(subjectFactory != null && securityDomainJndiName != null)
598 {
599 subject = subjectFactory.createSubject(securityDomainJndiName);
600 }
601 if (trace)
602 log.trace("subject: " + subject);
603 return subject;
604 }
605
606 // ConnectionListenerFactory
607
608 public boolean isTransactional()
609 {
610 return false;
611 }
612
613 public TransactionManager getTransactionManagerInstance()
614 {
615 return null;
616 }
617
618 //ConnectionListener
619
620 protected abstract class BaseConnectionEventListener implements ConnectionListener
621 {
622 private final ManagedConnection mc;
623
624 private final ManagedConnectionPool mcp;
625
626 private final Object context;
627
628 private int state = NORMAL;
629
630 private final List handles = new LinkedList();
631
632 private long lastUse;
633
634 private boolean trackByTx = false;
635
636 private boolean permit = false;
637
638 protected Logger log;
639
640 protected boolean trace;
641
642 protected long lastValidated;
643
644
645 protected BaseConnectionEventListener(ManagedConnection mc, ManagedConnectionPool mcp, Object context, Logger log)
646 {
647 this.mc = mc;
648 this.mcp = mcp;
649 this.context = context;
650 this.log = log;
651 trace = log.isTraceEnabled();
652 lastUse = System.currentTimeMillis();
653 }
654
655 public ManagedConnection getManagedConnection()
656 {
657 return mc;
658 }
659
660 public ManagedConnectionPool getManagedConnectionPool()
661 {
662 return mcp;
663 }
664
665 public Object getContext()
666 {
667 return context;
668 }
669
670 public int getState()
671 {
672 return state;
673 }
674
675 public void setState(int newState)
676 {
677 this.state = newState;
678 }
679
680 public boolean isTimedOut(long timeout)
681 {
682 return lastUse < timeout;
683 }
684
685 public void used()
686 {
687 lastUse = System.currentTimeMillis();
688 }
689
690 public boolean isTrackByTx()
691 {
692 return trackByTx;
693 }
694
695 public void setTrackByTx(boolean trackByTx)
696 {
697 this.trackByTx = trackByTx;
698 }
699
700 public void tidyup() throws ResourceException
701 {
702 }
703
704 public synchronized void registerConnection(Object handle)
705 {
706 handles.add(handle);
707 }
708
709 public synchronized void unregisterConnection(Object handle)
710 {
711 if (!handles.remove(handle))
712 {
713 log.info("Unregistered handle that was not registered! " + handle + " for managedConnection: " + mc);
714 }
715 if (trace)
716 log.trace("unregisterConnection: " + handles.size() + " handles left");
717 }
718
719 public synchronized boolean isManagedConnectionFree()
720 {
721 return handles.isEmpty();
722 }
723
724 protected synchronized void unregisterConnections()
725 {
726 try
727 {
728 for (Iterator i = handles.iterator(); i.hasNext();)
729 {
730 getCcm().unregisterConnection(BaseConnectionManager2.this, i.next());
731 }
732 }
733 finally
734 {
735 handles.clear();
736 }
737 }
738
739 public void connectionErrorOccurred(ConnectionEvent ce)
740 {
741 if (state == NORMAL)
742 {
743 if (ce != null)
744 {
745 Throwable t = ce.getException();
746 if (t == null)
747 t = new Exception("No exception was reported");
748 log.warn("Connection error occured: " + this, t);
749 }
750 else
751 {
752 Throwable t = new Exception("No exception was reported");
753 log.warn("Unknown Connection error occured: " + this, t);
754 }
755 }
756 try
757 {
758 unregisterConnections();
759 }
760 catch (Throwable t)
761 {
762 //ignore, it wasn't checked out.
763 }
764 if (ce != null && ce.getSource() != getManagedConnection())
765 log.warn("Notified of error on a different managed connection?");
766 returnManagedConnection(this, true);
767 }
768
769 public void enlist() throws SystemException
770 {
771 }
772
773 public void delist() throws ResourceException
774 {
775 }
776
777 public boolean hasPermit()
778 {
779 return permit;
780 }
781
782 public void grantPermit(boolean value)
783 {
784 this.permit = value;
785 }
786
787 public long getLastValidatedTime()
788 {
789 return this.lastValidated;
790 }
791
792 public void setLastValidatedTime(long lastValidated)
793 {
794 this.lastValidated = lastValidated;
795 }
796
797 // For debugging
798 public String toString()
799 {
800 StringBuffer buffer = new StringBuffer(100);
801 buffer.append(getClass().getName()).append('@').append(Integer.toHexString(System.identityHashCode(this)));
802 buffer.append("[state=");
803 if (state == ConnectionListener.NORMAL)
804 buffer.append("NORMAL");
805 else if (state == ConnectionListener.DESTROY)
806 buffer.append("DESTROY");
807 else if (state == ConnectionListener.DESTROYED)
808 buffer.append("DESTROYED");
809 else
810 buffer.append("UNKNOWN?");
811 buffer.append(" mc=").append(mc);
812 buffer.append(" handles=").append(handles.size());
813 buffer.append(" lastUse=").append(lastUse);
814 buffer.append(" permit=").append(permit);
815 buffer.append(" trackByTx=").append(trackByTx);
816 buffer.append(" mcp=").append(mcp);
817 buffer.append(" context=").append(context);
818 toString(buffer);
819 buffer.append(']');
820 return buffer.toString();
821 }
822
823 // For debugging
824 protected void toString(StringBuffer buffer)
825 {
826 }
827 }
828
829 public static class ConnectionManagerProxy
830 implements
831 ConnectionManager,
832 Serializable,
833 TransactionTimeoutConfiguration,
834 JTATransactionChecker
835 {
836 static final long serialVersionUID = -528322728929261214L;
837
838 private transient BaseConnectionManager2 realCm;
839
840 private final ObjectName cmName;
841
842 ConnectionManagerProxy(final BaseConnectionManager2 realCm, final ObjectName cmName)
843 {
844 this.realCm = realCm;
845 this.cmName = cmName;
846 }
847
848 // implementation of javax.resource.spi.ConnectionManager interface
849
850 public Object allocateConnection(ManagedConnectionFactory mcf, ConnectionRequestInfo cri)
851 throws ResourceException
852 {
853 return getCM().allocateConnection(mcf, cri);
854 }
855
856 public long getTimeLeftBeforeTransactionTimeout(boolean errorRollback) throws RollbackException
857 {
858 try
859 {
860 return getCM().getTimeLeftBeforeTransactionTimeout(errorRollback);
861 }
862 catch (ResourceException e)
863 {
864 throw new NestedRuntimeException("Unable to retrieve connection manager", e);
865 }
866 }
867
868 public int getTransactionTimeout() throws SystemException
869 {
870 try
871 {
872 return getCM().getTransactionTimeout();
873 }
874 catch (ResourceException e)
875 {
876 throw new NestedRuntimeException("Unable to retrieve connection manager", e);
877 }
878 }
879
880 public void checkTransactionActive() throws RollbackException, SystemException
881 {
882 try
883 {
884 getCM().checkTransactionActive();
885 }
886 catch (ResourceException e)
887 {
888 throw new NestedRuntimeException("Unable to retrieve connection manager", e);
889 }
890 }
891
892 private BaseConnectionManager2 getCM() throws ResourceException
893 {
894 if (realCm == null)
895 {
896 try
897 {
898 MBeanServer server = MBeanServerLocator.locateJBoss();
899 realCm = (BaseConnectionManager2) server.getAttribute(cmName, "Instance");
900 }
901 catch (Throwable t)
902 {
903 Throwable t2 = JMXExceptionDecoder.decode(t);
904 JBossResourceException.rethrowAsResourceException("Problem locating real ConnectionManager: " + cmName,
905 t2);
906 }
907 }
908 return realCm;
909 }
910 }
911 }