/*
 * Copyright (c) 2015 Brocade Communications Systems, Inc. and others.  All rights reserved.
 *
 * This program and the accompanying materials are made available under the
 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
 * and is available at http://www.eclipse.org/legal/epl-v10.html
 */
package org.opendaylight.controller.cluster.datastore;

import static java.util.Objects.requireNonNull;

import akka.actor.ActorSelection;
import com.google.common.util.concurrent.FutureCallback;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.MoreExecutors;
import com.google.common.util.concurrent.SettableFuture;
import java.util.Optional;
import java.util.SortedSet;
import org.opendaylight.controller.cluster.access.concepts.TransactionIdentifier;
import org.opendaylight.controller.cluster.datastore.messages.AbstractRead;
import org.opendaylight.mdsal.common.api.ReadFailedException;
import org.opendaylight.mdsal.dom.spi.store.DOMStoreReadTransaction;
import org.opendaylight.mdsal.dom.spi.store.DOMStoreTransaction;
import org.opendaylight.mdsal.dom.spi.store.DOMStoreWriteTransaction;
import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
import scala.concurrent.Future;

/**
 * Processes front-end transaction operations locally before being committed to the destination shard.
 * Instances of this class are used when the destination shard is local to the caller.
 *
 * @author Thomas Pantelis
 */
abstract class LocalTransactionContext extends AbstractTransactionContext {
    private final DOMStoreTransaction txDelegate;
    private final LocalTransactionReadySupport readySupport;
    private Exception operationError;

    LocalTransactionContext(final DOMStoreTransaction txDelegate, final TransactionIdentifier identifier,
            final LocalTransactionReadySupport readySupport) {
        super(identifier);
        this.txDelegate = requireNonNull(txDelegate);
        this.readySupport = readySupport;
    }

    protected abstract DOMStoreWriteTransaction getWriteDelegate();

    protected abstract DOMStoreReadTransaction getReadDelegate();

    @Override
    @SuppressWarnings("checkstyle:IllegalCatch")
    public void executeDelete(final YangInstanceIdentifier path, final Boolean havePermit) {
        incrementModificationCount();
        if (operationError == null) {
            try {
                getWriteDelegate().delete(path);
            } catch (Exception e) {
                operationError = e;
            }
        }
    }

    @Override
    @SuppressWarnings("checkstyle:IllegalCatch")
    public void executeMerge(final YangInstanceIdentifier path, final NormalizedNode<?, ?> data,
            final Boolean havePermit) {
        incrementModificationCount();
        if (operationError == null) {
            try {
                getWriteDelegate().merge(path, data);
            } catch (Exception e) {
                operationError = e;
            }
        }
    }

    @Override
    @SuppressWarnings("checkstyle:IllegalCatch")
    public void executeWrite(final YangInstanceIdentifier path, final NormalizedNode<?, ?> data,
            final Boolean havePermit) {
        incrementModificationCount();
        if (operationError == null) {
            try {
                getWriteDelegate().write(path, data);
            } catch (Exception e) {
                operationError = e;
            }
        }
    }

    @Override
    public <T> void executeRead(final AbstractRead<T> readCmd, final SettableFuture<T> proxyFuture,
            final Boolean havePermit) {
        Futures.addCallback(readCmd.apply(getReadDelegate()), new FutureCallback<T>() {
            @Override
            public void onSuccess(final T result) {
                proxyFuture.set(result);
            }

            @Override
            public void onFailure(final Throwable failure) {
                proxyFuture.setException(failure instanceof Exception
                        ? ReadFailedException.MAPPER.apply((Exception) failure) : failure);
            }
        }, MoreExecutors.directExecutor());
    }

    private LocalThreePhaseCommitCohort ready() {
        logModificationCount();
        return readySupport.onTransactionReady(getWriteDelegate(), operationError);
    }

    @Override
    public Future<ActorSelection> readyTransaction(final Boolean havePermit,
            final Optional<SortedSet<String>> participatingShardNames) {
        final LocalThreePhaseCommitCohort cohort = ready();
        return cohort.initiateCoordinatedCommit(participatingShardNames);
    }

    @Override
    public Future<Object> directCommit(final Boolean havePermit) {
        final LocalThreePhaseCommitCohort cohort = ready();
        return cohort.initiateDirectCommit();
    }

    @Override
    public void closeTransaction() {
        txDelegate.close();
    }
}

@@ -732,16 +732,52 @@
 tedSet;%0A
+import java.util.function.Consumer;%0A
 import o
@@ -2257,30 +2257,16 @@
 ate();%0A%0A
-    @Override%0A
     @Sup
@@ -2303,37 +2303,38 @@
 galCatch%22)%0A    p
-ublic
+rivate
  void executeDel
@@ -2334,74 +2334,64 @@
 cute
-Delete(final YangInstanceIdentifier path, final Boolean havePermit
+Modification(Consumer%3CDOMStoreWriteTransaction%3E consumer
 ) %7B%0A
@@ -2492,32 +2492,48 @@
                 
+consumer.accept(
 getWriteDelegate
@@ -2538,20 +2538,8 @@
 te()
-.delete(path
 );%0A 
@@ -2662,52 +2662,187 @@
     
-@SuppressWarnings(%22checkstyle:IllegalCatch%22)
+public void executeDelete(final YangInstanceIdentifier path, final Boolean havePermit) %7B%0A        executeModification(transaction -%3E transaction.delete(path));%0A    %7D%0A%0A    @Override
 %0A   
@@ -2979,33 +2979,31 @@
 ) %7B%0A        
-increment
+execute
 Modification
@@ -3006,292 +3006,76 @@
 tion
-Count();%0A        if (operationError == null) %7B%0A            try %7B%0A                getWriteDelegate().merge(path, data);%0A            %7D catch (Exception e) %7B%0A                operationError = e;%0A            %7D%0A        %7D%0A    %7D%0A%0A    @Override%0A    @SuppressWarnings(%22checkstyle:IllegalCatch%22)
+(transaction -%3E transaction.merge(path, data));%0A    %7D%0A%0A    @Override
 %0A   
@@ -3212,33 +3212,31 @@
 ) %7B%0A        
-increment
+execute
 Modification
@@ -3239,222 +3239,55 @@
 tion
-Count();%0A        if (operationError == null) %7B%0A            try %7B%0A                getWriteDelegate().write(path, data);%0A            %7D catch (Exception e) %7B%0A                operationError = e;%0A            %7D%0A        %7D
+(transaction -%3E transaction.write(path, data));
 %0A   

Simplify LocalTransactionContext