/*
 * Copyright (c) 2016 Red Hat, 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.netvirt.statemanager;

import com.google.common.util.concurrent.CheckedFuture;
import javax.annotation.PostConstruct;
import javax.inject.Inject;
import javax.inject.Singleton;
import org.opendaylight.controller.md.sal.binding.api.DataBroker;
import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
import org.opendaylight.netvirt.bgpmanager.api.IBgpManager;
import org.opendaylight.netvirt.elanmanager.api.IElanService;
import org.opendaylight.netvirt.fibmanager.api.IFibManager;
import org.opendaylight.netvirt.neutronvpn.interfaces.INeutronVpnManager;
import org.opendaylight.netvirt.vpnmanager.api.IVpnManager;
import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology;
import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TopologyId;
import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology;
import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyBuilder;
import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

@Singleton
public class StateManager implements IStateManager {

    private static final Logger LOG = LoggerFactory.getLogger(StateManager.class);
    private final DataBroker dataBroker;

    @Inject
    public StateManager(final DataBroker databroker, final IBgpManager bgpManager, final IElanService elanService,
                        final IFibManager fibManager, final INeutronVpnManager neutronVpnManager,
                        final IVpnManager vpnManager) {
        this.dataBroker = databroker;
    }

    /**
     * Start method called by blueprint.
     */
    @PostConstruct
    public void start() {
        setReady(true);
    }

    /**
     * Executes put as a blocking transaction.
     *
     * @param logicalDatastoreType {@link LogicalDatastoreType} which should be modified
     * @param path {@link InstanceIdentifier} for path to read
     * @param <D> the data object type
     * @return the result of the request
     */
    public <D extends org.opendaylight.yangtools.yang.binding.DataObject> boolean put(
            final LogicalDatastoreType logicalDatastoreType, final InstanceIdentifier<D> path, D data)  {
        boolean result = false;
        final WriteTransaction transaction = dataBroker.newWriteOnlyTransaction();
        transaction.put(logicalDatastoreType, path, data, WriteTransaction.CREATE_MISSING_PARENTS);
        CheckedFuture<Void, TransactionCommitFailedException> future = transaction.submit();
        try {
            future.checkedGet();
            result = true;
        } catch (TransactionCommitFailedException e) {
            LOG.warn("StateManager failed to put {} ", path, e);
        }
        return result;
    }

    private void initializeNetvirtTopology() {
        final TopologyId topologyId = new TopologyId("netvirt:1");
        InstanceIdentifier<Topology> path =
                InstanceIdentifier.create(NetworkTopology.class).child(Topology.class, new TopologyKey(topologyId));
        TopologyBuilder tpb = new TopologyBuilder();
        tpb.setTopologyId(topologyId);
        if (!put(LogicalDatastoreType.OPERATIONAL, path, tpb.build())) {
            LOG.error("StateManager error initializing netvirt topology");
        }
    }

    private class WriteTopology implements Runnable {
        @Override
        public void run() {
            try {
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                LOG.warn("StateManager thread was interrupted", e);
            }
            LOG.info("StateManager all is ready");
            initializeNetvirtTopology();
        }
    }

    @Override
    public void setReady(boolean ready) {
        if (ready) {
            new Thread(new WriteTopology()).start();
        }
    }
}

@@ -354,55 +354,47 @@
 ort 
-com.google.common.util.concurrent.CheckedFuture
+java.util.concurrent.ExecutionException
 ;%0Aim
@@ -559,80 +559,8 @@
 er;%0A
-import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;%0A
 impo
@@ -663,74 +663,118 @@
 ght.
-controller.md.sal.common.api.data.TransactionCommitFailedException
+genius.infra.ManagedNewTransactionRunner;%0Aimport org.opendaylight.genius.infra.ManagedNewTransactionRunnerImpl
 ;%0Aim
@@ -1952,27 +1952,42 @@
 nal 
-DataBroker dataBrok
+ManagedNewTransactionRunner txRunn
 er;%0A
@@ -2040,25 +2040,25 @@
 aBroker data
-b
+B
 roker, final
@@ -2285,31 +2285,66 @@
 his.
-dataBroker = 
+txRunner = new ManagedNewTransactionRunnerImpl(
 data
-b
+B
 roker
+)
 ;%0A  
@@ -2485,1045 +2485,8 @@
  %7D%0A%0A
-    /**%0A     * Executes put as a blocking transaction.%0A     *%0A     * @param logicalDatastoreType %7B@link LogicalDatastoreType%7D which should be modified%0A     * @param path %7B@link InstanceIdentifier%7D for path to read%0A     * @param %3CD%3E the data object type%0A     * @return the result of the request%0A     */%0A    public %3CD extends org.opendaylight.yangtools.yang.binding.DataObject%3E boolean put(%0A            final LogicalDatastoreType logicalDatastoreType, final InstanceIdentifier%3CD%3E path, D data)  %7B%0A        boolean result = false;%0A        final WriteTransaction transaction = dataBroker.newWriteOnlyTransaction();%0A        transaction.put(logicalDatastoreType, path, data, WriteTransaction.CREATE_MISSING_PARENTS);%0A        CheckedFuture%3CVoid, TransactionCommitFailedException%3E future = transaction.submit();%0A        try %7B%0A            future.checkedGet();%0A            result = true;%0A        %7D catch (TransactionCommitFailedException e) %7B%0A            LOG.warn(%22StateManager failed to put %7B%7D %22, path, e);%0A        %7D%0A        return result;%0A    %7D%0A%0A
     
@@ -2860,69 +2860,227 @@
     
-if (!put(LogicalDatastoreType.OPERATIONAL, path, tpb.build())
+try %7B%0A            txRunner.callWithNewWriteOnlyTransactionAndSubmit(%0A                tx -%3E tx.put(LogicalDatastoreType.OPERATIONAL, path, tpb.build())).get();%0A        %7D catch (InterruptedException %7C ExecutionException e
 ) %7B%0A
@@ -3151,16 +3151,19 @@
 opology%22
+, e
 );%0A     

use transaction manager