d249231757640ffbd3eec46e24621033931310ea
[openflowplugin.git] / openflowplugin-impl / src / main / java / org / opendaylight / openflowplugin / impl / device / TransactionChainManager.java
1 /**
2  * Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8
9 package org.opendaylight.openflowplugin.impl.device;
10
11 import com.google.common.annotations.VisibleForTesting;
12 import com.google.common.base.Preconditions;
13 import com.google.common.util.concurrent.CheckedFuture;
14 import com.google.common.util.concurrent.FutureCallback;
15 import com.google.common.util.concurrent.Futures;
16 import javax.annotation.Nonnull;
17 import org.opendaylight.controller.md.sal.binding.api.BindingTransactionChain;
18 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
19 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
20 import org.opendaylight.controller.md.sal.common.api.data.AsyncTransaction;
21 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
22 import org.opendaylight.controller.md.sal.common.api.data.TransactionChain;
23 import org.opendaylight.controller.md.sal.common.api.data.TransactionChainListener;
24 import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
27 import org.opendaylight.yangtools.concepts.Registration;
28 import org.opendaylight.yangtools.yang.binding.DataObject;
29 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
30 import org.opendaylight.yangtools.yang.binding.KeyedInstanceIdentifier;
31 import org.slf4j.Logger;
32 import org.slf4j.LoggerFactory;
33
34 /**
35  * openflowplugin-impl
36  * org.opendaylight.openflowplugin.impl.device
37  * <p/>
38  * Package protected class for controlling {@link WriteTransaction} life cycle. It is
39  * a {@link TransactionChainListener} and provide package protected methods for writeToTransaction
40  * method (wrapped {@link WriteTransaction#put(LogicalDatastoreType, InstanceIdentifier, DataObject)})
41  * and submitTransaction method (wrapped {@link WriteTransaction#submit()})
42  *
43  * @author <a href="mailto:vdemcak@cisco.com">Vaclav Demcak</a>
44  *         </p>
45  *         Created: Apr 2, 2015
46  */
47 class TransactionChainManager implements TransactionChainListener, AutoCloseable {
48
49     private static final Logger LOG = LoggerFactory.getLogger(TransactionChainManager.class);
50
51     private final Object txLock = new Object();
52
53     private final DataBroker dataBroker;
54     private WriteTransaction wTx;
55     private BindingTransactionChain txChainFactory;
56     private boolean submitIsEnabled;
57
58     public TransactionChainManagerStatus getTransactionChainManagerStatus() {
59         return transactionChainManagerStatus;
60     }
61
62     private TransactionChainManagerStatus transactionChainManagerStatus;
63     private ReadyForNewTransactionChainHandler readyForNewTransactionChainHandler;
64     private final KeyedInstanceIdentifier<Node, NodeKey> nodeII;
65     private Registration managerRegistration;
66
67     TransactionChainManager(@Nonnull final DataBroker dataBroker,
68                             @Nonnull final KeyedInstanceIdentifier<Node, NodeKey> nodeII,
69                             @Nonnull final Registration managerRegistration) {
70         this.dataBroker = Preconditions.checkNotNull(dataBroker);
71         this.nodeII = Preconditions.checkNotNull(nodeII);
72         this.managerRegistration = Preconditions.checkNotNull(managerRegistration);
73         this.transactionChainManagerStatus = TransactionChainManagerStatus.WORKING;
74         createTxChain(dataBroker);
75         LOG.debug("created txChainManager");
76     }
77
78     private void createTxChain(final DataBroker dataBroker) {
79         txChainFactory = dataBroker.createTransactionChain(TransactionChainManager.this);
80     }
81
82     void initialSubmitWriteTransaction() {
83         enableSubmit();
84         submitWriteTransaction();
85     }
86
87     public synchronized boolean attemptToRegisterHandler(final ReadyForNewTransactionChainHandler readyForNewTransactionChainHandler) {
88         if (TransactionChainManagerStatus.SHUTTING_DOWN.equals(this.transactionChainManagerStatus)
89                 && null == this.readyForNewTransactionChainHandler) {
90             this.readyForNewTransactionChainHandler = readyForNewTransactionChainHandler;
91             if (managerRegistration == null) {
92                 this.readyForNewTransactionChainHandler.onReadyForNewTransactionChain();
93             }
94             return true;
95         } else {
96             return false;
97         }
98     }
99
100     boolean submitWriteTransaction() {
101         if (!submitIsEnabled) {
102             LOG.trace("transaction not committed - submit block issued");
103             return false;
104         }
105         synchronized (txLock) {
106             if (wTx == null) {
107                 LOG.trace("nothing to commit - submit returns true");
108                 return true;
109             }
110             wTx.submit();
111             wTx = null;
112         }
113         return true;
114     }
115
116     <T extends DataObject> void addDeleteOperationTotTxChain(final LogicalDatastoreType store,
117                                                              final InstanceIdentifier<T> path) {
118         final WriteTransaction writeTx = getTransactionSafely();
119         writeTx.delete(store, path);
120     }
121
122     <T extends DataObject> void writeToTransaction(final LogicalDatastoreType store,
123                                                    final InstanceIdentifier<T> path, final T data) {
124         final WriteTransaction writeTx = getTransactionSafely();
125         writeTx.put(store, path, data);
126     }
127
128     @Override
129     public void onTransactionChainFailed(final TransactionChain<?, ?> chain,
130                                          final AsyncTransaction<?, ?> transaction, final Throwable cause) {
131         LOG.warn("txChain failed -> recreating", cause);
132         recreateTxChain();
133     }
134
135     @Override
136     public void onTransactionChainSuccessful(final TransactionChain<?, ?> chain) {
137         // NOOP - only yet, here is probably place for notification to get new WriteTransaction
138     }
139
140     private void recreateTxChain() {
141         txChainFactory.close();
142         createTxChain(dataBroker);
143         synchronized (txLock) {
144             wTx = null;
145         }
146     }
147
148     private WriteTransaction getTransactionSafely() {
149         if (wTx == null && !TransactionChainManagerStatus.SHUTTING_DOWN.equals(transactionChainManagerStatus)) {
150             synchronized (txLock) {
151                 if (wTx == null) {
152                     wTx = txChainFactory.newWriteOnlyTransaction();
153                 }
154             }
155         }
156         return wTx;
157     }
158
159     @VisibleForTesting
160     void enableSubmit() {
161         submitIsEnabled = true;
162     }
163
164     @Override
165     public void close() {
166         LOG.debug("Removing node {} from operational DS.", nodeII);
167         synchronized (txLock) {
168             final WriteTransaction writeTx = getTransactionSafely();
169             this.transactionChainManagerStatus = TransactionChainManagerStatus.SHUTTING_DOWN;
170             writeTx.delete(LogicalDatastoreType.OPERATIONAL, nodeII);
171             LOG.debug("Delete node {} from operational DS put to write transaction.", nodeII);
172             CheckedFuture<Void, TransactionCommitFailedException> submitsFuture = writeTx.submit();
173             LOG.debug("Delete node {} from operational DS write transaction submitted.", nodeII);
174             Futures.addCallback(submitsFuture, new FutureCallback<Void>() {
175                 @Override
176                 public void onSuccess(final Void aVoid) {
177                     LOG.debug("Removing node {} from operational DS successful .", nodeII);
178                     notifyReadyForNewTransactionChainAndCloseFactory();
179                 }
180
181                 @Override
182                 public void onFailure(final Throwable throwable) {
183                     LOG.info("Attempt to close transaction chain factory failed.", throwable);
184                     notifyReadyForNewTransactionChainAndCloseFactory();
185                 }
186             });
187             wTx = null;
188         }
189     }
190
191     private void notifyReadyForNewTransactionChainAndCloseFactory() {
192         synchronized (this) {
193             try {
194                 LOG.debug("Closing registration in manager.");
195                 managerRegistration.close();
196             } catch (Exception e) {
197                 LOG.warn("Failed to close transaction chain manager's registration.", e);
198             }
199             managerRegistration = null;
200             if (null != readyForNewTransactionChainHandler) {
201                 readyForNewTransactionChainHandler.onReadyForNewTransactionChain();
202             }
203         }
204         txChainFactory.close();
205         LOG.debug("Transaction chain factory closed.");
206     }
207
208     public enum TransactionChainManagerStatus {
209         WORKING, SHUTTING_DOWN;
210     }
211
212 }