1 17 18 package org.apache.geronimo.transaction.manager; 19 20 import java.util.HashMap ; 21 import java.util.Iterator ; 22 import java.util.List ; 23 import java.util.Map ; 24 import java.util.Set ; 25 import java.util.ArrayList ; 26 import java.util.Collections ; 27 import java.util.Arrays ; 28 import java.util.HashSet ; 29 import java.util.Collection ; 30 31 import javax.transaction.SystemException ; 32 import javax.transaction.xa.XAException ; 33 import javax.transaction.xa.XAResource ; 34 import javax.transaction.xa.Xid ; 35 36 import org.apache.commons.logging.Log; 37 import org.apache.commons.logging.LogFactory; 38 39 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 externalXids = new HashMap (); 52 private final Map ourXids = new HashMap (); 53 private final Map nameToOurTxMap = new HashMap (); 54 private final Map externalGlobalIdMap = new HashMap (); 55 56 private final List recoveryErrors = new ArrayList (); 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 { 64 Collection preparedXids = null; 65 try { 66 preparedXids = txLog.recover(xidFactory); 67 } catch (LogException e) { 68 throw (XAException ) new XAException (XAException.XAER_RMERR).initCause(e); 69 } 70 for (Iterator iterator = preparedXids.iterator(); iterator.hasNext();) { 71 XidBranchesPair xidBranchesPair = (Recovery.XidBranchesPair) iterator.next(); 72 Xid xid = xidBranchesPair.getXid(); 73 if (xidFactory.matchesGlobalId(xid.getGlobalTransactionId())) { 74 ourXids.put(new ByteArrayWrapper(xid.getGlobalTransactionId()), xidBranchesPair); 75 for (Iterator branches = xidBranchesPair.getBranches().iterator(); branches.hasNext();) { 76 String name = ((TransactionBranchInfo) branches.next()).getResourceName(); 77 Set transactionsForName = (Set )nameToOurTxMap.get(name); 78 if (transactionsForName == null) { 79 transactionsForName = new HashSet (); 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 { 94 String name = xaResource.getName(); 95 Xid [] prepared = xaResource.recover(XAResource.TMSTARTRSCAN + XAResource.TMENDRSCAN); 96 for (int i = 0; i < prepared.length; i++) { 97 Xid 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 e) { 104 recoveryErrors.add(e); 105 log.error(e); 106 } 107 removeNameFromTransaction(xidNamesPair, name, true); 108 } else if (xidFactory.matchesGlobalId(xid.getGlobalTransactionId())) { 109 try { 111 xaResource.rollback(xid); 112 } catch (XAException e) { 113 recoveryErrors.add(e); 114 log.error(e); 115 } 116 } else if (xidFactory.matchesBranchId(xid.getBranchQualifier())) { 117 TransactionImpl externalTx = (TransactionImpl) externalGlobalIdMap.get(xid.getGlobalTransactionId()); 119 if (externalTx == null) { 120 try { 122 xaResource.rollback(xid); 123 } catch (XAException e) { 124 recoveryErrors.add(e); 125 log.error(e); 126 } 127 } else { 128 externalTx.addBranchXid(xaResource, xid); 130 } 131 } 132 } 134 Set transactionsForName = (Set )nameToOurTxMap.get(name); 135 if (transactionsForName != null) { 136 for (Iterator 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 name, boolean warn) { 144 int removed = 0; 145 for (Iterator 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 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 186 public synchronized Map getExternalXids() { 187 return new HashMap (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 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 resourceNames; 218 219 public ExternalTransaction(Xid xid, TransactionLog txLog, Set resourceNames) { 220 super(xid, txLog); 221 this.resourceNames = resourceNames; 222 } 223 224 public boolean hasName(String name) { 225 return resourceNames.contains(name); 226 } 227 228 public void removeName(String name) { 229 resourceNames.remove(name); 230 } 231 232 public void preparedCommit() throws SystemException { 233 if (!resourceNames.isEmpty()) { 234 throw new SystemException ("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 { 240 if (!resourceNames.isEmpty()) { 241 throw new SystemException ("This tx does not have all resource managers online, rollback not allowed yet"); 242 } 243 super.rollback(); 244 245 } 246 } 247 } 248 | Popular Tags |