Ignore Junit failing after Magnesium Bump
[transportpce.git] / common / src / main / java / org / opendaylight / transportpce / common / device / DeviceTransaction.java
1 /*
2  * Copyright © 2017 Orange, 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.transportpce.common.device;
10
11 import com.google.common.util.concurrent.FluentFuture;
12 import com.google.common.util.concurrent.FutureCallback;
13 import com.google.common.util.concurrent.ListenableFuture;
14 import java.util.Optional;
15 import java.util.concurrent.CountDownLatch;
16 import java.util.concurrent.Executors;
17 import java.util.concurrent.ScheduledExecutorService;
18 import java.util.concurrent.TimeUnit;
19 import java.util.concurrent.atomic.AtomicBoolean;
20 import javax.annotation.Nullable;
21 import org.eclipse.jdt.annotation.NonNull;
22 import org.opendaylight.mdsal.binding.api.ReadWriteTransaction;
23 import org.opendaylight.mdsal.common.api.CommitInfo;
24 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
25 import org.opendaylight.yangtools.util.concurrent.FluentFutures;
26 import org.opendaylight.yangtools.yang.binding.DataObject;
27 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
28 import org.slf4j.Logger;
29 import org.slf4j.LoggerFactory;
30
31 /**
32  * Represents read-write transaction on netconf device.
33  * This transaction can be obtained by {@link DeviceTransactionManager}.
34  *
35  * <p>
36  * WARNING: Only one transaction can be opened at the same time on device!
37  * It's important to close (cancel/submit) transaction when work is done with it
38  * (so others can access the device).
39  * </p>
40  */
41 public class DeviceTransaction {
42
43     private static final Logger LOG = LoggerFactory.getLogger(DeviceTransaction.class);
44
45     private final ReadWriteTransaction rwTx;
46     private final CountDownLatch deviceLock;
47     private final ScheduledExecutorService scheduledExecutorService;
48     private final AtomicBoolean wasSubmittedOrCancelled = new AtomicBoolean(false);
49
50     DeviceTransaction(ReadWriteTransaction rwTx, CountDownLatch deviceLock) {
51         this.rwTx = rwTx;
52         this.deviceLock = deviceLock;
53         this.scheduledExecutorService = Executors.newSingleThreadScheduledExecutor();
54         LOG.debug("Device transaction created. Lock: {}", deviceLock);
55     }
56
57     public <T extends DataObject> ListenableFuture<Optional<T>> read(LogicalDatastoreType store,
58             InstanceIdentifier<T> path) {
59         return rwTx.read(store, path);
60     }
61
62     public <T extends DataObject> void put(LogicalDatastoreType store, InstanceIdentifier<T> path, T data) {
63         rwTx.put(store, path, data);
64     }
65
66     @Deprecated
67     public <T extends DataObject> void put(LogicalDatastoreType store, InstanceIdentifier<T> path, T data,
68             boolean createMissingParents) {
69         rwTx.put(store, path, data, createMissingParents);
70     }
71
72     public <T extends DataObject> void merge(LogicalDatastoreType store, InstanceIdentifier<T> path, T data) {
73         rwTx.merge(store, path, data);
74     }
75
76     @Deprecated
77     public <T extends DataObject> void merge(LogicalDatastoreType store, InstanceIdentifier<T> path, T data,
78             boolean createMissingParents) {
79         rwTx.merge(store, path, data, createMissingParents);
80     }
81
82     public void delete(LogicalDatastoreType store, InstanceIdentifier<?> path) {
83         rwTx.delete(store, path);
84     }
85
86     /**
87      * Cancels transaction and unlocks it.
88      * @return true if cancel was successful.
89      */
90     public boolean cancel() {
91         if (wasSubmittedOrCancelled.get()) {
92             LOG.warn("Transaction was already submitted or canceled!");
93             return false;
94         }
95
96         LOG.debug("Transaction cancelled. Lock: {}", deviceLock);
97         wasSubmittedOrCancelled.set(true);
98         afterClose();
99         return rwTx.cancel();
100     }
101
102     /**
103      * Submits data changed in transaction to device with defined timeout to commit. If time from timeout runs out then
104      * the commit will be interrupted and the device will be unlocked.
105      *
106      * @param timeout a timeout
107      * @param timeUnit a time unit
108      * @return FluentFuture which indicates when the commit is completed.
109      */
110     public FluentFuture<? extends @NonNull CommitInfo> commit(long timeout, TimeUnit timeUnit) {
111         if (wasSubmittedOrCancelled.get()) {
112             String msg = "Transaction was already submitted or canceled!";
113             LOG.error(msg);
114             return FluentFutures.immediateFailedFluentFuture(new IllegalStateException(msg));
115         }
116
117         LOG.debug("Transaction committed. Lock: {}", deviceLock);
118         wasSubmittedOrCancelled.set(true);
119         FluentFuture<? extends @NonNull CommitInfo> future =
120                 rwTx.commit().withTimeout(timeout, timeUnit, scheduledExecutorService);
121
122         future.addCallback(new FutureCallback<CommitInfo>() {
123             @Override
124             public void onSuccess(@Nullable CommitInfo result) {
125                 LOG.debug("Transaction with lock {} successfully committed: {}", deviceLock, result);
126                 afterClose();
127             }
128
129             @Override
130             public void onFailure(Throwable throwable) {
131                 LOG.error("Device transaction commit failed or submit took longer than {} {}! Unlocking device.",
132                     timeout, timeUnit, throwable);
133                 afterClose();
134             }
135         }, scheduledExecutorService);
136         return future;
137     }
138
139     /**
140      * Returns state of transaction.
141      * @return true if transaction was closed; otherwise false
142      */
143     public AtomicBoolean wasSubmittedOrCancelled() {
144         return wasSubmittedOrCancelled;
145     }
146
147     private void afterClose() {
148         scheduledExecutorService.shutdown();
149         deviceLock.countDown();
150     }
151 }