KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > mmbase > bridge > implementation > BasicTransaction


1 /*
2
3 This software is OSI Certified Open Source Software.
4 OSI Certified is a certification mark of the Open Source Initiative.
5
6 The license (Mozilla version 1.0) can be read at the MMBase site.
7 See http://www.MMBase.org/license
8
9 */

10
11 package org.mmbase.bridge.implementation;
12
13 import java.util.*;
14 import org.mmbase.bridge.*;
15 import org.mmbase.module.core.*;
16 import org.mmbase.util.logging.*;
17
18 /**
19  * The basic implementation for a Transaction cLoud.
20  * A Transaction cloud is a cloud which buffers allc hanegs made to nodes -
21  * which means that chanegs are committed only if you commit the transaction itself.
22  * This mechanism allows you to rollback changes if something goes wrong.
23  * @author Pierre van Rooden
24  * @version $Id: BasicTransaction.java,v 1.25 2006/06/22 07:52:14 nklasens Exp $
25  */

26 public class BasicTransaction extends BasicCloud implements Transaction {
27
28     private static final Logger log = Logging.getLoggerInstance(BasicTransaction.class);
29     /**
30      * The id of the transaction for use with the transaction manager.
31      */

32     protected final String JavaDoc transactionContext;
33
34     private boolean canceled = false;
35     private boolean committed = false;
36     /**
37      * The name of the transaction as used by the user.
38      */

39     protected final String JavaDoc transactionName;
40
41     protected final BasicCloud parentCloud;
42
43     /*
44      * Constructor to call from the CloudContext class.
45      * Package only, so cannot be reached from a script.
46      * @param transactionName name of the transaction (assigned by the user)
47      * @param cloud The cloud this transaction is working on
48      */

49     BasicTransaction(String JavaDoc transactionName, BasicCloud cloud) {
50         super(transactionName, cloud);
51         this.transactionName = transactionName;
52         this.parentCloud = cloud;
53
54         // if the parent cloud is itself a transaction,
55
// do not create a new one, just use that context instead!
56
// this allows for nesting of transactions without loosing performance
57
// due to additional administration
58
if (parentCloud instanceof BasicTransaction) {
59             transactionContext = ((BasicTransaction)parentCloud).transactionContext;
60         } else {
61             try {
62                 // XXX: the current transaction manager does not allow multiple transactions with the
63
// same name for different users
64
// We solved this here, but this should really be handled in the Transactionmanager.
65
transactionContext = account + "_" + transactionName;
66                 BasicCloudContext.transactionManager.createTransaction(transactionContext);
67             } catch (TransactionManagerException e) {
68                 throw new BridgeException(e.getMessage(), e);
69             }
70         }
71     }
72
73
74     public synchronized boolean commit() {
75         if (canceled) {
76             throw new BridgeException("Cannot commit transaction'" + name + "' (" + transactionContext +"), it was already canceled.");
77         }
78         if (committed) {
79             throw new BridgeException("Cannot commit transaction'" + name + "' (" + transactionContext +"), it was already committed.");
80         }
81         log.debug("Committing transaction " + transactionContext);
82
83         parentCloud.transactions.remove(transactionName); // hmpf
84

85         // if this is a transaction within a transaction (theoretically possible)
86
// leave the committing to the 'parent' transaction
87
if (parentCloud instanceof Transaction) {
88             // do nothing
89
} else {
90             try {
91                 Collection col = BasicCloudContext.transactionManager.getTransaction(transactionContext);
92                 // BasicCloudContext.transactionManager.commit(account, transactionContext);
93
BasicCloudContext.transactionManager.commit(userContext, transactionContext);
94                 // This is a hack to call the commitprocessors which are only available in the bridge.
95
// The EXISTS_NOLONGER check is required to prevent committing of deleted nodes.
96
Iterator i = col.iterator();
97                 while (i.hasNext()) {
98                     MMObjectNode n = (MMObjectNode) i.next();
99                     if (!TransactionManager.EXISTS_NOLONGER.equals(n.getStringValue("_exists"))) {
100                         Node node = parentCloud.makeNode(n, "" + n.getNumber());
101                         node.commit();
102                     }
103                 }
104             } catch (TransactionManagerException e) {
105                 // do we drop the transaction here or delete the trans context?
106
// return false;
107
throw new BridgeException(e.getMessage(), e);
108             }
109         }
110
111         committed = true;
112         return true;
113     }
114
115     public synchronized void cancel() {
116         if (canceled) {
117             throw new BridgeException("Cannot cancel transaction'" + name + "' (" + transactionContext +"), it was already canceled.");
118         }
119         if (committed) {
120             throw new BridgeException("Cannot cancel transaction'" + name + "' (" + transactionContext +"), it was already committed.");
121         }
122
123         // if this is a transaction within a transaction (theoretically possible)
124
// call the 'parent' transaction to cancel everything
125
if (parentCloud instanceof Transaction) {
126             ((Transaction)parentCloud).cancel();
127         } else {
128             try {
129             // BasicCloudContext.transactionManager.cancel(account, transactionContext);
130
BasicCloudContext.transactionManager.cancel(userContext, transactionContext);
131             } catch (TransactionManagerException e) {
132                 // do we drop the transaction here or delete the trans context?
133
throw new BridgeException(e.getMessage(), e);
134             }
135         }
136         // remove the transaction from the parent cloud
137
parentCloud.transactions.remove(transactionName);
138         canceled = true;
139     }
140
141     /*
142      * Transaction-notification: add a new temporary node to a transaction.
143      * @param currentObjectContext the context of the object to add
144      */

145     void add(String JavaDoc currentObjectContext) {
146         try {
147             BasicCloudContext.transactionManager.addNode(transactionContext, account, currentObjectContext);
148         } catch (TransactionManagerException e) {
149             throw new BridgeException(e.getMessage(), e);
150         }
151     }
152
153     /*
154      * Transaction-notification: remove a temporary (not yet committed) node in a transaction.
155      * @param currentObjectContext the context of the object to remove
156      */

157     void remove(String JavaDoc currentObjectContext) {
158         try {
159             BasicCloudContext.transactionManager.removeNode(transactionContext, account, currentObjectContext);
160         } catch (TransactionManagerException e) {
161             throw new BridgeException(e.getMessage(), e);
162         }
163     }
164
165     void delete(String JavaDoc currentObjectContext, MMObjectNode node) {
166         delete(currentObjectContext);
167     }
168     /*
169      * Transaction-notification: remove an existing node in a transaction.
170      * @param currentObjectContext the context of the object to remove
171      */

172     void delete(String JavaDoc currentObjectContext) {
173         try {
174             BasicCloudContext.transactionManager.deleteObject(transactionContext, account, currentObjectContext);
175         } catch (TransactionManagerException e) {
176             throw new BridgeException(e.getMessage(), e);
177         }
178     }
179
180     boolean contains(MMObjectNode node) {
181         // additional check, so transaction can still get nodes after it has committed.
182
if (transactionContext == null) {
183             return false;
184         }
185         try {
186             Collection transaction = BasicCloudContext.transactionManager.get(account, transactionContext);
187             return transaction.contains(node);
188         } catch (TransactionManagerException tme) {
189             throw new BridgeException(tme.getMessage(), tme);
190         }
191     }
192
193     /**
194      * If this Transaction is scheduled to be garbage collected, the transaction is canceled and cleaned up.
195      * Unless it has already been committed/canceled, ofcourse, and
196      * unless the parentcloud of a transaction is a transaction itself.
197      * In that case, the parent transaction should cancel!
198      * This means that a transaction is always cleared - if it 'times out', or is not properly removed, it will
199      * eventually be removed from the MMBase cache.
200      */

201     protected void finalize() {
202         if ((transactionContext != null) && !(parentCloud instanceof Transaction)) {
203             cancel();
204         }
205     }
206
207     public boolean isCanceled() {
208         return canceled;
209     }
210     public boolean isCommitted() {
211         return committed;
212     }
213
214     /**
215      * @see org.mmbase.bridge.Transaction#getCloudName()
216      */

217     public String JavaDoc getCloudName() {
218         if (parentCloud instanceof Transaction) {
219             return ((Transaction) parentCloud).getCloudName();
220         }
221         else {
222             return parentCloud.getName();
223         }
224     }
225 }
226
227
Popular Tags