org.openspaces.core.transaction.internal.InternalAsyncFutureListener.java Source code

Java tutorial

Introduction

Here is the source code for org.openspaces.core.transaction.internal.InternalAsyncFutureListener.java

Source

/*
 * Copyright (c) 2008-2016, GigaSpaces Technologies, Inc. All Rights Reserved.
 *
 * 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.openspaces.core.transaction.internal;

import com.gigaspaces.async.AsyncFutureListener;
import com.gigaspaces.async.AsyncResult;
import com.gigaspaces.async.internal.DefaultAsyncResult;

import net.jini.core.transaction.Transaction;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.openspaces.core.GigaSpace;
import org.openspaces.core.transaction.DefaultTransactionProvider;
import org.openspaces.core.transaction.manager.AbstractJiniTransactionManager;
import org.openspaces.core.transaction.manager.ExistingJiniTransactionManager;
import org.openspaces.core.transaction.manager.JiniTransactionHolder;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.DefaultTransactionStatus;

/**
 * @author kimchy
 */
public class InternalAsyncFutureListener<T> implements AsyncFutureListener<T> {

    private static final Log logger = LogFactory.getLog(InternalAsyncFutureListener.class);

    public static <T> AsyncFutureListener<T> wrapIfNeeded(AsyncFutureListener<T> listener, GigaSpace gigaSpace) {
        DefaultTransactionProvider txProvider = (DefaultTransactionProvider) gigaSpace.getTxProvider();
        JiniTransactionHolder holder = txProvider.getHolder();
        PlatformTransactionManager transactionManager = txProvider.getTransactionManager();
        if (holder == null || transactionManager == null) {
            // just wrap for exception translation
            return new InternalAsyncFutureListener<T>(gigaSpace, listener, null, transactionManager, holder);
        }
        // here, we create a dummy transaction status (with its new transaction set to true, so the commit/roolback
        // process will be performed). We also increase the ref count of the transaction, so only the last one will
        // be performed
        AbstractJiniTransactionManager.JiniTransactionObject jiniTransactionObject = new AbstractJiniTransactionManager.JiniTransactionObject();
        jiniTransactionObject.setJiniHolder(holder, false);
        TransactionStatus txStatus = new DefaultTransactionStatus(jiniTransactionObject, true, false, false, false,
                null);
        holder.incRef();
        return new InternalAsyncFutureListener<T>(gigaSpace, listener, txStatus, transactionManager, holder);
    }

    private final GigaSpace gigaSpace;

    private final AsyncFutureListener<T> listener;

    private final PlatformTransactionManager transactionManager;

    private final TransactionStatus txStatus;

    private final JiniTransactionHolder holder;

    private final boolean transactionalListener;

    public InternalAsyncFutureListener(GigaSpace gigaSpace, AsyncFutureListener<T> listener) {
        this(gigaSpace, listener, null, null, null);
    }

    public InternalAsyncFutureListener(GigaSpace gigaSpace, AsyncFutureListener<T> listener,
            TransactionStatus txStatus, PlatformTransactionManager transactionManager,
            JiniTransactionHolder holder) {
        this.gigaSpace = gigaSpace;
        this.listener = listener;
        this.txStatus = txStatus;
        this.transactionManager = transactionManager;
        this.holder = holder;
        this.transactionalListener = listener instanceof TransactionalAsyncFutureListener;
    }

    private static Exception translate(Exception exception, GigaSpace gigaSpace) {
        if (exception == null)
            return null;
        Exception translatedException = gigaSpace.getExceptionTranslator().translateNoUncategorized(exception);
        return translatedException != null ? translatedException : exception;
    }

    public void onResult(AsyncResult<T> asyncResult) {
        AsyncResult<T> result = new DefaultAsyncResult<T>(asyncResult.getResult(),
                translate(asyncResult.getException(), gigaSpace));
        Transaction tx = null;
        if (holder != null) {
            tx = holder.getTransaction();
        }
        if (tx != null) {
            try {
                ExistingJiniTransactionManager.bindExistingTransaction(tx, true, true);
                listener.onResult(result);
                if (transactionalListener) {
                    ((TransactionalAsyncFutureListener<T>) listener).onTransactionalResult(result, txStatus);
                }
                transactionManager.commit(txStatus);
                if (transactionalListener) {
                    ((TransactionalAsyncFutureListener<T>) listener).onPostCommitTransaction(result);
                }
            } catch (RuntimeException e) {
                try {
                    transactionManager.rollback(txStatus);
                } catch (RuntimeException e1) {
                    if (logger.isDebugEnabled()) {
                        logger.debug("Failed to rollback transaction after failed commit", e1);
                    }
                }
                if (transactionalListener) {
                    ((TransactionalAsyncFutureListener<T>) listener).onPostRollbackTransaction(result);
                }
                throw e;
            } finally {
                ExistingJiniTransactionManager.unbindExistingTransactionIfPossible();
            }
        } else {
            listener.onResult(result);
            if (transactionalListener) {
                try {
                    ((TransactionalAsyncFutureListener<T>) listener).onTransactionalResult(result, txStatus);
                    ((TransactionalAsyncFutureListener<T>) listener).onPostCommitTransaction(result);
                } catch (RuntimeException e) {
                    ((TransactionalAsyncFutureListener<T>) listener).onPostRollbackTransaction(result);
                    throw e;
                }
            }
        }
    }
}