KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > geronimo > transaction > manager > RecoveryImpl


1 /**
2  * Licensed to the Apache Software Foundation (ASF) under one or more
3  * contributor license agreements. See the NOTICE file distributed with
4  * this work for additional information regarding copyright ownership.
5  * The ASF licenses this file to You under the Apache License, Version 2.0
6  * (the "License"); you may not use this file except in compliance with
7  * the License. You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */

17
18 package org.apache.geronimo.transaction.manager;
19
20 import java.util.HashMap JavaDoc;
21 import java.util.Iterator JavaDoc;
22 import java.util.List JavaDoc;
23 import java.util.Map JavaDoc;
24 import java.util.Set JavaDoc;
25 import java.util.ArrayList JavaDoc;
26 import java.util.Collections JavaDoc;
27 import java.util.Arrays JavaDoc;
28 import java.util.HashSet JavaDoc;
29 import java.util.Collection JavaDoc;
30
31 import javax.transaction.SystemException JavaDoc;
32 import javax.transaction.xa.XAException JavaDoc;
33 import javax.transaction.xa.XAResource JavaDoc;
34 import javax.transaction.xa.Xid JavaDoc;
35
36 import org.apache.commons.logging.Log;
37 import org.apache.commons.logging.LogFactory;
38
39 /**
40  *
41  *
42  * @version $Rev: 476049 $ $Date: 2006-11-16 23:35:17 -0500 (Thu, 16 Nov 2006) $
43  *
44  * */

45 public class RecoveryImpl implements Recovery {
46     private static final Log log = LogFactory.getLog("Recovery");
47
48     private final TransactionLog txLog;
49     private final XidFactory xidFactory;
50
51     private final Map JavaDoc externalXids = new HashMap JavaDoc();
52     private final Map JavaDoc ourXids = new HashMap JavaDoc();
53     private final Map JavaDoc nameToOurTxMap = new HashMap JavaDoc();
54     private final Map JavaDoc externalGlobalIdMap = new HashMap JavaDoc();
55
56     private final List JavaDoc recoveryErrors = new ArrayList JavaDoc();
57
58     public RecoveryImpl(final TransactionLog txLog, final XidFactory xidFactory) {
59         this.txLog = txLog;
60         this.xidFactory = xidFactory;
61     }
62
63     public synchronized void recoverLog() throws XAException JavaDoc {
64         Collection JavaDoc preparedXids = null;
65         try {
66             preparedXids = txLog.recover(xidFactory);
67         } catch (LogException e) {
68             throw (XAException JavaDoc) new XAException JavaDoc(XAException.XAER_RMERR).initCause(e);
69         }
70         for (Iterator JavaDoc iterator = preparedXids.iterator(); iterator.hasNext();) {
71             XidBranchesPair xidBranchesPair = (Recovery.XidBranchesPair) iterator.next();
72             Xid JavaDoc xid = xidBranchesPair.getXid();
73             if (xidFactory.matchesGlobalId(xid.getGlobalTransactionId())) {
74                 ourXids.put(new ByteArrayWrapper(xid.getGlobalTransactionId()), xidBranchesPair);
75                 for (Iterator JavaDoc branches = xidBranchesPair.getBranches().iterator(); branches.hasNext();) {
76                     String JavaDoc name = ((TransactionBranchInfo) branches.next()).getResourceName();
77                     Set JavaDoc transactionsForName = (Set JavaDoc)nameToOurTxMap.get(name);
78                     if (transactionsForName == null) {
79                         transactionsForName = new HashSet JavaDoc();
80                         nameToOurTxMap.put(name, transactionsForName);
81                     }
82                     transactionsForName.add(xidBranchesPair);
83                 }
84             } else {
85                 TransactionImpl externalTx = new ExternalTransaction(xid, txLog, xidBranchesPair.getBranches());
86                 externalXids.put(xid, externalTx);
87                 externalGlobalIdMap.put(xid.getGlobalTransactionId(), externalTx);
88             }
89         }
90     }
91
92
93     public synchronized void recoverResourceManager(NamedXAResource xaResource) throws XAException JavaDoc {
94         String JavaDoc name = xaResource.getName();
95         Xid JavaDoc[] prepared = xaResource.recover(XAResource.TMSTARTRSCAN + XAResource.TMENDRSCAN);
96         for (int i = 0; i < prepared.length; i++) {
97             Xid JavaDoc xid = prepared[i];
98             ByteArrayWrapper globalIdWrapper = new ByteArrayWrapper(xid.getGlobalTransactionId());
99             XidBranchesPair xidNamesPair = (XidBranchesPair) ourXids.get(globalIdWrapper);
100             if (xidNamesPair != null) {
101                 try {
102                     xaResource.commit(xid, false);
103                 } catch (XAException JavaDoc e) {
104                     recoveryErrors.add(e);
105                     log.error(e);
106                 }
107                 removeNameFromTransaction(xidNamesPair, name, true);
108             } else if (xidFactory.matchesGlobalId(xid.getGlobalTransactionId())) {
109                 //ours, but prepare not logged
110
try {
111                     xaResource.rollback(xid);
112                 } catch (XAException JavaDoc e) {
113                     recoveryErrors.add(e);
114                     log.error(e);
115                 }
116             } else if (xidFactory.matchesBranchId(xid.getBranchQualifier())) {
117                 //our branch, but we did not start this tx.
118
TransactionImpl externalTx = (TransactionImpl) externalGlobalIdMap.get(xid.getGlobalTransactionId());
119                 if (externalTx == null) {
120                     //we did not prepare this branch, rollback.
121
try {
122                         xaResource.rollback(xid);
123                     } catch (XAException JavaDoc e) {
124                         recoveryErrors.add(e);
125                         log.error(e);
126                     }
127                 } else {
128                     //we prepared this branch, must wait for commit/rollback command.
129
externalTx.addBranchXid(xaResource, xid);
130                 }
131             }
132             //else we had nothing to do with this xid.
133
}
134         Set JavaDoc transactionsForName = (Set JavaDoc)nameToOurTxMap.get(name);
135         if (transactionsForName != null) {
136             for (Iterator JavaDoc transactions = transactionsForName.iterator(); transactions.hasNext();) {
137                 XidBranchesPair xidBranchesPair = (XidBranchesPair) transactions.next();
138                 removeNameFromTransaction(xidBranchesPair, name, false);
139             }
140         }
141     }
142
143     private void removeNameFromTransaction(XidBranchesPair xidBranchesPair, String JavaDoc name, boolean warn) {
144         int removed = 0;
145         for (Iterator JavaDoc branches = xidBranchesPair.getBranches().iterator(); branches.hasNext();) {
146             TransactionBranchInfo transactionBranchInfo = (TransactionBranchInfo) branches.next();
147             if (name.equals(transactionBranchInfo.getResourceName())) {
148                 branches.remove();
149                 removed++;
150             }
151         }
152         if (warn && removed == 0) {
153             log.error("XAResource named: " + name + " returned branch xid for xid: " + xidBranchesPair.getXid() + " but was not registered with that transaction!");
154         }
155         if (xidBranchesPair.getBranches().isEmpty() && 0 != removed ) {
156             try {
157                 ourXids.remove(new ByteArrayWrapper(xidBranchesPair.getXid().getGlobalTransactionId()));
158                 txLog.commit(xidBranchesPair.getXid(), xidBranchesPair.getMark());
159             } catch (LogException e) {
160                 recoveryErrors.add(e);
161                 log.error(e);
162             }
163         }
164     }
165
166     public synchronized boolean hasRecoveryErrors() {
167         return !recoveryErrors.isEmpty();
168     }
169
170     public synchronized List JavaDoc getRecoveryErrors() {
171         return Collections.unmodifiableList(recoveryErrors);
172     }
173
174     public synchronized boolean localRecoveryComplete() {
175         return ourXids.isEmpty();
176     }
177
178     public synchronized int localUnrecoveredCount() {
179         return ourXids.size();
180     }
181
182     //hard to implement.. needs ExternalTransaction to have a reference to externalXids.
183
// public boolean remoteRecoveryComplete() {
184
// }
185

186     public synchronized Map JavaDoc getExternalXids() {
187         return new HashMap JavaDoc(externalXids);
188     }
189
190     private static class ByteArrayWrapper {
191         private final byte[] bytes;
192         private final int hashCode;
193
194         public ByteArrayWrapper(final byte[] bytes) {
195             assert bytes != null;
196             this.bytes = bytes;
197             int hash = 0;
198             for (int i = 0; i < bytes.length; i++) {
199                 hash += 37 * bytes[i];
200             }
201             hashCode = hash;
202         }
203
204         public boolean equals(Object JavaDoc other) {
205             if (other instanceof ByteArrayWrapper) {
206                 return Arrays.equals(bytes, ((ByteArrayWrapper)other).bytes);
207             }
208             return false;
209         }
210
211         public int hashCode() {
212             return hashCode;
213         }
214     }
215
216     private static class ExternalTransaction extends TransactionImpl {
217         private Set JavaDoc resourceNames;
218
219         public ExternalTransaction(Xid JavaDoc xid, TransactionLog txLog, Set JavaDoc resourceNames) {
220             super(xid, txLog);
221             this.resourceNames = resourceNames;
222         }
223
224         public boolean hasName(String JavaDoc name) {
225             return resourceNames.contains(name);
226         }
227
228         public void removeName(String JavaDoc name) {
229             resourceNames.remove(name);
230         }
231
232         public void preparedCommit() throws SystemException JavaDoc {
233             if (!resourceNames.isEmpty()) {
234                 throw new SystemException JavaDoc("This tx does not have all resource managers online, commit not allowed yet");
235             }
236             super.preparedCommit();
237         }
238
239         public void rollback() throws SystemException JavaDoc {
240             if (!resourceNames.isEmpty()) {
241                 throw new SystemException JavaDoc("This tx does not have all resource managers online, rollback not allowed yet");
242             }
243             super.rollback();
244
245         }
246     }
247 }
248
Popular Tags