1 18 package org.objectweb.speedo.workingset.lib; 19 20 import java.util.ArrayList ; 21 import java.util.Iterator ; 22 23 import javax.jdo.JDOException; 24 import javax.jdo.JDOFatalException; 25 import javax.jdo.JDOFatalInternalException; 26 import javax.jdo.JDOUserException; 27 import javax.jdo.PersistenceManager; 28 import javax.naming.InitialContext ; 29 import javax.transaction.Status ; 30 import javax.transaction.Synchronization ; 31 import javax.transaction.TransactionManager ; 32 33 import org.objectweb.fractal.api.Component; 34 import org.objectweb.fractal.api.control.LifeCycleController; 35 import org.objectweb.jorm.api.PMapper; 36 import org.objectweb.medor.eval.prefetch.api.PrefetchCache; 37 import org.objectweb.perseus.persistence.api.ConnectionHolder; 38 import org.objectweb.perseus.persistence.api.PersistenceException; 39 import org.objectweb.perseus.persistence.api.State; 40 import org.objectweb.perseus.persistence.api.TransactionalPersistenceManager; 41 import org.objectweb.perseus.persistence.api.TransactionalWorkingSet; 42 import org.objectweb.perseus.persistence.api.VirtualState; 43 import org.objectweb.perseus.persistence.api.WorkingSet; 44 import org.objectweb.perseus.persistence.api.WorkingSetLifeCycle; 45 import org.objectweb.perseus.persistence.lib.BasicWorkingSet; 46 import org.objectweb.speedo.api.ExceptionHelper; 47 import org.objectweb.speedo.api.SpeedoProperties; 48 import org.objectweb.speedo.api.TransactionListener; 49 import org.objectweb.speedo.mim.api.SpeedoAccessor; 50 import org.objectweb.speedo.pm.api.ProxyManager; 51 import org.objectweb.speedo.workingset.api.Transaction; 52 import org.objectweb.util.monolog.api.BasicLevel; 53 54 65 public class SpeedoTransaction 66 extends BasicWorkingSet 67 implements Transaction, LifeCycleController { 68 69 public final static String PROXY_MANAGER_BINDING = "proxy-manager"; 70 public final static String MAPPER_BINDING = "mapper"; 71 public final static String TRANSACTIONAL_PERSISTENCE_MANAGER_BINDING 72 = "transactional-persistence-manager"; 73 public final static String COMPONENT_BINDING = "component"; 74 public static TransactionListener txListener = null; 75 76 79 private ProxyManager pm = null; 80 81 85 private PMapper mapper = null; 86 87 90 private TransactionalPersistenceManager tpm = null; 91 92 95 private Transaction thisT; 96 97 private boolean nontransactionalRead; 98 private boolean nontransactionalWrite; 99 100 103 private boolean optimistic; 104 105 109 private Synchronization synchronization = null; 110 111 114 private boolean managedEnv = false; 115 116 119 private boolean rollbackOnly = false; 120 121 125 public void active() throws PersistenceException { 126 tpm.createWS(thisT); 127 try { 128 status = WorkingSetLifeCycle.getNextStatus( 129 status, WorkingSetLifeCycle.ACTIVE_ACTION); 130 } catch (PersistenceException e) { 131 logger.log(BasicLevel.WARN, "Bad initial state of the working set:", e); 132 status = WorkingSet.CTX_ACTIVE; 133 } 134 } 135 136 142 public State bind(State state, Object oid, byte mode) { 143 State old = super.bind(state, oid, mode); 144 if(! (state instanceof VirtualState)){ 145 SpeedoAccessor sa = (SpeedoAccessor) state; 146 if (mode == BasicWorkingSet.WRITE_INTENTION) { 147 sa.changeVersion(); 148 } 149 } 150 return old; 151 } 152 153 158 public void beforeWSPrepare() throws PersistenceException { 159 logger.log(BasicLevel.DEBUG, "Starting beforeWSPrepare"); 160 Iterator it = oid2state.values().iterator(); 161 ArrayList exceptions = null; 162 while(it.hasNext()) { 163 State state = (State) it.next(); 164 if (state == VirtualState.instance) { 165 continue; 166 } 167 try { 168 ((SpeedoAccessor) state).prepareWrite(); 169 } catch (Exception e) { 170 if (exceptions == null) { 171 exceptions = new ArrayList (); 172 } 173 exceptions.add(e); 174 int level = e instanceof JDOException ? BasicLevel.DEBUG : BasicLevel.ERROR ; 175 if (logger.isLoggable(level)) { 176 logger.log(level, 177 "Error on SpeedoAccessor preparation for flushing: " 178 + "\n\tstate.ce.identifier=" + state.getCacheEntry().getCeIdentifier() 179 + "\n\tstate=" + state 180 + "\n\texception: ", e); 181 } 182 } 183 } 184 PrefetchCache pc = mapper.getPrefetchCache(); 186 if (pc != null) { 187 pc.invalidatePrefetchBuffer(thisT); 188 } 189 logger.log(BasicLevel.DEBUG, "Ending beforeWSPrepare"); 190 if (exceptions != null) { 191 Exception inner; 192 if (exceptions.size() == 1) { 193 throw new PersistenceException((Exception ) exceptions.get(0)); 194 } else { 195 throw new PersistenceException(new JDOUserException( 196 "Impossible to prepare instances before flushing", 197 (Exception []) exceptions.toArray(new Exception [exceptions.size()]))); 198 } 199 } 200 } 201 202 207 public void onWSEnd() { 208 logger.log(BasicLevel.DEBUG, "Starting onWSEnd"); 209 ArrayList exceptions = null; 210 if (!oid2state.isEmpty()) { 211 Iterator it = oid2state.values().iterator(); 212 while(it.hasNext()) { 213 State state = (State) it.next(); 214 if (state == VirtualState.instance) { 215 continue; 216 } 217 try { 218 ((SpeedoAccessor) state).workingSetClosed(); 219 } catch (Exception e) { 220 if (exceptions == null) { 221 exceptions = new ArrayList (); 222 } 223 exceptions.add(e); 224 if (!(e instanceof JDOException)) { 225 logger.log(BasicLevel.ERROR, 226 "Error on workingSetClosed for the SpeedoAccessor: " 227 + "\n\tstate.ce.identifier=" + state.getCacheEntry().getCeIdentifier() 228 + "\n\tstate=" + state 229 + "\n\texception: ", e); 230 } 231 } 232 } 233 } 234 logger.log(BasicLevel.DEBUG, "Ending onWSEnd"); 235 if (exceptions != null) { 236 Exception inner; 237 if (exceptions.size() == 1) { 238 throw new JDOException( 239 "Error when signal the close of working set on state(s):", 240 (Exception ) exceptions.get(0)); 241 } else { 242 throw new JDOUserException( 243 "Error when signal the close of working set on states:", 244 (Exception []) exceptions.toArray(new Exception [exceptions.size()])); 245 } 246 } 247 } 248 249 252 public void setConnectionHolder(ConnectionHolder ch) { 253 connectionHolder = ch; 254 connectionHolder.bindWorkingSet(thisT); 255 } 256 257 public JDOFatalException rollBackOnInternalError(Exception _e) { 258 Exception ie = ExceptionHelper.getNested(_e); 259 if (isActive()) { 260 if (managedEnv) { 261 logger.log(BasicLevel.INFO, "."); 262 String tmName = pm.getPersistenceManagerFactory().getProperties() 263 .getProperty(SpeedoProperties.TM_NAME); 264 if (tmName == null) { 265 return new JDOFatalException("No transaction manager jndi name found in initialisation properties"); 266 } 267 try { 268 Object o = new InitialContext ().lookup(tmName); 269 if (o == null) { 270 String msg = "The transaction must be marked as rollbackOnly: JNDI retrieves a null transaction manager for the name '" + tmName + "'."; 271 logger.log(BasicLevel.ERROR, msg); 272 return new JDOFatalException(msg); 273 } 274 if (!(o instanceof TransactionManager )) { 275 String msg = "The transaction must be marked as rollbackOnly: JNDI retrieves an object which is not a javax.transaction.TransactionManager (JNDI name: " + tmName + "): " + o; 276 logger.log(BasicLevel.ERROR, msg); 277 return new JDOFatalException(msg); 278 } 279 javax.transaction.Transaction t = ((TransactionManager ) o).getTransaction(); 280 if (t == null) { 281 String msg = "Impossible to rollback an unexisting transaction (TM.getTransaction()=null)"; 282 logger.log(BasicLevel.ERROR, msg); 283 return new JDOFatalException(msg); 284 } 285 t.setRollbackOnly(); 286 } catch (Exception e) { 287 String msg = "The transaction must be marked as rollbackOnly: Error when lookup the transaction manager in JNDI with the name '" 288 + tmName + "'"; 289 logger.log(BasicLevel.ERROR, msg, e); 290 return new JDOFatalException(msg); 291 } 292 } else { 293 rollback(); 294 } 295 return new JDOFatalException("The current transaction has been rolledback, please retry", ie); 296 } else { 297 return new JDOFatalException("The current working set occrurs an error, please retry", ie); 298 } 299 } 300 301 public boolean isManagedEnv() { 302 return managedEnv; 303 } 304 305 308 public String getFcState() { 309 return null; 310 } 311 312 public void startFc() { 313 managedEnv = pm.getPersistenceManagerFactory().getProperties() 314 .getProperty(SpeedoProperties.MANAGED, "") 315 .equals("true"); 316 } 317 318 public void stopFc() { 319 } 320 321 324 public String [] listFc() { 325 String [] names = super.listFc(); 326 String [] itfs = new String [names.length + 3]; 327 itfs[0] = PROXY_MANAGER_BINDING; 328 itfs[1] = TRANSACTIONAL_PERSISTENCE_MANAGER_BINDING; 329 itfs[2] = MAPPER_BINDING; 330 System.arraycopy(names, 0, itfs, 3, names.length); 331 return itfs; 332 } 333 334 public Object lookupFc(String c) { 335 if (PROXY_MANAGER_BINDING.equals(c)) 336 return pm; 337 else if (TRANSACTIONAL_PERSISTENCE_MANAGER_BINDING.equals(c)) 338 return tpm; 339 else if (MAPPER_BINDING.equals(c)) 340 return mapper; 341 else 342 return super.lookupFc(c); 343 } 344 345 public void bindFc(String c, Object s) { 346 if (PROXY_MANAGER_BINDING.equals(c)) 347 pm = (ProxyManager) s; 348 else if (TRANSACTIONAL_PERSISTENCE_MANAGER_BINDING.equals(c)) 349 tpm = (TransactionalPersistenceManager) s; 350 else if (MAPPER_BINDING.equals(c)) 351 mapper = (PMapper) s; 352 else if (COMPONENT_BINDING.equals(c)) { 353 try { 354 thisT = (Transaction) ((Component) s).getFcInterface("transaction"); 355 } catch (Exception e) { 356 throw new JDOFatalInternalException( 357 "Impossible to get self transaction", 358 ExceptionHelper.getNested(e)); 359 } 360 } else 361 super.bindFc(c, s); 362 } 363 364 public void unbindFc(String c) { 365 if (PROXY_MANAGER_BINDING.equals(c)) 366 pm = null; 367 else if (TRANSACTIONAL_PERSISTENCE_MANAGER_BINDING.equals(c)) 368 tpm = null; 369 else if (MAPPER_BINDING.equals(c)) 370 mapper = null; 371 else 372 super.unbindFc(c); 373 } 374 375 public void setStatus(byte status) throws PersistenceException { 376 try { 377 switch(status) { 378 case TransactionalWorkingSet.CTX_PREPARED: 379 beforeWSPrepare(); 380 break; 381 case TransactionalWorkingSet.CTX_COMMITTED: 382 case TransactionalWorkingSet.CTX_ABORTED: 383 onWSEnd(); 384 break; 385 case TransactionalWorkingSet.CTX_CLOSED: 386 if (oid2state.isEmpty()) { 387 PrefetchCache pc = mapper.getPrefetchCache(); 389 if (pc != null) { 390 pc.invalidatePrefetchBuffer(thisT); 391 } 392 } 393 onWSEnd(); 394 break; 395 } 396 } finally { 397 super.setStatus(status); 398 } 399 } 400 401 404 public void begin() { 405 logger.log(BasicLevel.INFO, "Begin the transaction"); 406 try { 407 rollbackOnly = false; tpm.begin(thisT); 409 } catch (PersistenceException e) { 410 Exception ie = ExceptionHelper.getNested(e); 411 logger.log(BasicLevel.ERROR, 412 "Error during the begin of the transaction:", ie); 413 throw new JDOException("", ie); 414 } 415 if (txListener != null) { 416 txListener.transactionBegun(this); 417 } 418 } 419 420 public void commit() { 421 int size = oid2state.size(); 422 logger.log(BasicLevel.INFO, "Commit the transaction, working set size: " + size); 423 if (synchronization != null) { 424 synchronization.beforeCompletion(); 425 } 426 boolean validated = rollbackOnly; 428 try { 429 if (rollbackOnly) { 430 tpm.rollback(thisT); 431 } else { 432 tpm.commit(thisT); 433 validated = true; 434 } 435 } catch (PersistenceException e) { 436 Exception ie = ExceptionHelper.getNested(e); 437 if (ie instanceof JDOException) { 438 throw (JDOException) ie; 439 } else { 440 ie = new JDOFatalException( 441 "Transaction rolledback due to an exception at commit time: ", ie); 442 logger.log(BasicLevel.INFO, ie.getMessage(), ie); 443 throw (JDOFatalException) ie; 444 } 445 } finally { 446 if (synchronization != null) 447 synchronization.afterCompletion((validated 448 ? Status.STATUS_COMMITTED : Status.STATUS_ROLLEDBACK)); 449 if (txListener != null) { 450 if (validated) { 451 txListener.transactionCommitted(this, size); 452 } else { 453 txListener.transactionAborted(this, size); 454 } 455 } 456 } 457 } 458 459 public void rollback() { 460 logger.log(BasicLevel.INFO, "Roll back a transaction: "); 461 int size = oid2state.size(); 462 try { 463 tpm.rollback(thisT); 464 } catch (PersistenceException e) { 465 Exception ie = ExceptionHelper.getNested(e); 466 logger.log(BasicLevel.ERROR, 467 "Error during the rollback of the transaction:", ie); 468 throw new JDOException("", ie); 469 } finally { 470 if (txListener != null) { 471 txListener.transactionAborted(this, size); 472 } 473 if (synchronization != null) { 474 synchronization.afterCompletion(Status.STATUS_ROLLEDBACK); 475 } 476 } 477 } 478 479 public boolean isActive() { 480 switch(status){ 481 case TransactionalWorkingSet.CTX_ACTIVE_TRANSACTIONAL: 482 case TransactionalWorkingSet.CTX_PREPARED: 483 case TransactionalWorkingSet.CTX_PREPARED_OK: 484 case TransactionalWorkingSet.CTX_PREPARED_FAIL: 485 return true; 486 case TransactionalWorkingSet.CTX_ACTIVE: 487 case TransactionalWorkingSet.CTX_COMMITTED: 488 case TransactionalWorkingSet.CTX_ABORTED: 489 case TransactionalWorkingSet.CTX_CLOSED: 490 default: 491 return false; 492 } 493 } 494 495 public void setNontransactionalRead(boolean b) { 496 nontransactionalRead = b; 497 } 498 499 public boolean getNontransactionalRead() { 500 return nontransactionalRead; 501 } 502 503 public void setNontransactionalWrite(boolean b) { 504 nontransactionalWrite = b; 505 } 506 507 public boolean getNontransactionalWrite() { 508 return nontransactionalWrite; 509 } 510 511 public void setRetainValues(boolean b) { 512 setWSRetainValues(b); 513 } 514 515 public boolean getRetainValues() { 516 return getWSRetainValues(); 517 } 518 519 public void setRestoreValues(boolean b) { 520 setWSRestoreValues(b); 521 } 522 523 public boolean getRestoreValues() { 524 return getWSRestoreValues(); 525 } 526 527 public void setOptimistic(boolean b) { 528 optimistic = b; 529 } 530 531 public boolean getOptimistic() { 532 return optimistic; 533 } 534 535 public void setSynchronization(Synchronization s) { 536 synchronization = s; 537 } 538 539 public Synchronization getSynchronization() { 540 return synchronization; 541 } 542 543 public PersistenceManager getPersistenceManager() { 544 return pm; 545 } 546 547 public boolean getRollbackOnly() { 548 return rollbackOnly; 549 } 550 551 public void setRollbackOnly() { 552 rollbackOnly = true; 553 } 554 } 555 | Popular Tags |