/*
* Copyright 2004-2009 the original author or authors.
*
* Licensed 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.compass.spring.transaction;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import org.compass.core.CompassException;
import org.compass.core.CompassSession;
import org.compass.core.CompassTransaction;
import org.compass.core.config.CompassSettings;
import org.compass.core.spi.InternalCompassSession;
import org.compass.core.transaction.AbstractTransactionFactory;
import org.compass.core.transaction.InternalCompassTransaction;
import org.compass.core.transaction.TransactionException;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.support.TransactionSynchronization;
import org.springframework.transaction.support.TransactionSynchronizationManager;
public class SpringSyncTransactionFactory extends AbstractTransactionFactory {
private static ThreadLocal<PlatformTransactionManager> transactionManagerHolder = new ThreadLocal<PlatformTransactionManager>();
private static String transactionManagerKey = SpringSyncTransactionFactory.class.getName();
private PlatformTransactionManager transactionManager;
private transient Map<TransactionSynchronization, CompassSession> currentSessionMap = new ConcurrentHashMap<TransactionSynchronization, CompassSession>();
public static void setTransactionManager(PlatformTransactionManager transactionManager) {
transactionManagerHolder.set(transactionManager);
}
protected void doConfigure(CompassSettings settings) {
this.transactionManager = transactionManagerHolder.get();
if (transactionManager == null) {
transactionManager = (PlatformTransactionManager) settings.getRegistry(transactionManagerKey);
}
if (transactionManager != null) {
settings.setRegistry(transactionManagerKey, transactionManager);
}
transactionManagerHolder.set(null);
}
protected boolean isWithinExistingTransaction(InternalCompassSession session) throws CompassException {
return TransactionSynchronizationManager.isActualTransactionActive();
// return ExistingSpringTxCompassHelper.isExistingTransaction(transactionManager);
}
protected InternalCompassTransaction doBeginTransaction(InternalCompassSession session) throws CompassException {
SpringSyncTransaction tr = new SpringSyncTransaction(this);
// transaction manager might be null, we rely then on the fact that the
// transaction started before
tr.begin(transactionManager, session, commitBeforeCompletion);
return tr;
}
protected InternalCompassTransaction doContinueTransaction(InternalCompassSession session)
throws CompassException {
SpringSyncTransaction tr = new SpringSyncTransaction(this);
tr.join(session);
return tr;
}
public CompassSession getTransactionBoundSession() throws CompassException {
TransactionSynchronization sync = lookupTransactionSynchronization();
if (sync == null) {
return null;
}
return currentSessionMap.get(sync);
}
protected void doBindSessionToTransaction(CompassTransaction tr, CompassSession session) throws CompassException {
TransactionSynchronization sync = lookupTransactionSynchronization();
if (sync == null) {
throw new TransactionException("Failed to find compass registered spring synchronization");
}
currentSessionMap.put(sync, session);
}
public void unbindSessionFromTransaction(TransactionSynchronization sync, CompassSession session) {
((InternalCompassSession) session).unbindTransaction();
currentSessionMap.remove(sync);
}
private TransactionSynchronization lookupTransactionSynchronization() throws TransactionException {
if (!TransactionSynchronizationManager.isSynchronizationActive()) {
if (transactionManager == null) {
throw new TransactionException(
"Either spring trnasction synchronization is not active, or a spring transaction has not been started, "
+ "you might want to check if transactionManager is set on LocalCompassBean configuration, so compass can start one by itself");
} else {
return null;
}
}
List syncs = TransactionSynchronizationManager.getSynchronizations();
for (int i = 0; i < syncs.size(); i++) {
Object sync = syncs.get(i);
if (sync instanceof SpringSyncTransaction.SpringTransactionSynchronization) {
SpringSyncTransaction.SpringTransactionSynchronization springSync = (SpringSyncTransaction.SpringTransactionSynchronization) sync;
if (springSync.getSession().getCompass() == compass) {
return springSync;
}
}
}
return null;
}
public PlatformTransactionManager getTransactionManager() {
return this.transactionManager;
}
}