Remove javax.annotation nullness annotations
[netconf.git] / netconf / sal-netconf-connector / src / main / java / org / opendaylight / netconf / sal / connect / netconf / sal / tx / WriteCandidateTx.java
1 /*
2  * Copyright (c) 2014 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.netconf.sal.connect.netconf.sal.tx;
10
11 import com.google.common.util.concurrent.FutureCallback;
12 import com.google.common.util.concurrent.Futures;
13 import com.google.common.util.concurrent.ListenableFuture;
14 import com.google.common.util.concurrent.MoreExecutors;
15 import java.util.Optional;
16 import org.opendaylight.mdsal.dom.api.DOMRpcResult;
17 import org.opendaylight.netconf.sal.connect.netconf.util.NetconfBaseOps;
18 import org.opendaylight.netconf.sal.connect.netconf.util.NetconfRpcFutureCallback;
19 import org.opendaylight.netconf.sal.connect.util.RemoteDeviceId;
20 import org.opendaylight.yangtools.yang.common.RpcResult;
21 import org.opendaylight.yangtools.yang.data.api.ModifyAction;
22 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
23 import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
24 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
25 import org.slf4j.Logger;
26 import org.slf4j.LoggerFactory;
27
28 /**
29  * Tx implementation for netconf devices that support only candidate datastore and no writable running.
30  * The sequence goes as:
31  * <ol>
32  *   <li>Lock candidate datastore on tx construction
33  *     <ul>
34  *       <li>Lock has to succeed, if it does not, an attempt to discard changes is made</li>
35  *       <li>Discard changes has to succeed</li>
36  *       <li>If discard is successful, lock is reattempted</li>
37  *       <li>Second lock attempt has to succeed</li>
38  *     </ul>
39  *   </li>
40  *   <li>Edit-config in candidate N times
41  *     <ul>
42  *       <li>If any issue occurs during edit,
43  *       datastore is discarded using discard-changes rpc, unlocked and an exception is thrown async</li>
44  *     </ul>
45  *   </li>
46  *   <li>Commit and Unlock candidate datastore async</li>
47  * </ol>
48  */
49 public class WriteCandidateTx extends AbstractWriteTx {
50
51     private static final Logger LOG  = LoggerFactory.getLogger(WriteCandidateTx.class);
52
53     public WriteCandidateTx(final RemoteDeviceId id, final NetconfBaseOps rpc, final boolean rollbackSupport) {
54         super(rpc, id, rollbackSupport);
55     }
56
57     @Override
58     protected synchronized void init() {
59         LOG.trace("{}: Initializing {} transaction", id, getClass().getSimpleName());
60         lock();
61     }
62
63     private void lock() {
64         final FutureCallback<DOMRpcResult> lockCandidateCallback = new FutureCallback<DOMRpcResult>() {
65             @Override
66             public void onSuccess(final DOMRpcResult result) {
67                 if (isSuccess(result)) {
68                     if (LOG.isTraceEnabled()) {
69                         LOG.trace("Lock candidate successful");
70                     }
71                 } else {
72                     LOG.warn("{}: lock candidate invoked unsuccessfully: {}", id, result.getErrors());
73                 }
74             }
75
76             @Override
77             public void onFailure(final Throwable throwable) {
78                 LOG.warn("Lock candidate operation failed. {}", throwable);
79                 discardChanges();
80             }
81         };
82         resultsFutures.add(netOps.lockCandidate(lockCandidateCallback));
83     }
84
85     @Override
86     protected void cleanup() {
87         discardChanges();
88         cleanupOnSuccess();
89     }
90
91     /**
92      * This has to be non blocking since it is called from a callback on commit
93      * and its netty threadpool that is really sensitive to blocking calls.
94      */
95     private void discardChanges() {
96         netOps.discardChanges(new NetconfRpcFutureCallback("Discarding candidate", id));
97     }
98
99     @Override
100     public synchronized ListenableFuture<RpcResult<Void>> performCommit() {
101         resultsFutures.add(netOps.commit(new NetconfRpcFutureCallback("Commit", id)));
102         final ListenableFuture<RpcResult<Void>> txResult = resultsToTxStatus();
103
104         Futures.addCallback(txResult, new FutureCallback<RpcResult<Void>>() {
105             @Override
106             public void onSuccess(final RpcResult<Void> result) {
107                 cleanupOnSuccess();
108             }
109
110             @Override
111             public void onFailure(final Throwable throwable) {
112                 // TODO If lock is cause of this failure cleanup will issue warning log
113                 // cleanup is trying to do unlock, but this will fail
114                 cleanup();
115             }
116         }, MoreExecutors.directExecutor());
117
118         return txResult;
119     }
120
121     protected void cleanupOnSuccess() {
122         unlock();
123     }
124
125     @Override
126     protected void editConfig(final YangInstanceIdentifier path,
127                               final Optional<NormalizedNode<?, ?>> data,
128                               final DataContainerChild<?, ?> editStructure,
129                               final Optional<ModifyAction> defaultOperation,
130                               final String operation) {
131
132         final NetconfRpcFutureCallback editConfigCallback = new NetconfRpcFutureCallback("Edit candidate", id);
133
134         if (defaultOperation.isPresent()) {
135             resultsFutures.add(netOps.editConfigCandidate(
136                     editConfigCallback, editStructure, defaultOperation.get(), rollbackSupport));
137         } else {
138             resultsFutures.add(netOps.editConfigCandidate(editConfigCallback, editStructure, rollbackSupport));
139         }
140     }
141
142     /**
143      * This has to be non blocking since it is called from a callback on commit
144      * and its netty threadpool that is really sensitive to blocking calls.
145      */
146     private void unlock() {
147         netOps.unlockCandidate(new NetconfRpcFutureCallback("Unlock candidate", id));
148     }
149
150 }