001: package org.apache.ojb.otm.connector;
002:
003: /* Copyright 2003-2005 The Apache Software Foundation
004: *
005: * Licensed under the Apache License, Version 2.0 (the "License");
006: * you may not use this file except in compliance with the License.
007: * You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017:
018: import org.apache.ojb.broker.PBKey;
019: import org.apache.ojb.otm.OTMConnection;
020: import org.apache.ojb.otm.core.Transaction;
021: import org.apache.ojb.otm.core.TransactionException;
022:
023: import javax.resource.NotSupportedException;
024: import javax.resource.ResourceException;
025: import javax.resource.spi.ConnectionEvent;
026: import javax.resource.spi.ConnectionEventListener;
027: import javax.resource.spi.ConnectionRequestInfo;
028: import javax.resource.spi.LocalTransaction;
029: import javax.resource.spi.ManagedConnection;
030: import javax.resource.spi.ManagedConnectionFactory;
031: import javax.resource.spi.ManagedConnectionMetaData;
032: import javax.security.auth.Subject;
033: import javax.transaction.xa.XAResource;
034: import java.io.PrintWriter;
035: import java.util.ArrayList;
036: import java.util.Collection;
037: import java.util.HashSet;
038: import java.util.Iterator;
039: import java.util.Set;
040:
041: /**
042: *
043: * @author <a href="mailto:mattbaird@yahoo.com">Matthew Baird<a>
044: */
045:
046: public class OTMJCAManagedConnection implements ManagedConnection,
047: LocalTransaction {
048: private PBKey m_pbKey;
049: private OTMJCAManagedConnectionFactory m_managedConnectionFactory;
050: private PrintWriter m_logWriter;
051: private boolean m_destroyed;
052: private final Set m_handles = new HashSet();
053: private final Collection m_connectionEventListeners = new ArrayList();
054: private boolean m_managed = false;
055: /**
056: * the wrapped connection
057: */
058: private OTMConnection m_connection;
059: private Transaction m_tx;
060:
061: OTMJCAManagedConnection(ManagedConnectionFactory mcf,
062: OTMConnection conn, PBKey pbKey) {
063: Util.log("In OTMJCAManagedConnection");
064: m_managedConnectionFactory = (OTMJCAManagedConnectionFactory) mcf;
065: m_pbKey = pbKey;
066: m_connection = conn;
067: }
068:
069: /**
070: * get the underlying wrapped connection
071: * @return OTMConnection raw connection to the OTM.
072: */
073: OTMConnection getConnection() {
074: if (m_connection == null) {
075: OTMConnectionRuntimeException ex = new OTMConnectionRuntimeException(
076: "Connection is null.");
077: sendEvents(ConnectionEvent.CONNECTION_ERROR_OCCURRED, ex,
078: null);
079: }
080: return m_connection;
081: }
082:
083: public Transaction getTransaction() {
084: return this .m_tx;
085: }
086:
087: public void setTransaction(Transaction tx) {
088: if (this .m_tx != null)
089: throw new IllegalStateException(
090: "Connection already has Transaction");
091: this .m_tx = tx;
092: }
093:
094: public String getUserName() {
095: return m_pbKey.getUser();
096: }
097:
098: public Object getConnection(Subject subject,
099: ConnectionRequestInfo connectionRequestInfo)
100: throws ResourceException {
101: Util.log("In OTMJCAManagedConnection.getConnection");
102: OTMJCAConnection myCon = new OTMJCAConnection(this );
103: synchronized (m_handles) {
104: m_handles.add(myCon);
105: }
106: return myCon;
107: }
108:
109: public void destroy() {
110: Util.log("In OTMJCAManagedConnection.destroy");
111: cleanup();
112: m_connection.close();
113: m_destroyed = true;
114: }
115:
116: public void cleanup() {
117: Util.log("In OTMJCAManagedConnection.cleanup");
118: synchronized (m_handles) {
119: for (Iterator i = m_handles.iterator(); i.hasNext();) {
120: OTMJCAConnection lc = (OTMJCAConnection) i.next();
121: lc.setManagedConnection(null);
122: }
123: m_handles.clear();
124: }
125: }
126:
127: void closeHandle(OTMJCAConnection handle) {
128: synchronized (m_handles) {
129: m_handles.remove(handle);
130: }
131: sendEvents(ConnectionEvent.CONNECTION_CLOSED, null, handle);
132: }
133:
134: public void associateConnection(Object connection) {
135: Util.log("In OTMJCAManagedConnection.associateConnection");
136: if (connection == null) {
137: throw new OTMConnectionRuntimeException(
138: "Cannot associate a null connection");
139: }
140: if (!(connection instanceof OTMJCAConnection)) {
141: throw new OTMConnectionRuntimeException(
142: "Cannot associate a connection of type: "
143: + connection.getClass().getName()
144: + " to a handle that manages: "
145: + OTMJCAConnection.class.getName());
146: }
147: ((OTMJCAConnection) connection).setManagedConnection(this );
148: synchronized (m_handles) {
149: m_handles.add(connection);
150: }
151: }
152:
153: public void addConnectionEventListener(ConnectionEventListener cel) {
154: synchronized (m_connectionEventListeners) {
155: m_connectionEventListeners.add(cel);
156: }
157: }
158:
159: public void removeConnectionEventListener(
160: ConnectionEventListener cel) {
161: synchronized (m_connectionEventListeners) {
162: m_connectionEventListeners.remove(cel);
163: }
164: }
165:
166: public XAResource getXAResource() throws ResourceException {
167: Util.log("In OTMJCAManagedConnection.getXAResource");
168: throw new NotSupportedException(
169: "public XAResource getXAResource() not supported in this release.");
170: }
171:
172: /**
173: * the OTMConnection is the transaction
174: * @return
175: */
176: public LocalTransaction getLocalTransaction() {
177: Util.log("In OTMJCAManagedConnection.getLocalTransaction");
178: return this ;
179: }
180:
181: public ManagedConnectionMetaData getMetaData()
182: throws ResourceException {
183: Util.log("In OTMJCAManagedConnection.getMetaData");
184: return new OTMConnectionMetaData(this );
185: }
186:
187: public void setLogWriter(PrintWriter out) throws ResourceException {
188: Util.log("In OTMJCAManagedConnection.setLogWriter");
189: m_logWriter = out;
190: }
191:
192: public PrintWriter getLogWriter() throws ResourceException {
193: Util.log("In OTMJCAManagedConnection.getLogWriter");
194: return m_logWriter;
195: }
196:
197: boolean isDestroyed() {
198: Util.log("In OTMJCAManagedConnection.isDestroyed");
199: return m_destroyed;
200: }
201:
202: ManagedConnectionFactory getManagedConnectionFactory() {
203: Util
204: .log("In OTMJCAManagedConnection.getManagedConnectionFactory");
205: return m_managedConnectionFactory;
206: }
207:
208: public void begin() throws ResourceException {
209: Util.log("In OTMJCAManagedConnection.begin");
210: if (!isManaged()) {
211: try {
212: m_tx = m_managedConnectionFactory.getKit()
213: .getTransaction(m_connection);
214: m_tx.begin();
215: setManaged(true);
216: } catch (TransactionException e) {
217: ResourceException ex = new ResourceException(e
218: .getMessage());
219: sendEvents(ConnectionEvent.CONNECTION_ERROR_OCCURRED,
220: ex, null);
221: throw ex;
222: }
223: } else {
224: ResourceException ex = new ResourceException(
225: "You probably called begin again without calling Commit or Rollback, OTM does not support nested Local Transactions.");
226: sendEvents(ConnectionEvent.CONNECTION_ERROR_OCCURRED, ex,
227: null);
228: throw ex;
229: }
230: }
231:
232: public void commit() throws ResourceException {
233: Util.log("In OTMJCAManagedConnection.commit");
234: if (isManaged()) {
235: try {
236: setManaged(false);
237: m_tx.commit();
238: } catch (TransactionException e) {
239: m_tx.rollback();
240: ResourceException ex = new ResourceException(e
241: .getMessage());
242: sendEvents(ConnectionEvent.CONNECTION_ERROR_OCCURRED,
243: ex, null);
244: throw ex;
245: }
246: } else {
247: ResourceException ex = new ResourceException(
248: "Cannot call commit when you are not in a Local Transaction.");
249: sendEvents(ConnectionEvent.CONNECTION_ERROR_OCCURRED, ex,
250: null);
251: throw ex;
252: }
253: }
254:
255: public void rollback() throws ResourceException {
256: Util.log("In OTMJCAManagedConnection.rollback");
257: if (isManaged()) {
258: try {
259: m_tx.rollback();
260: setManaged(false);
261: } catch (TransactionException e) {
262: ResourceException ex = new ResourceException(e
263: .getMessage());
264: sendEvents(ConnectionEvent.CONNECTION_ERROR_OCCURRED,
265: ex, null);
266: throw ex;
267: }
268: } else {
269: ResourceException ex = new ResourceException(
270: "Cannot call rollback when you are not in a Local Transaction.");
271: sendEvents(ConnectionEvent.CONNECTION_ERROR_OCCURRED, ex,
272: null);
273: throw ex;
274: }
275: }
276:
277: private boolean isManaged() {
278: return m_managed;
279: }
280:
281: private void setManaged(boolean flag) {
282: m_managed = flag;
283: }
284:
285: /**
286: * Section 6.5.6 of the JCA 1.5 spec instructs ManagedConnection instances to notify connection listeners with
287: * close/error and local transaction-related events to its registered set of listeners.
288: *
289: * The events for begin/commit/rollback are only sent if the application server did NOT
290: * initiate the actions.
291: *
292: * This method dispatchs all events to the listeners based on the eventType
293: * @param eventType as enumerated in the ConnectionEvents interface
294: * @param ex an optional exception if we are sending an error message
295: * @param connectionHandle an optional connectionHandle if we have access to it.
296: */
297: void sendEvents(int eventType, Exception ex, Object connectionHandle) {
298: ConnectionEvent ce = null;
299: if (ex == null) {
300: ce = new ConnectionEvent(this , eventType);
301: } else {
302: ce = new ConnectionEvent(this , eventType, ex);
303: }
304: ce.setConnectionHandle(connectionHandle);
305: Collection copy = null;
306: synchronized (m_connectionEventListeners) {
307: copy = new ArrayList(m_connectionEventListeners);
308: }
309: switch (ce.getId()) {
310: case ConnectionEvent.CONNECTION_CLOSED:
311: for (Iterator i = copy.iterator(); i.hasNext();) {
312: ConnectionEventListener cel = (ConnectionEventListener) i
313: .next();
314: cel.connectionClosed(ce);
315: }
316: break;
317: case ConnectionEvent.LOCAL_TRANSACTION_STARTED:
318: for (Iterator i = copy.iterator(); i.hasNext();) {
319: ConnectionEventListener cel = (ConnectionEventListener) i
320: .next();
321: cel.localTransactionStarted(ce);
322: }
323: break;
324: case ConnectionEvent.LOCAL_TRANSACTION_COMMITTED:
325: for (Iterator i = copy.iterator(); i.hasNext();) {
326: ConnectionEventListener cel = (ConnectionEventListener) i
327: .next();
328: cel.localTransactionCommitted(ce);
329: }
330: break;
331: case ConnectionEvent.LOCAL_TRANSACTION_ROLLEDBACK:
332: for (Iterator i = copy.iterator(); i.hasNext();) {
333: ConnectionEventListener cel = (ConnectionEventListener) i
334: .next();
335: cel.localTransactionRolledback(ce);
336: }
337: break;
338: case ConnectionEvent.CONNECTION_ERROR_OCCURRED:
339: for (Iterator i = copy.iterator(); i.hasNext();) {
340: ConnectionEventListener cel = (ConnectionEventListener) i
341: .next();
342: cel.connectionErrorOccurred(ce);
343: }
344: break;
345: default:
346: throw new IllegalArgumentException("Illegal eventType: "
347: + ce.getId());
348: }
349: }
350: }
|