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