/* 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.camunda.bpm.engine.spring;


import org.camunda.bpm.engine.impl.cfg.TransactionContext;
import org.camunda.bpm.engine.impl.cfg.TransactionListener;
import org.camunda.bpm.engine.impl.cfg.TransactionState;
import org.camunda.bpm.engine.impl.interceptor.CommandContext;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.TransactionSynchronization;
import org.springframework.transaction.support.TransactionSynchronizationManager;


/**
 * @author Frederik Heremans
 * @author Joram Barrez
 */
public class SpringTransactionContext implements TransactionContext {

  protected PlatformTransactionManager transactionManager;
  protected CommandContext commandContext;
  
  public SpringTransactionContext(PlatformTransactionManager transactionManager, CommandContext commandContext) {
    this.transactionManager = transactionManager;
    this.commandContext = commandContext;
  }
  
  public void commit() {
    // Do nothing, transaction is managed by spring
  }

  public void rollback() {
    // Just in case the rollback isn't triggered by an
    // exception, we mark the current transaction rollBackOnly.
    transactionManager.getTransaction(null).setRollbackOnly();
  }

  public void addTransactionListener(final TransactionState transactionState, final TransactionListener transactionListener) {
    if (transactionState.equals(TransactionState.COMMITTING)) {
      
      TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronizationAdapter() {
        @Override
        public void beforeCommit(boolean readOnly) {
          transactionListener.execute(commandContext);
        }
      });
      
    } else if (transactionState.equals(TransactionState.COMMITTED)) {
    
      TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronizationAdapter() {
        @Override
        public void afterCommit() {
          transactionListener.execute(commandContext);
        }
      });
      
    } else if (transactionState.equals(TransactionState.ROLLINGBACK)) {
      
      TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronizationAdapter() {
        @Override
        public void beforeCompletion() {
          transactionListener.execute(commandContext);
        }
      });
      
    } else if (transactionState.equals(TransactionState.ROLLED_BACK)) {
      
      TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronizationAdapter() {
        @Override
        public void afterCompletion(int status) {
          if(TransactionSynchronization.STATUS_ROLLED_BACK == status) {
            transactionListener.execute(commandContext);
          }
        }
      });
      
    }
    
  }

  public boolean isTransactionActive() {
    if(TransactionSynchronizationManager.isActualTransactionActive()){
      TransactionStatus transaction = transactionManager.getTransaction(null);
      return !transaction.isRollbackOnly() && !transaction.isCompleted();
    }
    return TransactionSynchronizationManager.isActualTransactionActive();
  }
  
  protected abstract class TransactionSynchronizationAdapter implements TransactionSynchronization {

    public void suspend() {
    }

    public void resume() {
    }

    public void flush() {
    }

    public void beforeCommit(boolean readOnly) {
    }

    public void beforeCompletion() {
    }

    public void afterCommit() {
    }

    public void afterCompletion(int status) {
    }
    
  }

}

@@ -907,66 +907,8 @@
 er;%0A
-import org.springframework.transaction.TransactionStatus;%0A
 impo
@@ -978,16 +978,16 @@
 zation;%0A
+
 import o
@@ -1296,16 +1296,75 @@
 ontext;%0A
+  protected TransactionState lastTransactionState = null; %0A
   %0A  pub
@@ -1522,16 +1522,16 @@
 anager;%0A
-
     this
@@ -1564,16 +1564,719 @@
 ontext;%0A
+    TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronizationAdapter() %7B%0A      @Override%0A      public void beforeCommit(boolean readOnly) %7B%0A        lastTransactionState = TransactionState.COMMITTING;%0A      %7D%0A      @Override%0A      public void afterCommit() %7B%0A        lastTransactionState = TransactionState.COMMITTED;%0A      %7D%0A      @Override%0A      public void beforeCompletion() %7B%0A        lastTransactionState = TransactionState.ROLLINGBACK;%0A      %7D%0A      @Override%0A      public void afterCompletion(int status) %7B%0A        if(TransactionSynchronization.STATUS_ROLLED_BACK == status) %7B%0A          lastTransactionState = TransactionState.ROLLED_BACK;%0A        %7D%0A      %7D%0A    %7D);%0A
   %7D%0A  %0A 
@@ -4221,24 +4221,32 @@
 e())%7B%0A      
+return !
 TransactionS
@@ -4252,81 +4252,56 @@
 Stat
-us transaction = transactionManager.getTransaction(null);%0A      return !t
+e.ROLLED_BACK.equals(lastTransactionState) && !T
 rans
@@ -4310,54 +4310,53 @@
 tion
-.isRollbackOnly() && !transaction.isCompleted(
+State.ROLLINGBACK.equals(lastTransactionState
 );%0A 

change check for transaction state to listener