Migrate users of Optional.get()
[ovsdb.git] / hwvtepsouthbound / hwvtepsouthbound-impl / src / main / java / org / opendaylight / ovsdb / hwvtepsouthbound / transact / DependentJob.java
1 /*
2  * Copyright (c) 2016, 2017 Ericsson India Global Services Pvt Ltd. 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.ovsdb.hwvtepsouthbound.transact;
10
11 import java.util.List;
12 import java.util.Map;
13 import java.util.Map.Entry;
14 import java.util.Optional;
15 import java.util.function.BiPredicate;
16 import java.util.function.Predicate;
17 import org.opendaylight.ovsdb.hwvtepsouthbound.HwvtepDeviceInfo;
18 import org.opendaylight.ovsdb.hwvtepsouthbound.HwvtepSouthboundConstants;
19 import org.opendaylight.ovsdb.lib.operations.TransactionBuilder;
20 import org.opendaylight.ovsdb.lib.schema.typed.TypedBaseTable;
21 import org.opendaylight.yangtools.yang.binding.DataObject;
22 import org.opendaylight.yangtools.yang.binding.Identifiable;
23 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
24 import org.slf4j.Logger;
25 import org.slf4j.LoggerFactory;
26
27 public abstract class DependentJob<T extends Identifiable> {
28
29     private static final Logger LOG = LoggerFactory.getLogger(DependentJob.class);
30
31     private static final Predicate<HwvtepDeviceInfo.DeviceData> DATA_INTRANSIT
32             = (controllerData) -> controllerData != null && controllerData.isInTransitState();
33
34     private static final Predicate<HwvtepDeviceInfo.DeviceData> DATA_INTRANSIT_EXPIRED
35             = (controllerData) -> controllerData != null && controllerData.isInTransitState()
36             && controllerData.isIntransitTimeExpired();
37
38     //expecting the device to create the data
39     private static final BiPredicate<HwvtepDeviceInfo.DeviceData, Optional<TypedBaseTable>> INTRANSIT_DATA_CREATED
40             = (controllerData, deviceData) -> controllerData.getUuid() == null && deviceData.isPresent();
41
42     private static final BiPredicate<HwvtepDeviceInfo.DeviceData, Optional<TypedBaseTable>> INTRANSIT_DATA_NOT_CREATED
43             = (controllerData, deviceData) -> controllerData.getUuid() == null && !deviceData.isPresent();
44
45     //expecting the device to delete the data
46     private static final BiPredicate<HwvtepDeviceInfo.DeviceData, Optional<TypedBaseTable>> INTRANSIT_DATA_DELETED
47             = (controllerData, deviceData) -> controllerData.getUuid() != null && !deviceData.isPresent();
48
49     private static final BiPredicate<HwvtepDeviceInfo.DeviceData, Optional<TypedBaseTable>> INTRANSIT_DATA_NOT_DELETED
50             = (controllerData, deviceData) -> controllerData.getUuid() != null && deviceData.isPresent();
51
52     private final long expiryTime;
53     private final InstanceIdentifier key;
54     private final T data;
55     private final Map<Class<? extends DataObject>, List<InstanceIdentifier>> dependencies;
56     private final long transactionId;
57
58     DependentJob(InstanceIdentifier key,
59                            T data, Map<Class<? extends DataObject>, List<InstanceIdentifier>> dependencies,
60                  long transactionId) {
61         this.expiryTime = System.currentTimeMillis() + HwvtepSouthboundConstants.WAITING_JOB_EXPIRY_TIME_MILLIS;
62         this.key = key;
63         this.data = data;
64         this.dependencies = dependencies;
65         this.transactionId = transactionId;
66     }
67
68     /**
69      * This call back method gets called when all its dependencies are resolved.
70      *
71      * @param operationalState   new current operational state
72      * @param transactionBuilder transaction builder to create device transaction
73      */
74     protected abstract void onDependencyResolved(HwvtepOperationalState operationalState,
75                                                  TransactionBuilder transactionBuilder);
76
77     /**
78      * This method is to check if all the given dependency of this job or not.
79      *
80      * @param deviceInfo   The device info of tis job
81      * @param cls          dependency type to be checked for
82      * @param iid          instance identifier to be checked for
83      * @return true if the dependency is met
84      */
85     protected abstract boolean isDependencyMet(HwvtepDeviceInfo deviceInfo, Class<? extends DataObject> cls,
86                                                InstanceIdentifier iid);
87
88     boolean isExpired(long currentTime) {
89         return currentTime > expiryTime;
90     }
91
92     /**
93      * This method checks if all the dependencies of this job or met or not.
94      *
95      * @param deviceInfo The device info of this job
96      * @return true if all the dependencies are met
97      */
98     boolean areDependenciesMet(HwvtepDeviceInfo deviceInfo) {
99         for (Entry<Class<? extends DataObject>, List<InstanceIdentifier>> entry : dependencies.entrySet()) {
100             Class<? extends DataObject> cls = entry.getKey();
101             for (InstanceIdentifier<?> iid : entry.getValue()) {
102                 if (!isDependencyMet(deviceInfo, cls, iid)) {
103                     return false;
104                 }
105             }
106         }
107         return true;
108     }
109
110     public InstanceIdentifier getKey() {
111         return key;
112     }
113
114     public long getTransactionId() {
115         return transactionId;
116     }
117
118     public Map<Class<? extends DataObject>, List<InstanceIdentifier>> getDependencies() {
119         return dependencies;
120     }
121
122     public T getData() {
123         return data;
124     }
125
126     public boolean isConfigWaitingJob() {
127         return true;
128     }
129
130     public void onFailure() {
131     }
132
133     public void onSuccess() {
134     }
135
136     public abstract static class ConfigWaitingJob<T extends Identifiable> extends DependentJob<T> {
137
138         public ConfigWaitingJob(InstanceIdentifier key, T data,
139                 Map<Class<? extends DataObject>, List<InstanceIdentifier>> dependencies) {
140             super(key, data, dependencies, 0);
141         }
142
143         @Override
144         protected boolean isDependencyMet(HwvtepDeviceInfo deviceInfo, Class cls, InstanceIdentifier iid) {
145             return deviceInfo.isConfigDataAvailable(cls, iid);
146         }
147
148         public boolean isConfigWaitingJob() {
149             return true;
150         }
151     }
152
153     public abstract static class OpWaitingJob<T extends Identifiable> extends DependentJob<T> {
154
155         public OpWaitingJob(InstanceIdentifier key, T data,
156                 Map<Class<? extends DataObject>, List<InstanceIdentifier>> dependencies,
157                             long transactionId) {
158             super(key, data, dependencies, transactionId);
159         }
160
161         @Override
162         protected boolean isDependencyMet(HwvtepDeviceInfo deviceInfo, Class cls, InstanceIdentifier iid) {
163             boolean depenencyMet = true;
164             HwvtepDeviceInfo.DeviceData controllerData = deviceInfo.getDeviceOperData(cls, iid);
165
166             if (DATA_INTRANSIT_EXPIRED.test(controllerData)) {
167                 LOG.info("Intransit state expired for key: {} --- dependency {}", iid, getKey());
168
169                 //either the device acted on the selected iid/uuid and sent the updated event or it did not
170                 //here we are querying the device directly to get the latest status on the iid
171                 Optional<TypedBaseTable> latestDeviceStatus = deviceInfo.getConnectionInstance()
172                         .getHwvtepTableReader().getHwvtepTableEntryUUID(cls, iid, controllerData.getUuid());
173
174                 TypedBaseTable latestDeviceData = latestDeviceStatus.orElse(null);
175
176                 if (INTRANSIT_DATA_CREATED.test(controllerData, latestDeviceStatus)) {
177                     LOG.info("Intransit expired key is actually created but update is missed/delayed {}", iid);
178                     deviceInfo.updateDeviceOperData(cls, iid, latestDeviceData.getUuid(), latestDeviceData);
179
180                 } else if (INTRANSIT_DATA_NOT_CREATED.test(controllerData, latestDeviceStatus)) {
181                     LOG.info("Intransit expired key is actually not created but update is missed/delayed {}", iid);
182                     deviceInfo.clearDeviceOperData(cls, iid);
183
184                 } else if (INTRANSIT_DATA_DELETED.test(controllerData, latestDeviceStatus)) {
185                     //also deleted from device
186                     LOG.info("Intransit expired key is actually deleted but update is missed/delayed {}", iid);
187                     deviceInfo.clearDeviceOperData(cls, iid);
188
189                 } else if (INTRANSIT_DATA_NOT_DELETED.test(controllerData, latestDeviceStatus)) {
190                     //not deleted from device we will reuse existing uuid
191                     LOG.info("Intransit expired key is actually not deleted but update is missed/delayed {}", iid);
192                     deviceInfo.updateDeviceOperData(cls, iid, latestDeviceData.getUuid(), latestDeviceData);
193                 }
194             } else if (DATA_INTRANSIT.test(controllerData)) {
195                 //device status is still in transit
196                 depenencyMet = false;
197             }
198             return depenencyMet;
199         }
200
201         @Override
202         public boolean isConfigWaitingJob() {
203             return false;
204         }
205     }
206 }