transactions/src/main/java/org/jboss/as/txn/service/internal/tsr/JCAOrderedLastSynchronizationList.java
@Override
    public void beforeCompletion() {
        // This is needed to guard against syncs being registered during the run, otherwise we could have used an iterator
        int lastIndexProcessed = 0;
        while ((lastIndexProcessed < preJcaSyncs.size())) {
            Synchronization preJcaSync = preJcaSyncs.get(lastIndexProcessed);
            if (TransactionLogger.ROOT_LOGGER.isTraceEnabled()) {
                TransactionLogger.ROOT_LOGGER.trace("JCAOrderedLastSynchronizationList.preJcaSyncs.before_completion - Class: " + preJcaSync.getClass() + " HashCode: "
                    + preJcaSync.hashCode()
                    + " toString: "
                    + preJcaSync);
            }
            preJcaSync.beforeCompletion();
            lastIndexProcessed = lastIndexProcessed + 1;
        }

        // Do the same for the jca syncs
        lastIndexProcessed = 0;
        while ((lastIndexProcessed < jcaSyncs.size())) {
            Synchronization jcaSync = jcaSyncs.get(lastIndexProcessed);
            if (TransactionLogger.ROOT_LOGGER.isTraceEnabled()) {
                TransactionLogger.ROOT_LOGGER.trace("JCAOrderedLastSynchronizationList.jcaSyncs.before_completion - Class: " + jcaSync.getClass() + " HashCode: "
                    + jcaSync.hashCode()
                    + " toString: "
                    + jcaSync);
            }
            jcaSync.beforeCompletion();
            lastIndexProcessed = lastIndexProcessed + 1;
        }
    }
@Override
    public void beforeCompletion() {
        // This is needed to guard against syncs being registered during the run, otherwise we could have used an iterator
        int lastIndexProcessed = 0;
        while ((lastIndexProcessed < preJcaSyncs.size())) {
            Synchronization preJcaSync = preJcaSyncs.get(lastIndexProcessed);
            if (TransactionLogger.ROOT_LOGGER.isTraceEnabled()) {
                TransactionLogger.ROOT_LOGGER.trace("JCAOrderedLastSynchronizationList.preJcaSyncs.before_completion - Class: " + preJcaSync.getClass() + " HashCode: "
                    + preJcaSync.hashCode()
                    + " toString: "
                    + preJcaSync);
            }
            preJcaSync.beforeCompletion();
            lastIndexProcessed = lastIndexProcessed + 1;
        }

        // Do the same for the jca syncs
        lastIndexProcessed = 0;
        while ((lastIndexProcessed < jcaSyncs.size())) {
            Synchronization jcaSync = jcaSyncs.get(lastIndexProcessed);
            if (TransactionLogger.ROOT_LOGGER.isTraceEnabled()) {
                TransactionLogger.ROOT_LOGGER.trace("JCAOrderedLastSynchronizationList.jcaSyncs.before_completion - Class: " + jcaSync.getClass() + " HashCode: "
                    + jcaSync.hashCode()
                    + " toString: "
                    + jcaSync);
            }
            jcaSync.beforeCompletion();
            lastIndexProcessed = lastIndexProcessed + 1;
        }
    }
Exceptions from Synchronizations that are registered with this TSR are not trapped for before completion. This is because
an error in a Sync here should result in the transaction rolling back.

You can see that in effect in these classes:
https://github.com/jbosstm/narayana/blob/5.0.4.Final/ArjunaCore/arjuna/classes
/com/arjuna/ats/arjuna/coordinator/TwoPhaseCoordinator.java#L91
https://github.com/jbosstm/narayana/blob/5.0.4.Final/ArjunaJTA
/jta/classes/com/arjuna/ats/internal/jta/resources/arjunacore/SynchronizationImple.java#L76