Skip to content

Commit

Permalink
Restored EjbSynchronizations for compatability with AS7 - You must no…
Browse files Browse the repository at this point in the history
…w configure TransactionManagerSynchronizations if desired - tests not passing yet
  • Loading branch information
lincolnthree committed Jun 2, 2011
1 parent 1bfc60c commit 771b20e
Show file tree
Hide file tree
Showing 3 changed files with 270 additions and 93 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,10 @@ target
.project
.settings
*.sw?
bin/
transaction.log
tests/jetty-hibernate/data
tests/jetty-hibernate/org.jboss.seam.persistence.test.util.IndexedHotel
.idea
*.iml
*~
*~
151 changes: 151 additions & 0 deletions impl/src/main/java/org/jboss/seam/transaction/EjbSynchronizations.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
/*
* JBoss, Home of Professional Open Source
* Copyright 2010, Red Hat, Inc., and individual contributors
* by the @authors tag. See the copyright.txt in the distribution for a
* full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.jboss.seam.transaction;

import java.rmi.RemoteException;
import java.util.LinkedList;

import javax.ejb.EJBException;
import javax.ejb.Remove;
import javax.ejb.SessionSynchronization;
import javax.ejb.Stateful;
import javax.ejb.TransactionAttribute;
import javax.ejb.TransactionAttributeType;
import javax.enterprise.context.RequestScoped;
import javax.enterprise.inject.spi.BeanManager;
import javax.inject.Inject;
import javax.transaction.Synchronization;

import org.jboss.seam.solder.bean.defaultbean.DefaultBean;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
* Receives JTA transaction completion notifications from the EJB container, and passes them on to the registered
* Synchronizations. This implementation is fully aware of container managed transactions and is able to register
* Synchronizations for the container transaction.
*
* @author Gavin King
*
*/
@Stateful
@RequestScoped
@TransactionAttribute(TransactionAttributeType.SUPPORTS)
@DefaultBean(Synchronizations.class)
public class EjbSynchronizations implements LocalEjbSynchronizations, SessionSynchronization
{
private static final Logger log = LoggerFactory.getLogger(EjbSynchronizations.class);

@Inject
private BeanManager beanManager;

// maintain two lists to work around a bug in JBoss EJB3 where a new
// SessionSynchronization
// gets registered each time the bean is called
protected LinkedList<SynchronizationRegistry> synchronizations = new LinkedList<SynchronizationRegistry>();
protected LinkedList<SynchronizationRegistry> committing = new LinkedList<SynchronizationRegistry>();

@Override
public void afterBegin()
{
log.debug("afterBegin");
synchronizations.addLast(new SynchronizationRegistry(beanManager));
}

@Override
public void beforeCompletion() throws EJBException, RemoteException
{
log.debug("beforeCompletion");
SynchronizationRegistry sync = synchronizations.removeLast();
sync.beforeTransactionCompletion();
committing.addLast(sync);
}

@Override
public void afterCompletion(boolean success) throws EJBException, RemoteException
{
log.debug("afterCompletion");
if (committing.isEmpty())
{
if (success)
{
throw new IllegalStateException("beforeCompletion was never called");
}
else
{
log.debug("afterCompletion");
if (committing.isEmpty())
{
if (success)
{
throw new IllegalStateException("beforeCompletion was never called");
}
else
{
synchronizations.removeLast().afterTransactionCompletion(false);
}
}
else
{
committing.removeFirst().afterTransactionCompletion(success);
}
}
}
}

@Override
public boolean isAwareOfContainerTransactions()
{
return true;
}

@Override
public void afterTransactionBegin()
{
// noop, let JTA notify us
}

@Override
public void afterTransactionCompletion(boolean success)
{
// noop, let JTA notify us
}

@Override
public void beforeTransactionCommit()
{
// noop, let JTA notify us
}

@Override
public void registerSynchronization(Synchronization sync)
{
synchronizations.getLast().registerSynchronization(sync);
}

@Override
@Remove
public void destroy()
{
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -28,100 +28,125 @@
import javax.transaction.TransactionManager;

import org.jboss.logging.Logger;
import org.jboss.seam.solder.bean.defaultbean.DefaultBean;
import org.jboss.seam.solder.core.Veto;

/**
* Synchronizations implementation that registers synchronizations with a JTA
* {@link TransactionManager}
* Synchronizations implementation that registers synchronizations with a JTA {@link TransactionManager}
*/
@Veto
@ApplicationScoped
@DefaultBean(Synchronizations.class)
public class TransactionManagerSynchronizations implements Synchronization, Synchronizations {
private static final Logger log = Logger.getLogger(TransactionManagerSynchronizations.class);

private final String[] JNDI_LOCATIONS = {"java:/TransactionManager", "java:appserver/TransactionManager", "java:comp/TransactionManager", "java:pm/TransactionManager"};

/**
* The location that the TM was found under JNDI. This is static, as it will
* not change between deployed apps on the same JVM
*/
private static volatile String foundJndiLocation;

@Inject
private BeanManager beanManager;


protected ThreadLocalStack<SynchronizationRegistry> synchronizations = new ThreadLocalStack<SynchronizationRegistry>();

protected ThreadLocalStack<Transaction> transactions = new ThreadLocalStack<Transaction>();

public void beforeCompletion() {
log.debug("beforeCompletion");
SynchronizationRegistry sync = synchronizations.peek();
sync.beforeTransactionCompletion();
}

public void afterCompletion(int status) {
transactions.pop();
log.debug("afterCompletion");
synchronizations.pop().afterTransactionCompletion((Status.STATUS_COMMITTED & status) == 0);
}

public boolean isAwareOfContainerTransactions() {
return true;
}

public void registerSynchronization(Synchronization sync) {
try {
TransactionManager manager = getTransactionManager();
Transaction transaction = manager.getTransaction();
if (transactions.isEmpty() || transactions.peek().equals(transaction)) {
transactions.push(transaction);
synchronizations.push(new SynchronizationRegistry(beanManager));
transaction.registerSynchronization(this);
}
synchronizations.peek().registerSynchronization(sync);
} catch (Exception e) {
throw new RuntimeException(e);
}
}

@Remove
public void destroy() {
}

public TransactionManager getTransactionManager() {
if (foundJndiLocation != null) {
try {
return (TransactionManager) new InitialContext().lookup(foundJndiLocation);
} catch (NamingException e) {
log.trace("Could not find transaction manager under" + foundJndiLocation);
}
}
for (String location : JNDI_LOCATIONS) {
try {
TransactionManager manager = (TransactionManager) new InitialContext().lookup(location);
foundJndiLocation = location;
return manager;
} catch (NamingException e) {
log.trace("Could not find transaction manager under" + location);
}
}
throw new RuntimeException("Could not find TransactionManager in JNDI");
}

@Override
public void afterTransactionBegin() {

}

@Override
public void afterTransactionCompletion(boolean success) {

}

@Override
public void beforeTransactionCommit() {

}
public class TransactionManagerSynchronizations implements Synchronization, Synchronizations
{
private static final Logger log = Logger.getLogger(TransactionManagerSynchronizations.class);

private final String[] JNDI_LOCATIONS = { "java:/TransactionManager", "java:appserver/TransactionManager",
"java:comp/TransactionManager", "java:pm/TransactionManager" };

/**
* The location that the TM was found under JNDI. This is static, as it will not change between deployed apps on the
* same JVM
*/
private static volatile String foundJndiLocation;

@Inject
private BeanManager beanManager;

protected ThreadLocalStack<SynchronizationRegistry> synchronizations = new ThreadLocalStack<SynchronizationRegistry>();

protected ThreadLocalStack<Transaction> transactions = new ThreadLocalStack<Transaction>();

@Override
public void beforeCompletion()
{
log.debug("beforeCompletion");
SynchronizationRegistry sync = synchronizations.peek();
sync.beforeTransactionCompletion();
}

@Override
public void afterCompletion(int status)
{
transactions.pop();
log.debug("afterCompletion");
synchronizations.pop().afterTransactionCompletion((Status.STATUS_COMMITTED & status) == 0);
}

@Override
public boolean isAwareOfContainerTransactions()
{
return true;
}

@Override
public void registerSynchronization(Synchronization sync)
{
try
{
TransactionManager manager = getTransactionManager();
Transaction transaction = manager.getTransaction();
if (transactions.isEmpty() || transactions.peek().equals(transaction))
{
transactions.push(transaction);
synchronizations.push(new SynchronizationRegistry(beanManager));
transaction.registerSynchronization(this);
}
synchronizations.peek().registerSynchronization(sync);
}
catch (Exception e)
{
throw new RuntimeException(e);
}
}

@Remove
public void destroy()
{
}

public TransactionManager getTransactionManager()
{
if (foundJndiLocation != null)
{
try
{
return (TransactionManager) new InitialContext().lookup(foundJndiLocation);
}
catch (NamingException e)
{
log.trace("Could not find transaction manager under" + foundJndiLocation);
}
}
for (String location : JNDI_LOCATIONS)
{
try
{
TransactionManager manager = (TransactionManager) new InitialContext().lookup(location);
foundJndiLocation = location;
return manager;
}
catch (NamingException e)
{
log.trace("Could not find transaction manager under" + location);
}
}
throw new RuntimeException("Could not find TransactionManager in JNDI");
}

@Override
public void afterTransactionBegin()
{

}

@Override
public void afterTransactionCompletion(boolean success)
{

}

@Override
public void beforeTransactionCommit()
{

}
}

0 comments on commit 771b20e

Please sign in to comment.