+ // NOOP
+ }
+
+ private void recreateTxChain() {
+ synchronized (txLock) {
+ createTxChain();
+ wTx = null;
+ }
+ }
+
+ @Nullable
+ private WriteTransaction getTransactionSafely() {
+ if (wTx == null && TransactionChainManagerStatus.WORKING.equals(transactionChainManagerStatus)) {
+ synchronized (txLock) {
+ if (wTx == null && TransactionChainManagerStatus.WORKING.equals(transactionChainManagerStatus)) {
+ if (wTx == null && txChainFactory != null) {
+ wTx = txChainFactory.newWriteOnlyTransaction();
+ }
+ }
+ }
+ }
+ return wTx;
+ }
+
+ @VisibleForTesting
+ void enableSubmit() {
+ submitIsEnabled = true;
+ }
+
+ ListenableFuture<Void> shuttingDown() {
+ LOG.debug("TxManager is going SUTTING_DOWN for node {}", nodeII);
+ ListenableFuture<Void> future;
+ synchronized (txLock) {
+ this.transactionChainManagerStatus = TransactionChainManagerStatus.SHUTTING_DOWN;
+ future = txChainShuttingDown();
+ }
+ return future;
+ }
+
+ private ListenableFuture<Void> txChainShuttingDown() {
+ ListenableFuture<Void> future;
+ if (txChainFactory == null) {
+ // stay with actual thread
+ future = Futures.immediateCheckedFuture(null);
+ } else {
+ // hijack md-sal thread
+ if (wTx == null) {
+ wTx = txChainFactory.newWriteOnlyTransaction();
+ }
+ final NodeBuilder nodeBuilder = new NodeBuilder().setId(deviceState.getNodeId());
+ wTx.merge(LogicalDatastoreType.OPERATIONAL, nodeII, nodeBuilder.build());
+ future = wTx.submit();
+ wTx = null;
+
+ future = Futures.withFallback(future, new FutureFallback<Void>() {
+
+ @Override
+ public ListenableFuture<Void> create(final Throwable t) throws Exception {
+ LOG.debug("Last ShuttingDown Transaction for node {} fail. Put empty FlowCapableNode",
+ deviceState.getNodeId());
+ final ReadOnlyTransaction readWriteTx = dataBroker.newReadOnlyTransaction();
+ final CheckedFuture<Optional<FlowCapableNode>, ReadFailedException> readFlowNode = readWriteTx
+ .read(LogicalDatastoreType.OPERATIONAL, nodeII.augmentation(FlowCapableNode.class));
+ return Futures.transform(readFlowNode, new AsyncFunction<Optional<FlowCapableNode>, Void>() {
+
+ @Override
+ public ListenableFuture<Void> apply(final Optional<FlowCapableNode> input) {
+ if (input.isPresent()) {
+ final WriteTransaction delWtx = dataBroker.newWriteOnlyTransaction();
+ nodeBuilder.addAugmentation(FlowCapableNode.class, new FlowCapableNodeBuilder().build());
+ delWtx.put(LogicalDatastoreType.OPERATIONAL, nodeII, nodeBuilder.build());
+ return delWtx.submit();
+ }
+ return Futures.immediateFuture(null);
+ }
+ });
+ }
+ });
+ }
+ return future;
+ }
+
+ /**
+ * Transaction could be close if we are not submit anything. We have property submitIsEnable what
+ * could protect us for check it is NEW transaction from chain and we are able close everything
+ * safely.
+ */
+ void clearUnsubmittedTransaction() {
+ LOG.debug("Cleaning unsubmited Transaction for Device {}", deviceState.getNodeId());
+ Verify.verify(!submitIsEnabled, "We are not able clean TxChain {}", deviceState.getNodeId());
+ synchronized (txLock) {
+ if (wTx != null) {
+ wTx.cancel();
+ wTx = null;
+ }
+ if (txChainFactory != null) {
+ txChainFactory.close();
+ txChainFactory = null;
+ }
+ transactionChainManagerStatus = TransactionChainManagerStatus.SLEEPING;
+ }
+ }
+
+ @Override
+ public void close() {
+ LOG.debug("Setting transactionChainManagerStatus to SHUTTING_DOWN, will wait for ownershipservice to notify", nodeII);
+ Preconditions.checkState(TransactionChainManagerStatus.SHUTTING_DOWN.equals(transactionChainManagerStatus));
+ Preconditions.checkState(wTx == null);
+ synchronized (txLock) {
+ if (txChainFactory != null) {
+ txChainFactory.close();
+ txChainFactory = null;
+ }
+ }
+ Preconditions.checkState(txChainFactory == null);
+ }
+
+ private enum TransactionChainManagerStatus {
+ /** txChainManager is sleeping - is not active (SLAVE or default init value) */
+ WORKING,
+ /** txChainManager is working - is active (MASTER) */
+ SLEEPING,
+ /** txChainManager is trying to be closed - device disconnecting */
+ SHUTTING_DOWN;