2 * Copyright © 2017 Orange, Inc. and others. All rights reserved.
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
9 package org.opendaylight.transportpce.common.device;
11 import com.google.common.base.Optional;
12 import com.google.common.util.concurrent.FluentFuture;
13 import com.google.common.util.concurrent.FutureCallback;
14 import com.google.common.util.concurrent.ListenableFuture;
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.controller.md.sal.binding.api.ReadWriteTransaction;
23 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
24 import org.opendaylight.mdsal.common.api.CommitInfo;
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;
32 * Represents read-write transaction on netconf device.
33 * This transaction can be obtained by {@link DeviceTransactionManager}.
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).
41 public class DeviceTransaction {
43 private static final Logger LOG = LoggerFactory.getLogger(DeviceTransaction.class);
45 private final ReadWriteTransaction rwTx;
46 private final CountDownLatch deviceLock;
47 private final ScheduledExecutorService scheduledExecutorService;
48 private final AtomicBoolean wasSubmittedOrCancelled = new AtomicBoolean(false);
50 DeviceTransaction(ReadWriteTransaction rwTx, CountDownLatch deviceLock) {
52 this.deviceLock = deviceLock;
53 this.scheduledExecutorService = Executors.newSingleThreadScheduledExecutor();
54 LOG.debug("Device transaction created. Lock: {}", deviceLock);
57 public <T extends DataObject> ListenableFuture<Optional<T>> read(LogicalDatastoreType store,
58 InstanceIdentifier<T> path) {
59 return rwTx.read(store, path);
62 public <T extends DataObject> void put(LogicalDatastoreType store, InstanceIdentifier<T> path, T data) {
63 rwTx.put(store, path, data);
66 public <T extends DataObject> void put(LogicalDatastoreType store, InstanceIdentifier<T> path, T data,
67 boolean createMissingParents) {
68 rwTx.put(store, path, data, createMissingParents);
71 public <T extends DataObject> void merge(LogicalDatastoreType store, InstanceIdentifier<T> path, T data) {
72 rwTx.merge(store, path, data);
75 public <T extends DataObject> void merge(LogicalDatastoreType store, InstanceIdentifier<T> path, T data,
76 boolean createMissingParents) {
77 rwTx.merge(store, path, data, createMissingParents);
80 public void delete(LogicalDatastoreType store, InstanceIdentifier<?> path) {
81 rwTx.delete(store, path);
85 * Cancels transaction and unlocks it.
86 * @return true if cancel was successful.
88 public boolean cancel() {
89 if (wasSubmittedOrCancelled.get()) {
90 LOG.warn("Transaction was already submitted or canceled!");
94 LOG.debug("Transaction cancelled. Lock: {}", deviceLock);
95 wasSubmittedOrCancelled.set(true);
101 * Submits data changed in transaction to device with defined timeout to commit. If time from timeout runs out then
102 * the commit will be interrupted and the device will be unlocked.
104 * @param timeout a timeout
105 * @param timeUnit a time unit
106 * @return FluentFuture which indicates when the commit is completed.
108 public FluentFuture<? extends @NonNull CommitInfo> commit(long timeout, TimeUnit timeUnit) {
109 if (wasSubmittedOrCancelled.get()) {
110 String msg = "Transaction was already submitted or canceled!";
112 return FluentFutures.immediateFailedFluentFuture(new IllegalStateException(msg));
115 LOG.debug("Transaction committed. Lock: {}", deviceLock);
116 wasSubmittedOrCancelled.set(true);
117 FluentFuture<? extends @NonNull CommitInfo> future =
118 rwTx.commit().withTimeout(timeout, timeUnit, scheduledExecutorService);
120 future.addCallback(new FutureCallback<CommitInfo>() {
122 public void onSuccess(@Nullable CommitInfo result) {
123 LOG.debug("Transaction with lock {} successfully committed:", deviceLock, result);
128 public void onFailure(Throwable throwable) {
129 LOG.error("Device transaction commit failed or submit took longer than {} {}! Unlocking device.",
130 timeout, timeUnit, throwable);
133 }, scheduledExecutorService);
138 * Returns state of transaction.
139 * @return true if transaction was closed; otherwise false
141 public AtomicBoolean wasSubmittedOrCancelled() {
142 return wasSubmittedOrCancelled;
145 private void afterClose() {
146 scheduledExecutorService.shutdown();
147 deviceLock.countDown();