001: /*
002: * Copyright (c) 1998-2008 Caucho Technology -- all rights reserved
003: *
004: * This file is part of Resin(R) Open Source
005: *
006: * Each copy or derived work must preserve the copyright notice and this
007: * notice unmodified.
008: *
009: * Resin Open Source is free software; you can redistribute it and/or modify
010: * it under the terms of the GNU General Public License as published by
011: * the Free Software Foundation; either version 2 of the License, or
012: * (at your option) any later version.
013: *
014: * Resin Open Source is distributed in the hope that it will be useful,
015: * but WITHOUT ANY WARRANTY; without even the implied warranty of
016: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty
017: * of NON-INFRINGEMENT. See the GNU General Public License for more
018: * details.
019: *
020: * You should have received a copy of the GNU General Public License
021: * along with Resin Open Source; if not, write to the
022: *
023: * Free Software Foundation, Inc.
024: * 59 Temple Place, Suite 330
025: * Boston, MA 02111-1307 USA
026: *
027: * @author Scott Ferguson
028: */
029:
030: package com.caucho.jca;
031:
032: import com.caucho.log.Log;
033: import com.caucho.util.L10N;
034:
035: import javax.resource.ResourceException;
036: import javax.resource.spi.ConnectionEvent;
037: import javax.resource.spi.ConnectionRequestInfo;
038: import javax.resource.spi.ManagedConnectionFactory;
039: import javax.security.auth.Subject;
040: import javax.transaction.RollbackException;
041: import java.util.logging.Logger;
042:
043: /**
044: * Pool item representing the user connection.
045: *
046: * The UserPoolItem is responsible for the lifecycle of an
047: * associated PoolItem (ownPoolItem).
048: *
049: * The UserPoolItem also has the current XA PoolItem, which may be
050: * shared with other UserPoolItems.
051: *
052: * When the XA completes, the UserPoolItem restores
053: * its current XA PoolItem to the ownPoolItem.
054: */
055: class UserPoolItem {
056: private static final L10N L = new L10N(UserPoolItem.class);
057: private static final Logger log = Log.open(UserPoolItem.class);
058:
059: private ConnectionPool _cm;
060: private String _id;
061:
062: // the pool item associated with this connection
063: private PoolItem _ownPoolItem;
064:
065: private ManagedConnectionFactory _mcf;
066: private Subject _subject;
067: private ConnectionRequestInfo _info;
068:
069: // The owning transaction
070: private UserTransactionImpl _transaction;
071:
072: // The head PoolItem for the transaction
073: private PoolItem _sharePoolItem;
074:
075: // The next shared UserPoolItem in the chain
076: private UserPoolItem _shareNext;
077: // The previous shared UserPoolItem in the chain
078: private UserPoolItem _sharePrev;
079:
080: private Object _userConn;
081:
082: private boolean _hasConnectionError;
083:
084: private IllegalStateException _allocationStackTrace;
085:
086: public UserPoolItem(ConnectionPool cm) {
087: _cm = cm;
088: _id = _cm.generateId();
089:
090: _transaction = _cm.getTransaction();
091:
092: if (cm.getSaveAllocationStackTrace()) {
093: _allocationStackTrace = new IllegalStateException(L
094: .l("unclosed connection: " + this
095: + " was allocated at"));
096: _allocationStackTrace.fillInStackTrace();
097: }
098: }
099:
100: public UserPoolItem(ConnectionPool cm, PoolItem poolItem) {
101: this (cm);
102:
103: _ownPoolItem = poolItem;
104: _sharePoolItem = poolItem;
105: }
106:
107: /**
108: * Sets the managed connection factory
109: */
110: public void setManagedConnectionFactory(ManagedConnectionFactory mcf) {
111: _mcf = mcf;
112: }
113:
114: /**
115: * Gets the managed connection factory
116: */
117: public ManagedConnectionFactory getManagedConnectionFactory() {
118: return _mcf;
119: }
120:
121: /**
122: * Sets the subject.
123: */
124: public void setSubject(Subject subject) {
125: _subject = subject;
126: }
127:
128: /**
129: * Sets the subject.
130: */
131: public Subject getSubject() {
132: return _subject;
133: }
134:
135: /**
136: * Sets the info.
137: */
138: public void setInfo(ConnectionRequestInfo info) {
139: _info = info;
140: }
141:
142: /**
143: * Gets the info.
144: */
145: public ConnectionRequestInfo getInfo() {
146: return _info;
147: }
148:
149: /**
150: * Returns true if the connection is active.
151: */
152: public boolean isActive() {
153: return _userConn != null;
154: }
155:
156: /**
157: * Notifies that a connection error has occurred.
158: */
159: public void connectionErrorOccurred(ConnectionEvent event) {
160: _hasConnectionError = true;
161: }
162:
163: /**
164: * Returns true if there was a connection error.
165: */
166: public boolean isConnectionError() {
167: return _hasConnectionError;
168: }
169:
170: /**
171: * Returns the allocation stack trace.
172: */
173: public IllegalStateException getAllocationStackTrace() {
174: return _allocationStackTrace;
175: }
176:
177: /**
178: * Enables saving of the allocation stack traces.
179: */
180: public void setSaveAllocationStackTrace(boolean enable) {
181: _cm.setSaveAllocationStackTrace(enable);
182: }
183:
184: /**
185: * Return true if connections should be closed automatically.
186: */
187: public boolean isCloseDanglingConnections() {
188: return _cm.isCloseDanglingConnections();
189: }
190:
191: /**
192: * Returns the pool item.
193: */
194: public PoolItem getOwnPoolItem() {
195: return _ownPoolItem;
196: }
197:
198: /**
199: * Returns the xa item.
200: */
201: public PoolItem getXAPoolItem() {
202: return _sharePoolItem;
203: }
204:
205: /**
206: * Gets the user connection.
207: */
208: public Object getUserConnection() {
209: return _userConn;
210: }
211:
212: /**
213: * Gets the user connection.
214: */
215: Object allocateUserConnection() throws ResourceException {
216: if (_userConn == null)
217: _userConn = _sharePoolItem.allocateConnection();
218:
219: return _userConn;
220: }
221:
222: /**
223: * Sets the user connection.
224: */
225: public void setUserConnection(Object userConn) {
226: _userConn = userConn;
227: }
228:
229: /**
230: * Returns the next share.
231: */
232: UserPoolItem getShareNext() {
233: return _shareNext;
234: }
235:
236: /**
237: * Associates the UserPoolItem with a pool item
238: */
239: void associatePoolItem(PoolItem poolItem) {
240: if (_ownPoolItem != null)
241: throw new IllegalStateException(L
242: .l("associating with old pool item."));
243:
244: _ownPoolItem = poolItem;
245:
246: if (_sharePoolItem != null)
247: removeFromShareList();
248:
249: addToShareList(poolItem);
250: }
251:
252: /**
253: * Associates the UserPoolItem with a pool item
254: */
255: void associate(PoolItem poolItem, ManagedConnectionFactory mcf,
256: Subject subject, ConnectionRequestInfo info) {
257: if (_sharePoolItem != null)
258: removeFromShareList();
259:
260: _mcf = mcf;
261: _subject = subject;
262: _info = info;
263:
264: addToShareList(poolItem);
265:
266: if (_transaction != null) {
267: try {
268: _transaction.enlistResource(this );
269: } catch (RollbackException e) {
270: removeFromShareList();
271:
272: poolItem.toIdle();
273:
274: throw new RuntimeException(e);
275: } catch (Throwable e) {
276: removeFromShareList();
277:
278: poolItem.setConnectionError();
279: poolItem.toIdle();
280:
281: throw new RuntimeException(e);
282: }
283: }
284: }
285:
286: /**
287: * Reassociates with the an own pool item.
288: */
289: void reassociatePoolItem() throws ResourceException {
290: if (_ownPoolItem == null) {
291: UserPoolItem item = _cm.allocatePool(_mcf, _subject, _info,
292: this );
293:
294: assert (item == this );
295:
296: _ownPoolItem = item.getOwnPoolItem();
297: }
298:
299: if (_sharePoolItem != null)
300: removeFromShareList();
301:
302: addToShareList(_ownPoolItem);
303: }
304:
305: /**
306: * Close the connection, called from UserTransactionImpl.
307: */
308: void abortConnection() throws ResourceException {
309: PoolItem poolItem = _ownPoolItem;
310: _ownPoolItem = null;
311:
312: removeFromShareList();
313:
314: if (poolItem != null)
315: poolItem.abortConnection();
316: }
317:
318: /**
319: * Closes the item.
320: */
321: void close() {
322: PoolItem ownPoolItem = _ownPoolItem;
323: _ownPoolItem = null;
324:
325: _userConn = null;
326:
327: if (_transaction != null)
328: _transaction.delistResource(this );
329:
330: removeFromShareList();
331:
332: if (ownPoolItem != null)
333: ownPoolItem.toIdle();
334: }
335:
336: /**
337: * Removes from the current list.
338: */
339: void removeFromShareList() {
340: PoolItem poolItem = _sharePoolItem;
341: _sharePoolItem = null;
342:
343: if (poolItem == null)
344: return;
345:
346: synchronized (poolItem._shareLock) {
347: UserPoolItem prev = _sharePrev;
348: UserPoolItem next = _shareNext;
349:
350: _sharePrev = null;
351: _shareNext = null;
352:
353: if (prev != null)
354: prev._shareNext = next;
355: else
356: poolItem._shareHead = next;
357:
358: if (next != null)
359: next._sharePrev = prev;
360: }
361: }
362:
363: /**
364: * Removes from the current list.
365: */
366: void addToShareList(PoolItem poolItem) {
367: if (_sharePoolItem != null)
368: throw new IllegalStateException();
369:
370: synchronized (poolItem._shareLock) {
371: _sharePoolItem = poolItem;
372:
373: _sharePrev = null;
374: _shareNext = poolItem._shareHead;
375:
376: if (poolItem._shareHead != null)
377: poolItem._shareHead._sharePrev = this ;
378:
379: poolItem._shareHead = this ;
380: }
381: }
382:
383: /**
384: * Returns true for a closed connection.
385: */
386: boolean isClosed() {
387: return _sharePoolItem == null;
388: }
389:
390: // XAResource stuff
391:
392: public String toString() {
393: return "UserPoolItem[" + _cm.getName() + "," + _id + "]";
394: }
395: }
|