KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > mmbase > module > core > TransactionManager


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 package org.mmbase.module.core;
11
12 import java.util.*;
13 import org.mmbase.module.corebuilders.*;
14
15 import org.mmbase.util.logging.Logger;
16 import org.mmbase.util.logging.Logging;
17 import org.mmbase.security.*;
18
19 /**
20  * @javadoc
21  * @author Rico Jansen
22  * @version $Id: TransactionManager.java,v 1.34 2006/07/06 11:24:44 michiel Exp $
23  */

24 public class TransactionManager implements TransactionManagerInterface {
25
26     private static final Logger log = Logging.getLoggerInstance(TransactionManager.class);
27
28     public static final String JavaDoc EXISTS_NO = "no";
29     public static final int I_EXISTS_NO = 0;
30     public static final String JavaDoc EXISTS_YES = "yes";
31     public static final int I_EXISTS_YES = 1;
32     public static final String JavaDoc EXISTS_NOLONGER = "nolonger";
33     public static final int I_EXISTS_NOLONGER = 2;
34
35     private TemporaryNodeManagerInterface tmpNodeManager;
36     private MMBase mmbase;
37     protected Map transactions = new HashMap(); /* String -> Collection */
38     protected TransactionResolver transactionResolver;
39
40     public TransactionManager(MMBase mmbase, TemporaryNodeManagerInterface tmpn) {
41         this.mmbase = mmbase;
42         this.tmpNodeManager = tmpn;
43         transactionResolver = new TransactionResolver(mmbase);
44         mmbase.getMMBaseCop();
45     }
46     /**
47      * Returns transaction with given name.
48      * @param transactionName The name of the transaction to return
49      * @exception TransactionManagerExcpeption if the transaction with given name does not exist
50      * @return Collection containing the nodes in this transaction (as {@link org.mmbase.module.core.MMObjectNode}s).
51      */

52     synchronized public Collection getTransaction(String JavaDoc transactionName) throws TransactionManagerException {
53         Collection transaction = (Collection) transactions.get(transactionName);
54         if (transaction == null) {
55             throw new TransactionManagerException("Transaction " + transactionName + " does not exist (existing are " + transactions.keySet() + ")");
56         } else {
57             return transaction;
58         }
59     }
60
61     /**
62      * Creates transaction with given name.
63      * @param transactionName The name of the transaction to return
64      * @exception TransactionManagerExcpeption if the transaction with given name existed already
65      * @return Collection containing the nodes in this transaction (so, this is an empty collection)
66      */

67     synchronized public Collection createTransaction(String JavaDoc transactionName) throws TransactionManagerException {
68         if (!transactions.containsKey(transactionName)) {
69             Vector transactionNodes = new Vector();
70             transactions.put(transactionName, transactionNodes);
71             return transactionNodes;
72         } else {
73             throw new TransactionManagerException("Transaction " + transactionName + " already exists");
74         }
75     }
76
77     /**
78      * Removes the transaction with given name
79      * @return the collection with nodes from the removed transaction or <code>null</code> if no transaction with this name existed
80      */

81     synchronized protected Collection deleteTransaction(String JavaDoc transactionName) {
82         return (Collection) transactions.remove(transactionName);
83     }
84
85     /**
86      * @deprecated use {@link #getTransaction}
87      */

88     public Vector getNodes(Object JavaDoc user, String JavaDoc transactionName) {
89         try {
90             return (Vector)getTransaction(transactionName);
91         } catch (TransactionManagerException tme) {
92             return null;
93         }
94     }
95
96     /**
97      * Creates a new transaction with given name
98      * @param user This parameter is ignored (WTF!)
99      * @param transactionName The name of the transaction to create
100      * @exception TransactionManagerExcpeption if the transaction with given name already existed
101      * @return transactionName
102      * @deprecated Use {@link #createTransaction}
103      */

104     public String JavaDoc create(Object JavaDoc user, String JavaDoc transactionName) throws TransactionManagerException {
105         createTransaction(transactionName);
106         if (log.isDebugEnabled()) {
107             log.debug("Create transaction for " + transactionName);
108         }
109         return transactionName;
110     }
111
112     /**
113      * Returns the (existing) transaction with given name.
114      * @param user This parameter is ignored (WTF!)
115      * @param transactionName The name of the transaction to return
116      * @exception TransactionManagerExcpeption if the transaction with given name does not exist
117      * @deprecated use {@link #getTransaction}
118      */

119     public Collection get(Object JavaDoc user, String JavaDoc transactionName) throws TransactionManagerException {
120         return getTransaction(transactionName);
121     }
122
123     public String JavaDoc addNode(String JavaDoc transactionName, String JavaDoc owner, String JavaDoc tmpnumber)
124         throws TransactionManagerException {
125         Collection transaction = getTransaction(transactionName);
126         MMObjectNode node = tmpNodeManager.getNode(owner, tmpnumber);
127         if (node != null) {
128             if (!transaction.contains(node)) {
129                 transaction.add(node);
130 // } else {
131
// throw new TransactionManagerException(
132
// "Node " + tmpnumber + " not added as it was already in transaction " + transactionName);
133
}
134         } else {
135             throw new TransactionManagerException("Node " + tmpnumber + " doesn't exist.");
136         }
137         return tmpnumber;
138     }
139
140     public String JavaDoc removeNode(String JavaDoc transactionName, String JavaDoc owner, String JavaDoc tmpnumber)
141         throws TransactionManagerException {
142         Collection transaction = getTransaction(transactionName);
143         MMObjectNode node = tmpNodeManager.getNode(owner, tmpnumber);
144         if (node!=null) {
145             if (transaction.contains(node)) {
146                 transaction.remove(node);
147 // } else {
148
// throw new TransactionManagerException("Node " + tmpnumber + " is not in transaction " + transactionName);
149
}
150         } else {
151             throw new TransactionManagerException("Node " + tmpnumber + " doesn't exist.");
152         }
153         return tmpnumber;
154     }
155
156     public String JavaDoc deleteObject(String JavaDoc transactionName, String JavaDoc owner, String JavaDoc tmpnumber)
157         throws TransactionManagerException {
158         Collection transaction = getTransaction(transactionName);
159         MMObjectNode node = tmpNodeManager.getNode(owner, tmpnumber);
160         if (node!=null) {
161             if (transaction.contains(node)) {
162                 // Mark it as deleted
163
node.setValue("_exists",EXISTS_NOLONGER);
164              } else {
165                 throw new TransactionManagerException("Node " + tmpnumber + " is not in transaction " + transactionName);
166             }
167         } else {
168             throw new TransactionManagerException("Node " + tmpnumber + " doesn't exist.");
169         }
170         return tmpnumber;
171     }
172
173     public String JavaDoc cancel(Object JavaDoc user, String JavaDoc transactionName) throws TransactionManagerException {
174         Collection transaction = getTransaction(transactionName);
175         // remove nodes from the temporary node cache
176
MMObjectBuilder builder = mmbase.getTypeDef();
177         for (Iterator i = transaction.iterator(); i.hasNext(); ) {
178             MMObjectNode node=(MMObjectNode)i.next();
179             builder.removeTmpNode(node.getStringValue(MMObjectBuilder.TMP_FIELD_NUMBER));
180         }
181         deleteTransaction(transactionName);
182         if (log.isDebugEnabled()) {
183             log.debug("Removed transaction (after cancel) " + transactionName + "\n" + transaction);
184         }
185         return transactionName;
186     }
187
188     public String JavaDoc commit(Object JavaDoc user, String JavaDoc transactionName) throws TransactionManagerException {
189         Collection transaction = getTransaction(transactionName);
190         try {
191             boolean resolved = transactionResolver.resolve(transaction);
192             if (!resolved) {
193                 log.error("Can't resolve transaction " + transactionName);
194                 log.error("Nodes \n" + transaction);
195                 throw new TransactionManagerException("Can't resolve transaction " + transactionName + "" + transaction);
196             } else {
197                 resolved = performCommits(user, transaction);
198                 if (!resolved) {
199                     log.error("Can't commit transaction " + transactionName);
200                     log.error("Nodes \n" + transaction);
201                     throw new TransactionManagerException("Can't commit transaction " + transactionName);
202                 }
203             }
204         } finally {
205             // remove nodes from the temporary node cache
206
MMObjectBuilder builder = mmbase.getTypeDef();
207             for (Iterator i = transaction.iterator(); i.hasNext(); ) {
208                 MMObjectNode node=(MMObjectNode)i.next();
209                 builder.removeTmpNode(node.getStringValue(MMObjectBuilder.TMP_FIELD_NUMBER));
210             }
211             deleteTransaction(transactionName);
212             if (log.isDebugEnabled()) {
213                 log.debug("Removed transaction (after commit) " + transactionName + "\n" + transaction);
214             }
215         }
216         return transactionName;
217     }
218
219     private final static int UNCOMMITED = 0;
220     private final static int COMMITED = 1;
221     private final static int FAILED = 2;
222     private final static int NODE = 3;
223     private final static int RELATION = 4;
224
225     boolean performCommits(Object JavaDoc user, Collection nodes) {
226         if (nodes == null || nodes.size() == 0) {
227             log.warn("Empty list of nodes");
228             return true;
229         }
230
231         int[] nodestate = new int[nodes.size()];
232         int[] nodeexist = new int[nodes.size()];
233         String JavaDoc username = findUserName(user),exists;
234
235         log.debug("Checking types and existance");
236
237         int i = 0;
238         for (Iterator nodeIterator = nodes.iterator(); nodeIterator.hasNext(); i++) {
239             MMObjectNode node = (MMObjectNode)nodeIterator.next();
240             // Nodes are uncommited by default
241
nodestate[i] = UNCOMMITED;
242             exists = node.getStringValue("_exists");
243             if (exists == null) {
244                 throw new IllegalStateException JavaDoc("The _exists field does not exist on node "+node);
245             } else if (exists.equals(EXISTS_NO)) {
246                 nodeexist[i]=I_EXISTS_NO;
247             } else if (exists.equals(EXISTS_YES)) {
248                 nodeexist[i]=I_EXISTS_YES;
249             } else if (exists.equals(EXISTS_NOLONGER)) {
250                 nodeexist[i]=I_EXISTS_NOLONGER;
251             } else {
252                 throw new IllegalStateException JavaDoc("Invalid value for _exists on node "+node);
253             }
254         }
255
256         log.debug("Commiting nodes");
257
258         // First commit all the NODES
259
i = 0;
260         for (Iterator nodeIterator = nodes.iterator(); nodeIterator.hasNext(); i++) {
261             MMObjectNode node = (MMObjectNode)nodeIterator.next();
262             if (!(node.getBuilder() instanceof InsRel)) {
263                 if (nodeexist[i] == I_EXISTS_YES ) {
264                     // use safe commit, which locks the node cache
265
boolean commitOK;
266                     if (user instanceof UserContext) {
267                         commitOK = node.commit((UserContext)user);
268                     } else {
269                         commitOK = node.parent.safeCommit(node);
270                     }
271                     if (commitOK) {
272                         nodestate[i] = COMMITED;
273                     } else {
274                         nodestate[i] = FAILED;
275                     }
276                 } else if (nodeexist[i] == I_EXISTS_NO ) {
277                     int insertOK;
278                     if (user instanceof UserContext) {
279                         insertOK = node.insert((UserContext)user);
280                     } else {
281                         insertOK = node.parent.safeInsert(node, username);
282                     }
283                     if (insertOK > 0) {
284                         nodestate[i] = COMMITED;
285                     } else {
286                         nodestate[i] = FAILED;
287                         String JavaDoc message = "When this failed, it is possible that the creation of an insrel went right, which leads to a database inconsistency.. stop now.. (transaction 2.0: [rollback?])";
288                         log.error(message);
289                         throw new RuntimeException JavaDoc(message);
290                     }
291                 }
292             }
293         }
294
295         log.debug("Commiting relations");
296
297         // Then commit all the RELATIONS
298
i = 0;
299         for (Iterator nodeIterator = nodes.iterator(); nodeIterator.hasNext(); i++) {
300             MMObjectNode node = (MMObjectNode)nodeIterator.next();
301             if (node.getBuilder() instanceof InsRel) {
302                 // excactly the same code as 10 lines ago. Should be dispatched to some method..
303
if (nodeexist[i] == I_EXISTS_YES ) {
304                     boolean commitOK;
305                     if (user instanceof UserContext) {
306                         commitOK = node.commit((UserContext)user);
307                     } else {
308                         commitOK = node.parent.safeCommit(node);
309                     }
310                     if (commitOK) {
311                         nodestate[i] = COMMITED;
312                     } else {
313                         nodestate[i] = FAILED;
314                     }
315                 } else if (nodeexist[i] == I_EXISTS_NO ) {
316                     int insertOK;
317                     if (user instanceof UserContext) {
318                         insertOK = node.insert((UserContext)user);
319                     } else {
320                         insertOK = node.parent.safeInsert(node, username);
321                     }
322                     if (insertOK > 0) {
323                         nodestate[i] = COMMITED;
324                     } else {
325                         nodestate[i] = FAILED;
326                         String JavaDoc message = "relation failed(transaction 2.0: [rollback?])";
327                         log.error(message);
328                     }
329                 }
330             }
331         }
332
333         log.debug("Deleting relations");
334
335         // Then commit all the RELATIONS that must be deleted
336
i = 0;
337         for (Iterator nodeIterator = nodes.iterator(); nodeIterator.hasNext(); i++) {
338             MMObjectNode node = (MMObjectNode)nodeIterator.next();
339             if (node.getBuilder() instanceof InsRel && nodeexist[i] == I_EXISTS_NOLONGER) {
340                 // no return information
341
if (user instanceof UserContext) {
342                     node.remove((UserContext)user);
343                 } else {
344                     node.parent.removeNode(node);
345                 }
346                 nodestate[i]=COMMITED;
347             }
348         }
349
350         log.debug("Deleting nodes");
351         // Then commit all the NODES that must be deleted
352
i = 0;
353         for (Iterator nodeIterator = nodes.iterator(); nodeIterator.hasNext(); i++) {
354             MMObjectNode node = (MMObjectNode)nodeIterator.next();
355             if (!(node.getBuilder() instanceof InsRel) && (nodeexist[i] == I_EXISTS_NOLONGER)) {
356                 // no return information
357
if (user instanceof UserContext) {
358                     node.remove((UserContext)user);
359                 } else {
360                     node.parent.removeNode(node);
361                 }
362                 nodestate[i]=COMMITED;
363             }
364         }
365
366         // check for failures
367
boolean okay=true;
368         i = 0;
369         for (Iterator nodeIterator = nodes.iterator(); nodeIterator.hasNext(); i++) {
370             MMObjectNode node = (MMObjectNode)nodeIterator.next();
371             if (nodestate[i] == FAILED) {
372                 okay=false;
373                 log.error("Failed node "+node.toString());
374             }
375         }
376         return okay;
377     }
378
379     public String JavaDoc findUserName(Object JavaDoc user) {
380         if (user instanceof UserContext) {
381             return ((UserContext)user).getIdentifier();
382         } else {
383             return "";
384         }
385     }
386
387 }
388
Popular Tags