fix import extra separations
[transportpce.git] / common / src / main / java / org / opendaylight / transportpce / common / device / DeviceTransactionManager.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 java.util.Optional;
12 import java.util.concurrent.Future;
13 import java.util.concurrent.TimeUnit;
14 import org.opendaylight.mdsal.binding.api.MountPoint;
15 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
16 import org.opendaylight.yangtools.yang.binding.DataObject;
17 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
18
19 /**
20  * <p>
21  *     Device transaction manager manages access to netconf devices. Only one transaction can be opened per device so
22  *     it IS IMPORTANT TO CLOSE TRANSACTION as soon as transactions is not needed.
23  * </p>
24  *
25  * <p>
26  *     Most important method is {@link DeviceTransactionManager#getDeviceTransaction(String)}. This method let's you
27  *     obtain {@link DeviceTransaction} on the device. {@link DeviceTransaction} provices methods to read/write data
28  *     from/to device.
29  * </p>
30  *
31  * <p>
32  *     Method
33  *  {@link DeviceTransactionManager#getDataFromDevice(String, LogicalDatastoreType, InstanceIdentifier, long, TimeUnit)}
34  *     is 'shortcut' to get data from device. It creates {@link DeviceTransaction}, gets data via it and then closes
35  *     the transaction.
36  * </p>
37  *
38  * <p>
39  *     Two timeouts are built in process to prevent locking device forever:
40  * </p>
41  * <ul>
42  *     <li>
43  *     First is from creation of {@link DeviceTransaction} to calling method to close it (commit or cancel). When using
44  *     {@link DeviceTransactionManager#getDeviceTransaction(String)} method then default timeout will be used. If there
45  *     is need to specify this timeout manually use
46  *     {@link DeviceTransactionManager#getDeviceTransaction(String, long, TimeUnit)} method. So if programmer will
47  *     forgot to close transaction or it will take too much time transaction will be cancelled automatically and device
48  *     will be unlocked.
49  *     </li>
50  *
51  *     <li>
52  *     Second timeout is from calling {@link DeviceTransaction#commit(long, TimeUnit)} until commit is completed on
53  *     device. Timeout can be specified directly using commit method. So in case commit will freeze somewhere on device
54  *     or it will take too much time device will be unlocked.
55  *     </li>
56  * </ul>
57  *
58  * <p>
59  *     If there is only need to read from device
60  *  {@link DeviceTransactionManager#getDataFromDevice(String, LogicalDatastoreType, InstanceIdentifier, long, TimeUnit)}
61  *     method can be used. It will automatically take care of {@link DeviceTransaction} and it will return data.
62  *     This method <b>SHOULD NOT BE USED TOGETHER WITH DEVICE TRANSACTION ON THE SAME DEVICE IN THE SAME TIME</b>.
63  *     In case that {@link DeviceTransaction} is created on device and before committing it
64  *  {@link DeviceTransactionManager#getDataFromDevice(String, LogicalDatastoreType, InstanceIdentifier, long, TimeUnit)}
65  *     method is called then get method will wait (will be blocking current thread) until device will be unlocked.
66  *     However device is locked by transaction previously created. So this will result in blocking current thread until
67  *     timeout for commit transaction will run out and cancel transaction. This can lead to incorrect execution of code.
68  * </p>
69  *
70  * <p>
71  * Bellow is simple example how to get {@link DeviceTransaction}, put some data to it and then commit it.
72  * </p>
73  * <pre>
74  * {@code
75  *     // get device transaction future from device transaction manager
76  *     Future<Optional<DeviceTransaction>> deviceTxFuture = deviceTransactionManager.getDeviceTransaction(deviceId);
77  *     DeviceTransaction deviceTx;
78  *     try {
79  *         // wait until device transaction is available
80  *         Optional<DeviceTransaction> deviceTxOpt = deviceTxFuture.get();
81  *
82  *         // check if device transaction is present
83  *         if (deviceTxOpt.isPresent()) {
84  *             deviceTx = deviceTxOpt.get();
85  *         } else {
86  *             throw new IllegalStateException("Device transaction for device " + deviceId + " was not found!");
87  *         }
88  *     } catch (InterruptedException | ExecutionException e) {
89  *         throw new IllegalStateException("Unable to obtain device transaction for device " + deviceId + "!", e);
90  *     }
91  *
92  *     // do some operations with transaction
93  *     deviceTx.put(LogicalDatastoreType.CONFIGURATION, someInstanceIdentifier, someData);
94  *     deviceTx.delete(LogicalDatastoreType.CONFIGURATION, someOtherInstanceIdentifier, someOtherData);
95  *
96  *     // commit transaction with 5 seconds timeout
97  *     FluentFuture<? extends @NonNull CommitInfo> commit = deviceTx.commit(5, TimeUnit.SECONDS);
98  *     try {
99  *         // wait until transaction is committed
100  *         commit.get();
101  *     } catch (InterruptedException | ExecutionException e) {
102  *         throw new IllegalStateException("Failed to post data to device " + deviceId + "!", e);
103  *     }
104  * }
105  * </pre>
106  */
107 public interface DeviceTransactionManager {
108
109     /**
110      * Gets Future containing {@link DeviceTransaction}. Since only one transaction can be opened per device future will
111      * return transaction when all previously committed transaction on device are closed. This method will use default
112      * timeout for commit transaction.
113      *
114      * @param deviceId device identifier on which will be transaction created.
115      * @return Future returning Optional of DeviceTransaction. Optional will be empty if device with specified ID
116      *         does not exists or transaction will fail to obtain.
117      */
118     Future<Optional<DeviceTransaction>> getDeviceTransaction(String deviceId);
119
120     /**
121     * Works same as {@link DeviceTransactionManager#getDeviceTransaction(String)} but with option to set custom timeout.
122      *
123      * @param deviceId device id on which will be transaction created.
124      * @param timeoutToSubmit timeout will start running when transaction is created. If transaction will not be
125      *                        closed (committed or cancelled) when times runs out it will be canceled (so device will
126      *                        be unlocked).
127      * @param timeUnit time units for timeout.
128      * @return Future returning Optional of DeviceTransaction. Optional will be empty if device with specified ID
129      *         does not exists or transaction will fail to obtain.
130      */
131     Future<Optional<DeviceTransaction>> getDeviceTransaction(String deviceId, long timeoutToSubmit, TimeUnit timeUnit);
132
133     // TODO make private in impl
134     Optional<MountPoint> getDeviceMountPoint(String deviceId);
135
136     /**
137      * Returns data from device from specified path. Creates new device transaction, gets data via it and closes
138      * transaction.
139      *
140      * <p>
141      * This method is blocking - it's waiting until it receives {@link DeviceTransaction} and then the data from device.
142      * </p>
143      *
144      * @param deviceId Device identifier from which will be data read.
145      * @param logicalDatastoreType Datastore type.
146      * @param path Path to data in device's datastore.
147      * @param timeout Timeout to automatically close transaction AND to get data from device (sets both timeouts to
148      *                same value).
149      * @param timeUnit Time unit of timeout.
150      * @param <T> Type of data to be returned.
151      * @return Optional of data obtained from device. If device does not contain data or device does not exists then
152      *         empty Optional will be returned.
153      */
154     <T extends DataObject> Optional<T> getDataFromDevice(String deviceId, LogicalDatastoreType logicalDatastoreType,
155             InstanceIdentifier<T> path, long timeout, TimeUnit timeUnit);
156
157     /**
158      * Checks if device with specified ID is mounted.
159      *
160      * @param deviceId Identifier of device to check.
161      * @return True if device is mounted.
162      */
163     boolean isDeviceMounted(String deviceId);
164 }