/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jboss.narayana.osgi.jta.internal; import javax.transaction.Transaction; import javax.transaction.xa.XAException; import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import org.jboss.narayana.osgi.jta.internal.OsgiTransactionManager.Listener; import org.osgi.framework.BundleContext; import org.osgi.framework.ServiceRegistration; import org.springframework.transaction.PlatformTransactionManager; import org.springframework.transaction.jta.JtaTransactionManager; import org.springframework.transaction.support.TransactionSynchronization; import org.springframework.transaction.support.TransactionSynchronizationManager; /** */ public class PlatformTransactionManagerImple extends JtaTransactionManager { private final Map<Transaction, SuspendedResourcesHolder> suspendedResources = new ConcurrentHashMap<>(); public PlatformTransactionManagerImple(OsgiTransactionManager transactionManager) throws XAException { super(transactionManager, transactionManager); transactionManager.setListener(new Listener() { public void resumed(Transaction transaction) { SuspendedResourcesHolder holder = suspendedResources.remove(transaction); if (holder != null) { TransactionSynchronizationManager.setActualTransactionActive(true); TransactionSynchronizationManager.setCurrentTransactionReadOnly(holder.isReadOnly()); TransactionSynchronizationManager.setCurrentTransactionName(holder.getName()); TransactionSynchronizationManager.initSynchronization(); for (TransactionSynchronization synchronization : holder.getSuspendedSynchronizations()) { synchronization.resume(); TransactionSynchronizationManager.registerSynchronization(synchronization); } } } public void suspended(Transaction transaction) { if (TransactionSynchronizationManager.isSynchronizationActive()) { List<TransactionSynchronization> suspendedSynchronizations = TransactionSynchronizationManager.getSynchronizations(); for (TransactionSynchronization suspendedSynchronization : suspendedSynchronizations) { suspendedSynchronization.suspend(); } TransactionSynchronizationManager.clearSynchronization(); String name = TransactionSynchronizationManager.getCurrentTransactionName(); TransactionSynchronizationManager.setCurrentTransactionName(null); boolean readOnly = TransactionSynchronizationManager.isCurrentTransactionReadOnly(); TransactionSynchronizationManager.setCurrentTransactionReadOnly(false); TransactionSynchronizationManager.setActualTransactionActive(false); SuspendedResourcesHolder holder = new SuspendedResourcesHolder(suspendedSynchronizations, name, readOnly); suspendedResources.put(transaction, holder); } } }); } public static ServiceRegistration register(BundleContext bundleContext, OsgiTransactionManager transactionManager) throws Exception { PlatformTransactionManagerImple ptm = new PlatformTransactionManagerImple(transactionManager); return bundleContext.registerService(PlatformTransactionManager.class, ptm, null); } /** * Holder for suspended resources. * Used internally by <code>suspend</code> and <code>resume</code>. */ private static class SuspendedResourcesHolder { private final List<TransactionSynchronization> suspendedSynchronizations; private final String name; private final boolean readOnly; public SuspendedResourcesHolder(List<TransactionSynchronization> suspendedSynchronizations, String name, boolean readOnly) { this.suspendedSynchronizations = suspendedSynchronizations; this.name = name; this.readOnly = readOnly; } public List<TransactionSynchronization> getSuspendedSynchronizations() { return suspendedSynchronizations; } public String getName() { return name; } public boolean isReadOnly() { return readOnly; } } }