The spec I believe says that the beforeCompletion() call does not have to be called if a tx is rolled back. Hence the behavior is correct though, may be unusual.
I think you are mistaken.
The spec says:
The Synchronization.beforeCompletion method is called prior to the start
of the two-phase transaction commit process. This call is executed with the
transaction context of the transaction that is being committed.
so calling beforeCompletion during rollback seems completely wrong, although afterCompletion should be called after a rollback.
The current (3.2.4RC1) JBoss behaviour is wrong, IMHO.
Just to make things clearer, here's a snippet of stack trace:
at kodo.runtime.PersistenceManagerImpl.beforeCompletion(PersistenceManagerImpl.java:650) at org.jboss.tm.TransactionImpl.doBeforeCompletion(TransactionImpl.java:1308) at org.jboss.tm.TransactionImpl.rollback(TransactionImpl.java:456) at org.jboss.ejb.plugins.TxInterceptorCMT.endTransaction(TxInterceptorCMT.java:436) at org.jboss.ejb.plugins.TxInterceptorCMT.runWithTransactions(TxInterceptorCMT.java:323) at org.jboss.ejb.plugins.TxInterceptorCMT.invoke(TxInterceptorCMT.java:147) at org.jboss.ejb.plugins.SecurityInterceptor.invoke(SecurityInterceptor.java:118) at org.jboss.ejb.plugins.LogInterceptor.invoke(LogInterceptor.java:191) at org.jboss.ejb.plugins.ProxyFactoryFinderInterceptor.invoke(ProxyFactoryFinderInterceptor.java:122) at org.jboss.ejb.StatelessSessionContainer.internalInvoke(StatelessSessionContainer.java:331) at org.jboss.ejb.Container.invoke(Container.java:713)
PersistenceManagerImpl implements javax.transaction.Synchronization.
You are correct, it is not correct.
It has already been fixed in JBoss4 but the fix has not been backported yet.