Value for transactions moved to yang module
[controller.git] / opendaylight / md-sal / sal-netconf-connector / src / main / java / org / opendaylight / controller / sal / connect / netconf / sal / tx / AbstractWriteTx.java
1 package org.opendaylight.controller.sal.connect.netconf.sal.tx;
2
3 import com.google.common.base.Function;
4 import com.google.common.base.Optional;
5 import com.google.common.base.Preconditions;
6 import com.google.common.util.concurrent.ListenableFuture;
7 import java.util.concurrent.ExecutionException;
8 import java.util.concurrent.TimeUnit;
9 import java.util.concurrent.TimeoutException;
10 import org.opendaylight.controller.md.sal.common.api.TransactionStatus;
11 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
12 import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction;
13 import org.opendaylight.controller.md.sal.dom.api.DOMRpcResult;
14 import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
15 import org.opendaylight.controller.sal.connect.netconf.listener.NetconfSessionPreferences;
16 import org.opendaylight.controller.sal.connect.netconf.util.NetconfBaseOps;
17 import org.opendaylight.controller.sal.connect.util.RemoteDeviceId;
18 import org.opendaylight.yangtools.yang.common.RpcResult;
19 import org.opendaylight.yangtools.yang.data.api.ModifyAction;
20 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
21 import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
22 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
23
24 public abstract class AbstractWriteTx implements DOMDataWriteTransaction {
25
26     private final long defaultRequestTimeoutMillis;
27
28     protected final RemoteDeviceId id;
29     protected final NetconfBaseOps netOps;
30     protected final NetconfSessionPreferences netconfSessionPreferences;
31     // Allow commit to be called only once
32     protected boolean finished = false;
33
34     public AbstractWriteTx(final NetconfBaseOps netOps, final RemoteDeviceId id, final NetconfSessionPreferences netconfSessionPreferences, long defaultRequestTimeoutMillis) {
35         this.netOps = netOps;
36         this.id = id;
37         this.netconfSessionPreferences = netconfSessionPreferences;
38         this.defaultRequestTimeoutMillis = defaultRequestTimeoutMillis;
39         init();
40     }
41
42     static boolean isSuccess(final DOMRpcResult result) {
43         return result.getErrors().isEmpty();
44     }
45
46     protected void checkNotFinished() {
47         Preconditions.checkState(!isFinished(), "%s: Transaction %s already finished", id, getIdentifier());
48     }
49
50     protected boolean isFinished() {
51         return finished;
52     }
53
54     protected void invokeBlocking(final String msg, final Function<NetconfBaseOps, ListenableFuture<DOMRpcResult>> op) throws NetconfDocumentedException {
55         try {
56             final DOMRpcResult compositeNodeRpcResult = op.apply(netOps).get(defaultRequestTimeoutMillis, TimeUnit.MILLISECONDS);
57             if(isSuccess(compositeNodeRpcResult) == false) {
58                 throw new NetconfDocumentedException(id + ": " + msg + " failed: " + compositeNodeRpcResult.getErrors(), NetconfDocumentedException.ErrorType.application,
59                         NetconfDocumentedException.ErrorTag.operation_failed, NetconfDocumentedException.ErrorSeverity.warning);
60             }
61         } catch (final InterruptedException e) {
62             Thread.currentThread().interrupt();
63             throw new RuntimeException(e);
64         } catch (final ExecutionException | TimeoutException e) {
65             throw new NetconfDocumentedException(id + ": " + msg + " failed: " + e.getMessage(), e, NetconfDocumentedException.ErrorType.application,
66                     NetconfDocumentedException.ErrorTag.operation_failed, NetconfDocumentedException.ErrorSeverity.warning);
67         }
68     }
69
70     @Override
71     public synchronized boolean cancel() {
72         if(isFinished()) {
73             return false;
74         }
75
76         finished = true;
77         cleanup();
78         return true;
79     }
80
81     protected abstract void init();
82
83     protected abstract void cleanup();
84
85     @Override
86     public Object getIdentifier() {
87         return this;
88     }
89
90     @Override
91     public synchronized void put(final LogicalDatastoreType store, final YangInstanceIdentifier path, final NormalizedNode<?, ?> data) {
92         checkEditable(store);
93
94         try {
95             editConfig(
96                     netOps.createEditConfigStrcture(Optional.<NormalizedNode<?, ?>>fromNullable(data), Optional.of(ModifyAction.REPLACE), path), Optional.of(ModifyAction.NONE));
97         } catch (final NetconfDocumentedException e) {
98             handleEditException(path, data, e, "putting");
99         }
100     }
101
102     protected abstract void handleEditException(YangInstanceIdentifier path, NormalizedNode<?, ?> data, NetconfDocumentedException e, String editType);
103     protected abstract void handleDeleteException(YangInstanceIdentifier path, NetconfDocumentedException e);
104
105     @Override
106     public synchronized void merge(final LogicalDatastoreType store, final YangInstanceIdentifier path, final NormalizedNode<?, ?> data) {
107         checkEditable(store);
108
109         try {
110             editConfig(
111                     netOps.createEditConfigStrcture(Optional.<NormalizedNode<?, ?>>fromNullable(data), Optional.<ModifyAction>absent(), path), Optional.<ModifyAction>absent());
112         } catch (final NetconfDocumentedException e) {
113             handleEditException(path, data, e, "merge");
114         }
115     }
116
117     @Override
118     public synchronized void delete(final LogicalDatastoreType store, final YangInstanceIdentifier path) {
119         checkEditable(store);
120
121         try {
122             editConfig(
123                     netOps.createEditConfigStrcture(Optional.<NormalizedNode<?, ?>>absent(), Optional.of(ModifyAction.DELETE), path), Optional.of(ModifyAction.NONE));
124         } catch (final NetconfDocumentedException e) {
125             handleDeleteException(path, e);
126         }
127     }
128
129     @Override
130     public final ListenableFuture<RpcResult<TransactionStatus>> commit() {
131         checkNotFinished();
132         finished = true;
133
134         return performCommit();
135     }
136
137     protected abstract ListenableFuture<RpcResult<TransactionStatus>> performCommit();
138
139     private void checkEditable(final LogicalDatastoreType store) {
140         checkNotFinished();
141         Preconditions.checkArgument(store == LogicalDatastoreType.CONFIGURATION, "Can edit only configuration data, not %s", store);
142     }
143
144     protected abstract void editConfig(DataContainerChild<?, ?> editStructure, Optional<ModifyAction> defaultOperation) throws NetconfDocumentedException;
145 }