1 22 package org.jboss.ejb; 23 24 import org.jboss.logging.Logger; 25 import org.jboss.tm.TransactionLocal; 26 27 import javax.ejb.EJBException ; 28 import javax.transaction.RollbackException ; 29 import javax.transaction.Status ; 30 import javax.transaction.Synchronization ; 31 import javax.transaction.SystemException ; 32 import javax.transaction.Transaction ; 33 import java.util.ArrayList ; 34 import java.util.List ; 35 36 49 public class GlobalTxEntityMap 50 { 51 private static final Logger log = Logger.getLogger(GlobalTxEntityMap.class); 52 53 private final TransactionLocal txSynch = new TransactionLocal(); 54 55 64 public static interface TxAssociation 65 { 66 74 void scheduleSync(Transaction tx, EntityEnterpriseContext instance) 75 throws SystemException , RollbackException ; 76 77 84 void synchronize(Thread thread, Transaction tx, EntityEnterpriseContext instance) 85 throws Exception ; 86 87 93 void invokeEjbStore(Thread thread, EntityEnterpriseContext instance) 94 throws Exception ; 95 } 96 97 public static final TxAssociation NONE = new TxAssociation() 98 { 99 public void scheduleSync(Transaction tx, EntityEnterpriseContext instance) 100 throws SystemException , RollbackException 101 { 102 EntityContainer.getGlobalTxEntityMap().associate(tx, instance); 103 instance.setTxAssociation(SYNC_SCHEDULED); 104 } 105 106 public void synchronize(Thread thread, Transaction tx, EntityEnterpriseContext instance) 107 { 108 throw new UnsupportedOperationException (); 109 } 110 111 public void invokeEjbStore(Thread thread, EntityEnterpriseContext instance) 112 { 113 throw new UnsupportedOperationException (); 114 } 115 }; 116 117 public static final TxAssociation SYNC_SCHEDULED = new TxAssociation() 118 { 119 public void scheduleSync(Transaction tx, EntityEnterpriseContext instance) 120 { 121 } 122 123 public void invokeEjbStore(Thread thread, EntityEnterpriseContext instance) throws Exception 124 { 125 if(instance.getId() != null) 126 { 127 EntityContainer container = (EntityContainer) instance.getContainer(); 128 SecurityActions.setContextClassLoader(thread, container.getClassLoader()); 130 131 container.invokeEjbStore(instance); 133 } 134 } 135 136 public void synchronize(Thread thread, Transaction tx, EntityEnterpriseContext instance) 137 throws Exception 138 { 139 if(instance.getId() != null) 142 { 143 EntityContainer container = (EntityContainer) instance.getContainer(); 144 145 SecurityActions.setContextClassLoader(thread, container.getClassLoader()); 147 148 container.storeEntity(instance); 150 151 instance.setTxAssociation(SYNCHRONIZED); 152 } 153 } 154 }; 155 156 public static final TxAssociation SYNCHRONIZED = new TxAssociation() 157 { 158 public void scheduleSync(Transaction tx, EntityEnterpriseContext instance) 159 { 160 instance.setTxAssociation(SYNC_SCHEDULED); 161 } 162 163 public void invokeEjbStore(Thread thread, EntityEnterpriseContext instance) 164 { 165 } 166 167 public void synchronize(Thread thread, Transaction tx, EntityEnterpriseContext instance) 168 { 169 } 170 }; 171 172 public static final TxAssociation PREVENT_SYNC = new TxAssociation() 173 { 174 public void scheduleSync(Transaction tx, EntityEnterpriseContext instance) 175 { 176 } 177 178 public void synchronize(Thread thread, Transaction tx, EntityEnterpriseContext instance) throws Exception 179 { 180 EntityContainer container = (EntityContainer)instance.getContainer(); 181 if(container.getPersistenceManager().isStoreRequired(instance)) 182 { 183 throw new EJBException ("The instance of " + 184 container.getBeanMetaData().getEjbName() + 185 " with pk=" + 186 instance.getId() + 187 " was not stored to prevent potential inconsistency of data in the database:" + 188 " the instance was evicted from the cache during the transaction" + 189 " and the database was possibly updated by another process."); 190 } 191 } 192 193 public void invokeEjbStore(Thread thread, EntityEnterpriseContext instance) throws Exception 194 { 195 GlobalTxEntityMap.SYNC_SCHEDULED.invokeEjbStore(thread, instance); 196 } 197 }; 198 199 203 public void synchronizeEntities(Transaction tx) 204 { 205 GlobalTxSynchronization globalSync = (GlobalTxSynchronization) txSynch.get(tx); 206 if(globalSync != null) 207 { 208 globalSync.synchronize(); 209 } 210 } 211 212 215 private void associate(Transaction tx, EntityEnterpriseContext entity) 216 throws RollbackException , SystemException 217 { 218 GlobalTxSynchronization globalSync = (GlobalTxSynchronization) txSynch.get(tx); 219 if(globalSync == null) 220 { 221 globalSync = new GlobalTxSynchronization(tx); 222 txSynch.set(tx, globalSync); 223 tx.registerSynchronization(globalSync); 224 } 225 226 230 globalSync.associate(entity); 231 } 232 233 235 238 private class GlobalTxSynchronization implements Synchronization 239 { 240 private Transaction tx; 241 private List instances = new ArrayList (); 242 private boolean synchronizing; 243 244 public GlobalTxSynchronization(Transaction tx) 245 { 246 this.tx = tx; 247 } 248 249 public void associate(EntityEnterpriseContext ctx) 250 { 251 instances.add(ctx); 252 } 253 254 public void synchronize() 255 { 256 if(synchronizing || instances.isEmpty()) 257 { 258 return; 259 } 260 261 synchronizing = true; 262 263 Thread currentThread = Thread.currentThread(); 266 ClassLoader oldCl = SecurityActions.getContextClassLoader(); 267 268 EntityEnterpriseContext instance = null; 269 try 270 { 271 for(int i = 0; i < instances.size(); i++) 272 { 273 if(tx.getStatus() == Status.STATUS_MARKED_ROLLBACK) 276 { 277 return; 278 } 279 280 instance = (EntityEnterpriseContext) instances.get(i); 281 instance.getTxAssociation().invokeEjbStore(currentThread, instance); 282 } 283 284 for(int i = 0; i < instances.size(); i++) 285 { 286 if(tx.getStatus() == Status.STATUS_MARKED_ROLLBACK) 289 { 290 return; 291 } 292 293 instance = (EntityEnterpriseContext) instances.get(i); 295 instance.getTxAssociation().synchronize(currentThread, tx, instance); 296 } 297 } 298 catch(Exception causeByException) 299 { 300 try 310 { 311 tx.setRollbackOnly(); 312 } 313 catch(Exception e) 314 { 315 log.warn("Exception while trying to rollback tx: " + tx, e); 316 } 317 318 if(causeByException instanceof EJBException ) 320 { 321 throw (EJBException ) causeByException; 322 } 323 throw new EJBException ("Exception in store of entity:" + 324 ((instance == null || instance.getId() == null) ? "<null>" : instance.getId().toString()), 325 causeByException); 326 } 327 finally 328 { 329 SecurityActions.setContextClassLoader(oldCl); 330 synchronizing = false; 331 } 332 } 333 334 336 public void beforeCompletion() 337 { 338 if(log.isTraceEnabled()) 339 { 340 log.trace("beforeCompletion called for tx " + tx); 341 } 342 343 synchronize(); 346 } 347 348 public void afterCompletion(int status) 349 { 350 } 352 } 353 } 354 | Popular Tags |