001: // You can redistribute this software and/or modify it under the terms of
002: // the Ozone Library License version 1 published by ozone-db.org.
003: //
004: // The original code and portions created by SMB are
005: // Copyright (C) 1997-@year@ by SMB GmbH. All rights reserved.
006: //
007: // $Id: ExternalTransaction.java,v 1.1 2001/12/18 10:31:30 per_nyfelt Exp $
008:
009: package org.ozoneDB;
010:
011: import java.io.*;
012: import java.util.*;
013: import java.rmi.*;
014: import org.ozoneDB.DxLib.*;
015: import org.ozoneDB.core.*;
016: import org.ozoneDB.util.*;
017: import org.ozoneDB.core.DbRemote.*; //import javax.transaction.*;
018: import javax.naming.*;
019:
020: /**
021: * ExternalTransaction allows an application to explicitly manage transaction
022: * boundaries.<p>
023: *
024: * When programming ozone applications explicite transaction demarcation is
025: * needed under rare circumstances only (for example: processing of binary large
026: * objects - BLOBs). In fact, in most cases explicite transactions are not
027: * really needed while implicite transactions are cleaner and faster. So, every
028: * time you are going to use explicite transactions, you should ask yourself if
029: * an implicite transaction is maybe a better choice.<p>
030: *
031: * In case of a deadlock the ordinary behaviour of ozone is to abort one of the
032: * locked transactions and restart until all transactions are successfully
033: * commited. This is not possible when explicite transactions are used! In case
034: * of deadlock an exceptions is thrown and the client has to decide what to do.
035: * <p>
036: *
037: * Note: If an operation that runs under control of this transaction fails, the
038: * transaction is set to rollback only.
039: *
040: *
041: * @author <a href="http://www.softwarebuero.de/">SMB</a>
042: * @version $Revision: 1.1 $Date: 2001/12/18 10:31:30 $
043: */
044: public final class ExternalTransaction extends AbstractTransaction
045: implements Referenceable {
046:
047: // Constants
048:
049: /** Status of a transaction: transaction is not active. */
050: public final static int STATUS_NONE = 1;
051:
052: /** Status of a transaction: transaction has been started. */
053: public final static int STATUS_ACTIVE = 2;
054:
055: /** Status of a transaction: transaction is about to prepare. */
056: public final static int STATUS_PREPARING = 3;
057:
058: /** Status of a transaction: transaction has been successfully prepared. */
059: public final static int STATUS_PREPARED = 4;
060:
061: /** Status of a transaction: transaction is about to commit.*/
062: public final static int STATUS_COMMITING = 5;
063:
064: /** Status of a transaction: transaction has been successfully committed. */
065: public final static int STATUS_COMMITED = 6;
066:
067: /** Status of a transaction: transaction is about to abort. */
068: public final static int STATUS_ROLLINGBACK = 7;
069:
070: /** Status of a transaction: transaction has been aborted. */
071: public final static int STATUS_ROLLEDBACK = 8;
072:
073: // Fields
074:
075: protected boolean rollbackOnly = false;
076:
077: public ExternalTransaction(ExternalDatabase _database) {
078: super (_database);
079: }
080:
081: /**
082: * Start work on behalf of this transaction and associate it with the current
083: * thread.
084: *
085: *
086: * @throws TransactionExc If the thread is already associated with a
087: * transaction.
088: * @throws IOException If the server is not reachable.
089: */
090: public void begin() throws TransactionExc, IOException {
091: database.beginTX(this );
092: }
093:
094: /**
095: * Attach the caller's thread to this transaction and detach the thread
096: * from any former Transaction the thread may have been associated with.
097: */
098: public void join() throws TransactionExc, IOException {
099: if (database instanceof LocalDatabase) {
100: // currently the client side threads are used for server internal work;
101: // that is, DbLocalClient just calls the appropriate server method; but
102: // the server can handle only one thread per transaction, therefore
103: // jointTX for local connections is not allowed -> one (Command)Thread per
104: // DbLocalClient
105: throw new RuntimeException(
106: "Operation not supported: join() on LocalDatabase's.");
107: } else {
108: database.leaveTX(this );
109: database.joinTX(this );
110: }
111: }
112:
113: /**
114: * Detach the caller's thread from this <code>Transaction</code>, but do not attach
115: * the thread to another <code>Transaction</code>.
116: */
117: public void leave() throws TransactionExc, IOException {
118: database.leaveTX(this );
119: }
120:
121: /**
122: * Prepares this transaction. This method is intended to be used by
123: * transactional applications that need two-phase commit.
124: */
125: public void prepare() throws TransactionExc, IOException {
126: if (rollbackOnly) {
127: database.rollbackTX(this );
128: throw new TransactionExc(
129: "Transaction was set to rollback only.",
130: TransactionExc.ROLLBACK);
131: } else {
132: // the server can also decide to rollback this transaction
133: database.prepareTX(this );
134: }
135: }
136:
137: /**
138: * Complete this transaction. When this method completes, the thread
139: * becomes associated with no transaction. This method can be called by a
140: * non-joined thread.
141: */
142: public void commit() throws TransactionExc, IOException {
143: commit(true);
144: }
145:
146: /**
147: * Complete this transaction. When this method completes, the thread
148: * becomes associated with no transaction. This method is intended to be
149: * used by transactional applications that need two-phase commit.
150: */
151: public void commit(boolean onePhase) throws TransactionExc,
152: IOException {
153: if (rollbackOnly) {
154: database.rollbackTX(this );
155: throw new TransactionExc(
156: "Transaction was set to rollback only.",
157: TransactionExc.ROLLBACK);
158: } else {
159: // the server can also decide to rollback this transaction
160: database.commitTX(this , onePhase);
161: }
162: }
163:
164: /**
165: * Checkpoint this transaction. This method can also be called by a
166: * non-joined thread.
167: */
168: public void checkpoint() throws TransactionExc, IOException {
169: database.checkpointTX(this );
170: }
171:
172: /**
173: * Rollback the transaction associated with the current thread. When this
174: * method completes, the thread becomes associated with no transaction.
175: * Calling this method when the transaction is not opened doe not throw
176: * an exception.
177: * <p>
178: * This method can be called by any threads.
179: */
180: public void rollback() throws TransactionExc, IOException {
181: database.rollbackTX(this );
182: }
183:
184: /**
185: * Modify the transaction associated with the current thread such that the
186: * only possible outcome of the transaction is to roll back the transaction.
187: */
188: public synchronized void setRollbackOnly() throws TransactionExc,
189: IOException {
190: rollbackOnly = true;
191: }
192:
193: /**
194: * Obtain the status of the transaction associated with the current thread.
195: */
196: public int getStatus() throws TransactionExc, IOException {
197: int internal = database.getStatusTX(this );
198:
199: // explicitely map this to avoid conflicts when codes are changed in
200: // of the two classes
201: switch (internal) {
202: case Transaction.STATUS_NONE:
203: return STATUS_NONE;
204: case Transaction.STATUS_STARTED:
205: return STATUS_ACTIVE;
206: case Transaction.STATUS_PREPARING:
207: return STATUS_PREPARING;
208: case Transaction.STATUS_PREPARED:
209: return STATUS_PREPARED;
210: case Transaction.STATUS_COMMITING:
211: return STATUS_COMMITING;
212: case Transaction.STATUS_COMMITED:
213: return STATUS_COMMITED;
214: case Transaction.STATUS_ABORTING:
215: return STATUS_ROLLINGBACK;
216: case Transaction.STATUS_ABORTED:
217: return STATUS_ROLLEDBACK;
218: default:
219: throw new RuntimeException(
220: "Unknown internal transaction status.");
221: }
222: }
223:
224: /**
225: * Modify the value of the timeout value that is associated with the
226: * transactions started by the current thread with the begin method.
227: *
228: * If an application has not called this method, the transaction service
229: * uses some default value for the transaction timeout.
230: *
231: *
232: * @param seconds The value of the timeout in seconds. If the value is zero,
233: * the transaction service restores the default value
234: */
235: public void setTransactionTimeout(int seconds)
236: throws TransactionExc, IOException {
237: throw new RuntimeException(
238: "setTransactionTimeout() is not yet implemented.");
239: }
240:
241: // JNDI stuff *****************************************
242:
243: /**
244: * Retrieves the JNDI Reference of this object.
245: * @return The non-null Reference of this object.
246: */
247: public Reference getReference() throws NamingException {
248: throw new RuntimeException(
249: "getReference() is not yet implemented.");
250:
251: // Reference ref;
252: // Package pkg;
253: //
254: // // we use same object as factory.
255: // ref = new Reference (getClass().getName(), getClass().getName(), null);
256: //
257: // // No properties, the entire transaction manager is static.
258: // pkg = ExternalTransaction.class.getPackage();
259: // if (pkg != null) {
260: // ref.add ( new StringRefAddr( "title", pkg.getImplementationTitle() ) );
261: // ref.add ( new StringRefAddr( "vendor", pkg.getImplementationVendor() ) );
262: // ref.add ( new StringRefAddr( "version", pkg.getImplementationVersion() ) );
263: // }
264: // return ref;
265: }
266:
267: public Object getObjectInstance(Object refObj, Name name,
268: Context nameCtx, Hashtable env) {
269: Reference ref;
270:
271: // Can only reconstruct from a reference.
272: if (refObj instanceof Reference) {
273: return this ;
274: } else if (refObj instanceof Remote) {
275: return refObj;
276: } else {
277: return null;
278: }
279: }
280:
281: public static ExternalTransaction getInstance() {
282: throw new RuntimeException(
283: "ExternalTransaction.getInstance() not implemented yet.");
284: // return new ExternalTransaction (database);
285: }
286:
287: }
|