@Override public Connection getConnection() { // If TransactionSynchronizationRegistry exists, // register Synchronization to release connection automatically // at the first invocation of this method in the current thread. // TODO: I wonder if I can register for each thread ... if(syncRegistry != null && registered.get() == null){ syncRegistry.registerInterposedSynchronization(new Synchronization() { //@Override public void beforeCompletion() { } //@Override public void afterCompletion(int status) { releaseConnection(); registered.remove(); } }); registered.set(true); } return super.getConnection(); }
@Test public void testClobStringTypeWithJtaSynchronization() throws Exception { TransactionManager tm = mock(TransactionManager.class); MockJtaTransaction transaction = new MockJtaTransaction(); given(tm.getStatus()).willReturn(Status.STATUS_ACTIVE); given(tm.getTransaction()).willReturn(transaction); given(lobHandler.getClobAsString(rs, "column")).willReturn("content"); ClobStringType type = new ClobStringType(lobHandler, tm); assertEquals("content", type.nullSafeGet(rs, new String[] {"column"}, null)); type.nullSafeSet(ps, "content", 1); Synchronization synch = transaction.getSynchronization(); assertNotNull(synch); synch.beforeCompletion(); synch.afterCompletion(Status.STATUS_COMMITTED); verify(lobCreator).setClobAsString(ps, 1, "content"); }
@Test public void testClobStringTypeWithJtaSynchronizationAndRollback() throws Exception { TransactionManager tm = mock(TransactionManager.class); MockJtaTransaction transaction = new MockJtaTransaction(); given(tm.getStatus()).willReturn(Status.STATUS_ACTIVE); given(tm.getTransaction()).willReturn(transaction); given(lobHandler.getClobAsString(rs, "column")).willReturn("content"); ClobStringType type = new ClobStringType(lobHandler, tm); assertEquals("content", type.nullSafeGet(rs, new String[] {"column"}, null)); type.nullSafeSet(ps, "content", 1); Synchronization synch = transaction.getSynchronization(); assertNotNull(synch); synch.afterCompletion(Status.STATUS_ROLLEDBACK); verify(lobCreator).setClobAsString(ps, 1, "content"); }
@Test public void testBlobStringTypeWithJtaSynchronization() throws Exception { TransactionManager tm = mock(TransactionManager.class); MockJtaTransaction transaction = new MockJtaTransaction(); given(tm.getStatus()).willReturn(Status.STATUS_ACTIVE); given(tm.getTransaction()).willReturn(transaction); String content = "content"; byte[] contentBytes = content.getBytes(); given(lobHandler.getBlobAsBytes(rs, "column")).willReturn(contentBytes); BlobStringType type = new BlobStringType(lobHandler, tm); assertEquals(content, type.nullSafeGet(rs, new String[] {"column"}, null)); type.nullSafeSet(ps, content, 1); Synchronization synch = transaction.getSynchronization(); assertNotNull(synch); synch.beforeCompletion(); synch.afterCompletion(Status.STATUS_COMMITTED); verify(lobCreator).setBlobAsBytes(ps, 1, contentBytes); }
@Test public void testBlobStringTypeWithJtaSynchronizationAndRollback() throws Exception { TransactionManager tm = mock(TransactionManager.class); MockJtaTransaction transaction = new MockJtaTransaction(); given(tm.getStatus()).willReturn(Status.STATUS_ACTIVE); given(tm.getTransaction()).willReturn(transaction); String content = "content"; byte[] contentBytes = content.getBytes(); given(lobHandler.getBlobAsBytes(rs, "column")).willReturn(contentBytes); BlobStringType type = new BlobStringType(lobHandler, tm); assertEquals(content, type.nullSafeGet(rs, new String[] {"column"}, null)); type.nullSafeSet(ps, content, 1); Synchronization synch = transaction.getSynchronization(); assertNotNull(synch); synch.afterCompletion(Status.STATUS_ROLLEDBACK); verify(lobCreator).setBlobAsBytes(ps, 1, contentBytes); }
@Test public void testBlobByteArrayTypeWithJtaSynchronization() throws Exception { TransactionManager tm = mock(TransactionManager.class); MockJtaTransaction transaction = new MockJtaTransaction(); given(tm.getStatus()).willReturn(Status.STATUS_ACTIVE); given(tm.getTransaction()).willReturn(transaction); byte[] content = "content".getBytes(); given(lobHandler.getBlobAsBytes(rs, "column")).willReturn(content); BlobByteArrayType type = new BlobByteArrayType(lobHandler, tm); assertEquals(content, type.nullSafeGet(rs, new String[] {"column"}, null)); type.nullSafeSet(ps, content, 1); Synchronization synch = transaction.getSynchronization(); assertNotNull(synch); synch.beforeCompletion(); synch.afterCompletion(Status.STATUS_COMMITTED); verify(lobCreator).setBlobAsBytes(ps, 1, content); }
@Test public void testBlobByteArrayTypeWithJtaSynchronizationAndRollback() throws Exception { TransactionManager tm = mock(TransactionManager.class); MockJtaTransaction transaction = new MockJtaTransaction(); given(tm.getStatus()).willReturn(Status.STATUS_ACTIVE); given(tm.getTransaction()).willReturn(transaction); byte[] content = "content".getBytes(); given(lobHandler.getBlobAsBytes(rs, "column")).willReturn(content); BlobByteArrayType type = new BlobByteArrayType(lobHandler, tm); assertEquals(content, type.nullSafeGet(rs, new String[] {"column"}, null)); type.nullSafeSet(ps, content, 1); Synchronization synch = transaction.getSynchronization(); assertNotNull(synch); synch.afterCompletion(Status.STATUS_ROLLEDBACK); verify(lobCreator).setBlobAsBytes(ps, 1, content); }
@Test public void testRollbackNoExisting() throws Exception { setupTransaction(Connection.TRANSACTION_SERIALIZABLE); execute("create local temporary table x (e1 string, e2 integer)", new List[] {Arrays.asList(0)}); //$NON-NLS-1$ execute("insert into x (e2, e1) select e2, e1 from pm1.g1", new List[] {Arrays.asList(6)}); //$NON-NLS-1$ execute("update x set e1 = e2 where e2 > 1", new List[] {Arrays.asList(2)}); //$NON-NLS-1$ Mockito.verify(txn).registerSynchronization((Synchronization) Mockito.anyObject()); synch.afterCompletion(Status.STATUS_ROLLEDBACK); try { execute("select * from x", new List[] {}); fail(); } catch (Exception e) { } execute("create local temporary table x (e1 string, e2 integer)", new List[] {Arrays.asList(0)}); //$NON-NLS-1$ }
/** * Experience shows that in some cases the synchronization objects are added * while we are doing the commits as a result of EntityListeners for * example. Therefore prevent concurrent modification exceptions. * * @param c The consumer to execute on all synchronization objects */ private void doWithSyncs(Consumer<Synchronization> c) { if (toSync.size() == 0) return; List<Synchronization> toDo = toSync; toSync = new ArrayList<>(); try { // Perform the consumer on the existing list. toDo.stream().forEach((s) -> c.accept(s)); // And on the new list recursively. doWithSyncs(c); } finally { // Gather the lot to the new list. toDo.addAll(toSync); toSync = toDo; } }
@AroundInvoke public Object invoke(final InvocationContext ctx) throws Exception { boolean transactional = false; try { System.out.println("Intercepting "+ctx.getMethod().toGenericString()); transactional = txRegistry != null && txRegistry.getTransactionStatus() != Status.STATUS_NO_TRANSACTION; if (transactional) { txRegistry.registerInterposedSynchronization(new Synchronization() { @Override public void beforeCompletion() { } @Override public void afterCompletion(int i) { registerInvocation(ctx.getMethod()); } }); } return ctx.proceed(); } finally { if (!transactional) { registerInvocation(ctx.getMethod()); } } }
@Override public void registerSynchronization(Synchronization synchronization) throws RollbackException, SystemException { if (this.status != Status.STATUS_ACTIVE) { throw new IllegalStateException("the transaction is not active"); } if (this.rollbackOnly) { throw new RollbackException("the transaction is signed to roll back only"); } TransactionAdapter txAdapt = (TransactionAdapter) TransactionManagerImpl.getManager().getTransaction(); if (txAdapt.getTx() != this) { throw new IllegalStateException("the transaction is not held"); } if (this.synList == null) { this.synList = new ArrayList<Synchronization>(); } this.synList.add(synchronization); }
@Test public void testCommit() { Transaction tx = new Transaction(); boolean[] tmp = new boolean[2]; tx.registerSynchronization( new Synchronization() { @Override public void beforeCompletion() { tmp[0] = true; } @Override public void afterCompletion(int status) { if ( status == Status.STATUS_COMMITTED ) { tmp[1] = true; } } } ); tx.commit(); for ( boolean t : tmp ) { assertTrue( t ); } }
@Test public void testRollback() { Transaction tx = new Transaction(); boolean[] tmp = new boolean[2]; tx.registerSynchronization( new Synchronization() { @Override public void beforeCompletion() { tmp[0] = true; } @Override public void afterCompletion(int status) { if ( status == Status.STATUS_ROLLEDBACK ) { tmp[1] = true; } } } ); tx.rollback(); for ( boolean t : tmp ) { assertTrue( t ); } }
/** * {@inheritDoc} */ public void registerInterposedSynchronization(Synchronization sync) { TransactionImpl tx = registry.getTransaction(); if (tx == null) throw new IllegalStateException(); try { tx.registerSynchronization(sync); } catch (Throwable t) { // Nothing to do } }
synchronized void doAfterCompletion() { for ( Synchronization s : syncHooks ) { try { s.afterCompletion( status ); } catch ( Throwable t ) { log.log( Level.WARNING, "Caught exception from tx syncronization[" + s + "] afterCompletion()", t ); } } syncHooks = null; // help gc }
synchronized void doAfterCompletion() { for ( Synchronization s : syncHooks ) { try { s.afterCompletion( status ); } catch ( Throwable t ) { log.warning( "Caught exception from tx syncronization[" + s + "] afterCompletion()" ); } } syncHooks = null; // help gc }
@SuppressWarnings({ "unchecked", "rawtypes" }) private TransactionManagerAdapter() { try { uowManagerClass = Class.forName("com.ibm.ws.uow.UOWManager"); setRollbackOnlyMethod = uowManagerClass.getMethod( "setRollbackOnly", new Class[] {}); uowSynchronizationRegistryClass = Class .forName("com.ibm.websphere.uow.UOWSynchronizationRegistry"); registerSynchronizationMethod = uowSynchronizationRegistryClass .getMethod("registerInterposedSynchronization", new Class[] { Synchronization.class }); Class extendedJTATransactionClass = Class .forName("com.ibm.websphere.jtaextensions.ExtendedJTATransaction"); getLocalIdMethod = extendedJTATransactionClass.getMethod( "getLocalId", new Class[0]); } catch (ClassNotFoundException cnfe) { throw new HibernateException(cnfe); } catch (NoSuchMethodException nsme) { throw new HibernateException(nsme); } }
@Override public TheResult compute(final boolean passing) { final TheResult theResult = new TheResult(); counter++; // ensure we are not called N times theResult.setValue(counter); if (!passing) { registry.registerInterposedSynchronization(new Synchronization() { @Override public void beforeCompletion() { registry.setRollbackOnly(); } @Override public void afterCompletion(final int status) { // no-op } }); } return theResult; }
public void registerSynchronization(final TransactionSynchronization synchronization) { if (isTransactionActive()) { synchronizationRegistry.registerInterposedSynchronization(new Synchronization() { public void beforeCompletion() { synchronization.beforeCompletion(); } public void afterCompletion(final int s) { final TransactionSynchronization.Status status; if (s == Status.STATUS_COMMITTED) { status = TransactionSynchronization.Status.COMMITTED; } else if (s == Status.STATUS_ROLLEDBACK) { status = TransactionSynchronization.Status.ROLLEDBACK; } else { status = TransactionSynchronization.Status.UNKNOWN; } synchronization.afterCompletion(status); } }); } else { synchronizations.add(synchronization); } }
public CmrSet(final EntityBean source, final String sourceProperty, final BeanContext relatedInfo, final String relatedProperty, final Collection<Bean> relatedBeans) { this.source = source; this.sourceProperty = sourceProperty; this.relatedInfo = relatedInfo; this.relatedProperty = relatedProperty; this.relatedBeans = relatedBeans; relatedLocal = relatedInfo.getLocalInterface(); final TransactionSynchronizationRegistry transactionRegistry = SystemInstance.get().getComponent(TransactionSynchronizationRegistry.class); try { transactionRegistry.registerInterposedSynchronization(new Synchronization() { public void beforeCompletion() { } public void afterCompletion(final int i) { mutable = false; } }); } catch (final IllegalStateException ignored) { // no tx so not mutable mutable = false; } }
@Transactional(value = REQUIRED, dontRollbackOn = AnotherException.class) public void anotherException(final AtomicInteger status) { try { OpenEJB.getTransactionManager().getTransaction().registerSynchronization(new Synchronization() { @Override public void beforeCompletion() { // no-op } @Override public void afterCompletion(final int state) { status.set(state); } }); } catch (final RollbackException | SystemException e) { fail(); } throw new AnotherException(); }
@Override public void putResource(Object key, Object value) { try { if (key == null) throw new NullPointerException("key cannot be null"); if (currentTransaction() == null || currentTransaction().getStatus() == Status.STATUS_NO_TRANSACTION) throw new IllegalStateException("no transaction started on current thread"); Object oldValue = getResources().put(key, value); if (oldValue == null && getResources().size() == 1) { if (log.isDebugEnabled()) { log.debug("first resource put in synchronization registry, registering a ClearRegistryResourcesSynchronization"); } Synchronization synchronization = new ClearRegistryResourcesSynchronization(); currentTransaction().getSynchronizationScheduler().add(synchronization, Scheduler.ALWAYS_LAST_POSITION); } } catch (SystemException ex) { throw new BitronixRuntimeException("cannot get current transaction status", ex); } }
@Override public void registerInterposedSynchronization(Synchronization synchronization) { try { if (currentTransaction() == null || currentTransaction().getStatus() == Status.STATUS_NO_TRANSACTION) throw new IllegalStateException("no transaction started on current thread"); if ( currentTransaction().getStatus() == Status.STATUS_PREPARING || currentTransaction().getStatus() == Status.STATUS_PREPARED || currentTransaction().getStatus() == Status.STATUS_COMMITTING || currentTransaction().getStatus() == Status.STATUS_COMMITTED || currentTransaction().getStatus() == Status.STATUS_ROLLING_BACK || currentTransaction().getStatus() == Status.STATUS_ROLLEDBACK ) throw new IllegalStateException("transaction is done, cannot register an interposed synchronization"); currentTransaction().getSynchronizationScheduler().add(synchronization, Scheduler.DEFAULT_POSITION -1); } catch (SystemException ex) { throw new BitronixRuntimeException("cannot get current transaction status", ex); } }
/** * Run all registered Synchronizations' beforeCompletion() method. Be aware that this method can change the * transaction status to mark it as rollback only for instance. * @throws bitronix.tm.internal.BitronixSystemException if status changing due to a synchronization throwing an * exception fails. */ private void fireBeforeCompletionEvent() throws BitronixSystemException { if (log.isDebugEnabled()) { log.debug("before completion, " + synchronizationScheduler.size() + " synchronization(s) to execute"); } Iterator<Synchronization> it = synchronizationScheduler.reverseIterator(); while (it.hasNext()) { Synchronization synchronization = it.next(); try { if (log.isDebugEnabled()) { log.debug("executing synchronization " + synchronization); } synchronization.beforeCompletion(); } catch (RuntimeException ex) { if (log.isDebugEnabled()) { log.debug("Synchronization.beforeCompletion() call failed for " + synchronization + ", marking transaction as rollback only - " + ex); } setStatus(Status.STATUS_MARKED_ROLLBACK); throw ex; } } }
private void fireAfterCompletionEvent() { // this TX is no longer in-flight -> remove this transaction's state from all XAResourceHolders getResourceManager().clearXAResourceHolderStates(); if (log.isDebugEnabled()) { log.debug("after completion, " + synchronizationScheduler.size() + " synchronization(s) to execute"); } for (Synchronization synchronization : synchronizationScheduler) { try { if (log.isDebugEnabled()) { log.debug("executing synchronization " + synchronization + " with status=" + Decoder.decodeStatus(status)); } synchronization.afterCompletion(status); } catch (Exception ex) { log.warn("Synchronization.afterCompletion() call failed for " + synchronization, ex); } } ManagementRegistrar.unregister("bitronix.tm:type=Transaction,Gtrid=" + resourceManager.getGtrid()); }
public void testBeforeCompletionRuntimeExceptionRethrown() throws Exception { btm.begin(); btm.getTransaction().registerSynchronization(new Synchronization() { public void beforeCompletion() { throw new RuntimeException("beforeCompletion failure"); } public void afterCompletion(int i) { } }); try { btm.commit(); fail("expected runtime exception"); } catch (RollbackException ex) { assertEquals(RuntimeException.class, ex.getCause().getClass()); assertEquals("beforeCompletion failure", ex.getCause().getMessage()); } btm.begin(); btm.commit(); }
public void registerSynchronization(Synchronization synchronization) { if (this.transactionSynchronizationRegistry != null) { this.transactionSynchronizationRegistry.registerInterposedSynchronization(synchronization); } else { try { this.transactionManager.getTransaction().registerSynchronization(synchronization); } catch (Exception ex) { throw new TransactionException("Could not access JTA Transaction to register synchronization", ex); } } }
@Override public void registerSynchronization(final Synchronization synchronization) throws RollbackException, IllegalStateException, SystemException { final InvocationHandler ih = new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { if ( "afterCompletion".equals( method.getName() ) ) { int status = args[2].equals(Boolean.TRUE) ? Status.STATUS_COMMITTED : Status.STATUS_UNKNOWN; synchronization.afterCompletion(status); } else if ( "beforeCompletion".equals( method.getName() ) ) { synchronization.beforeCompletion(); } else if ( "toString".equals( method.getName() ) ) { return synchronization.toString(); } return null; } }; final Object synchronizationCallback = Proxy.newProxyInstance( getClass().getClassLoader(), new Class[] {synchronizationCallbackClass}, ih ); try { registerSynchronizationMethod.invoke( extendedJTATransaction, synchronizationCallback ); } catch (Exception e) { throw new HibernateException(e); } }
@Override public void registerSynchronization(Synchronization synchronization) { try { transactionManagerAccess.getTransactionManager().getTransaction().registerSynchronization( synchronization ); } catch (Exception e) { throw new JtaPlatformException( "Could not access JTA Transaction to register synchronization", e ); } }
@Override public void registerSynchronization(Synchronization synchronization) { if ( synchronization == null ) { throw new NullSynchronizationException(); } if ( synchronizations == null ) { synchronizations = new LinkedHashSet<Synchronization>(); } boolean added = synchronizations.add( synchronization ); if ( !added ) { LOG.synchronizationAlreadyRegistered( synchronization ); } }
@Override public void notifySynchronizationsBeforeTransactionCompletion() { if ( synchronizations != null ) { for ( Synchronization synchronization : synchronizations ) { try { synchronization.beforeCompletion(); } catch ( Throwable t ) { LOG.synchronizationFailed( synchronization, t ); } } } }
@Override public void notifySynchronizationsAfterTransactionCompletion(int status) { if ( synchronizations != null ) { for ( Synchronization synchronization : synchronizations ) { try { synchronization.afterCompletion( status ); } catch ( Throwable t ) { LOG.synchronizationFailed( synchronization, t ); } } } }
/** * Registers transaction synchronization with session in order to clean up and close the session when transaction * finishes. * * @param session * Session to register into transaction synchronization. Cannot be null. * @return Returns <code>true</code> if the session was register into any available synchronization strategy, * <code>false</code> otherwise. */ private boolean registerSynchronization(final Session session) { // Tries Spring's transaction manager synchronization. if (TransactionSynchronizationManager.isSynchronizationActive()) { // If it's allowed, registers synchronization to cleanup session. TransactionSynchronizationManager.registerSynchronization(createTransactionSynchronization(session)); return true; } else { // Tries JTA transaction manager synchronization. JtaPlatform jtaPlatform = sessionFactory.getServiceRegistry().getService(JtaPlatform.class); // If it's allowed, registers synchronization to cleanup session. if (jtaPlatform.canRegisterSynchronization()) { List<TransactionSynchronization> synchronizations; synchronizations = Arrays.asList(createTransactionSynchronization(session)); Synchronization jtaSync; jtaSync = new JtaAfterCompletionSynchronization(synchronizations); jtaPlatform.registerSynchronization(jtaSync); return true; } } return false; }
@Override public void doAfterCommit(Runnable runnable) { getSession().getTransaction().registerSynchronization(new Synchronization() { @Override public void beforeCompletion() { } @Override public void afterCompletion(int status) { if (status == Status.STATUS_COMMITTED) runnable.run(); } }); }