blob: fa10d3374c90ecda3e3bdba02b5dcdcb7071b1ef [file] [log] [blame]
Andrea Campanellabc112a92017-06-26 19:06:43 +02001/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2017-present Open Networking Foundation
Andrea Campanellabc112a92017-06-26 19:06:43 +02003 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package org.onosproject.net.pi.impl;
18
Andrea Campanella48f99fa2017-07-13 19:06:21 +020019import com.google.common.annotations.Beta;
Andrea Campanellabc112a92017-06-26 19:06:43 +020020import com.google.common.collect.ImmutableSet;
Carmelo Casconeda60a612018-08-24 00:01:34 -070021import com.google.common.collect.Sets;
22import com.google.common.util.concurrent.Striped;
Andrea Campanellabc112a92017-06-26 19:06:43 +020023import org.onlab.util.ItemNotFoundException;
Carmelo Casconeda0b5592018-09-14 12:54:15 -070024import org.onlab.util.SharedExecutors;
Andrea Campanellabc112a92017-06-26 19:06:43 +020025import org.onosproject.net.DeviceId;
26import org.onosproject.net.config.ConfigFactory;
Andrea Campanellabc112a92017-06-26 19:06:43 +020027import org.onosproject.net.config.NetworkConfigRegistry;
28import org.onosproject.net.config.basics.BasicDeviceConfig;
29import org.onosproject.net.config.basics.SubjectFactories;
30import org.onosproject.net.driver.Behaviour;
31import org.onosproject.net.driver.DefaultDriver;
32import org.onosproject.net.driver.Driver;
33import org.onosproject.net.driver.DriverAdminService;
Carmelo Casconeda60a612018-08-24 00:01:34 -070034import org.onosproject.net.driver.DriverEvent;
35import org.onosproject.net.driver.DriverListener;
Andrea Campanellabc112a92017-06-26 19:06:43 +020036import org.onosproject.net.driver.DriverProvider;
Andrea Campanellabc112a92017-06-26 19:06:43 +020037import org.onosproject.net.pi.model.PiPipeconf;
38import org.onosproject.net.pi.model.PiPipeconfId;
Carmelo Cascone39c28ca2017-11-15 13:03:57 -080039import org.onosproject.net.pi.service.PiPipeconfConfig;
40import org.onosproject.net.pi.service.PiPipeconfMappingStore;
41import org.onosproject.net.pi.service.PiPipeconfService;
Ray Milkeyd84f89b2018-08-17 14:54:17 -070042import org.osgi.service.component.annotations.Activate;
43import org.osgi.service.component.annotations.Component;
44import org.osgi.service.component.annotations.Deactivate;
45import org.osgi.service.component.annotations.Reference;
46import org.osgi.service.component.annotations.ReferenceCardinality;
Andrea Campanellabc112a92017-06-26 19:06:43 +020047import org.slf4j.Logger;
48
49import java.util.HashMap;
50import java.util.Map;
Carmelo Casconeda60a612018-08-24 00:01:34 -070051import java.util.Objects;
Andrea Campanellabc112a92017-06-26 19:06:43 +020052import java.util.Optional;
53import java.util.Set;
Andrea Campanellabc112a92017-06-26 19:06:43 +020054import java.util.concurrent.ConcurrentHashMap;
Carmelo Cascone96beb6f2018-06-27 18:07:12 +020055import java.util.concurrent.ConcurrentMap;
Andrea Campanellabc112a92017-06-26 19:06:43 +020056import java.util.concurrent.ExecutorService;
57import java.util.concurrent.Executors;
Carmelo Casconeda0b5592018-09-14 12:54:15 -070058import java.util.concurrent.TimeUnit;
Carmelo Casconeda60a612018-08-24 00:01:34 -070059import java.util.concurrent.locks.Lock;
Andrea Campanellabc112a92017-06-26 19:06:43 +020060
Carmelo Cascone44daf562017-07-16 23:55:08 -040061import static java.lang.String.format;
Andrea Campanellabc112a92017-06-26 19:06:43 +020062import static org.onlab.util.Tools.groupedThreads;
63import static org.slf4j.LoggerFactory.getLogger;
64
65
66/**
67 * Implementation of the PiPipeconfService.
68 */
Ray Milkeyd84f89b2018-08-17 14:54:17 -070069@Component(immediate = true, service = PiPipeconfService.class)
Andrea Campanella48f99fa2017-07-13 19:06:21 +020070@Beta
71public class PiPipeconfManager implements PiPipeconfService {
Andrea Campanellabc112a92017-06-26 19:06:43 +020072
73 private final Logger log = getLogger(getClass());
74
Carmelo Cascone158b8c42018-07-04 19:42:37 +020075 private static final String MERGED_DRIVER_SEPARATOR = ":";
Andrea Campanellabc112a92017-06-26 19:06:43 +020076 private static final String CFG_SCHEME = "piPipeconf";
77
Carmelo Casconeda0b5592018-09-14 12:54:15 -070078 private static final int MISSING_DRIVER_WATCHDOG_INTERVAL = 5; // Seconds.
79
Ray Milkeyd84f89b2018-08-17 14:54:17 -070080 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Andrea Campanellabc112a92017-06-26 19:06:43 +020081 protected NetworkConfigRegistry cfgService;
82
Ray Milkeyd84f89b2018-08-17 14:54:17 -070083 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Andrea Campanellabc112a92017-06-26 19:06:43 +020084 protected DriverAdminService driverAdminService;
85
Ray Milkeyd84f89b2018-08-17 14:54:17 -070086 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Carmelo Cascone96beb6f2018-06-27 18:07:12 +020087 private PiPipeconfMappingStore pipeconfMappingStore;
Andrea Campanellaf9c409a2017-07-13 14:14:41 +020088
Carmelo Cascone96beb6f2018-06-27 18:07:12 +020089 // Registered pipeconf are replicated through the app subsystem and
90 // registered on app activated events. Hence, there should be no need of
91 // distributing this map.
92 protected ConcurrentMap<PiPipeconfId, PiPipeconf> pipeconfs = new ConcurrentHashMap<>();
Andrea Campanellabc112a92017-06-26 19:06:43 +020093
Carmelo Casconeda60a612018-08-24 00:01:34 -070094 private final DriverListener driverListener = new InternalDriverListener();
95 private final Set<String> missingMergedDrivers = Sets.newCopyOnWriteArraySet();
96 private final Striped<Lock> locks = Striped.lock(20);
97
Carmelo Cascone96beb6f2018-06-27 18:07:12 +020098 protected ExecutorService executor = Executors.newFixedThreadPool(
99 10, groupedThreads("onos/pipeconf-manager", "%d", log));
Andrea Campanellabc112a92017-06-26 19:06:43 +0200100
Carmelo Cascone96beb6f2018-06-27 18:07:12 +0200101 protected final ConfigFactory configFactory =
Andrea Campanellabc112a92017-06-26 19:06:43 +0200102 new ConfigFactory<DeviceId, PiPipeconfConfig>(
103 SubjectFactories.DEVICE_SUBJECT_FACTORY,
104 PiPipeconfConfig.class, CFG_SCHEME) {
105 @Override
106 public PiPipeconfConfig createConfig() {
107 return new PiPipeconfConfig();
108 }
109 };
110
Andrea Campanellabc112a92017-06-26 19:06:43 +0200111 @Activate
112 public void activate() {
Carmelo Cascone96beb6f2018-06-27 18:07:12 +0200113 cfgService.registerConfigFactory(configFactory);
Carmelo Cascone0761cd32018-08-29 19:22:50 -0700114 driverAdminService.addListener(driverListener);
Carmelo Casconeda60a612018-08-24 00:01:34 -0700115 checkMissingMergedDrivers();
Carmelo Casconeda0b5592018-09-14 12:54:15 -0700116 if (!missingMergedDrivers.isEmpty()) {
117 // Missing drivers should be created upon detecting registration
118 // events of a new pipeconf or a base driver. If, for any reason, we
119 // miss such event, here's a watchdog task.
120 SharedExecutors.getPoolThreadExecutor()
121 .execute(this::missingDriversWatchdogTask);
122 }
Andrea Campanellabc112a92017-06-26 19:06:43 +0200123 log.info("Started");
124 }
125
126
127 @Deactivate
128 public void deactivate() {
129 executor.shutdown();
Carmelo Cascone96beb6f2018-06-27 18:07:12 +0200130 cfgService.unregisterConfigFactory(configFactory);
Carmelo Cascone0761cd32018-08-29 19:22:50 -0700131 driverAdminService.removeListener(driverListener);
Carmelo Cascone96beb6f2018-06-27 18:07:12 +0200132 pipeconfs.clear();
Carmelo Casconeda60a612018-08-24 00:01:34 -0700133 missingMergedDrivers.clear();
Andrea Campanellabc112a92017-06-26 19:06:43 +0200134 cfgService = null;
135 driverAdminService = null;
Andrea Campanellabc112a92017-06-26 19:06:43 +0200136 log.info("Stopped");
137 }
138
139 @Override
140 public void register(PiPipeconf pipeconf) throws IllegalStateException {
Carmelo Cascone96beb6f2018-06-27 18:07:12 +0200141 if (pipeconfs.containsKey(pipeconf.id())) {
Carmelo Cascone44daf562017-07-16 23:55:08 -0400142 throw new IllegalStateException(format("Pipeconf %s is already registered", pipeconf.id()));
143 }
Carmelo Cascone96beb6f2018-06-27 18:07:12 +0200144 pipeconfs.put(pipeconf.id(), pipeconf);
Carmelo Cascone44daf562017-07-16 23:55:08 -0400145 log.info("New pipeconf registered: {}", pipeconf.id());
Carmelo Casconeda0b5592018-09-14 12:54:15 -0700146 executor.execute(() -> attemptMergeAll(pipeconf.id()));
Andrea Campanellabc112a92017-06-26 19:06:43 +0200147 }
148
149 @Override
Andrea Campanellaa9b3c9b2017-07-21 14:03:15 +0200150 public void remove(PiPipeconfId pipeconfId) throws IllegalStateException {
Carmelo Cascone96beb6f2018-06-27 18:07:12 +0200151 // TODO add mechanism to remove from device.
152 if (!pipeconfs.containsKey(pipeconfId)) {
Andrea Campanellaa9b3c9b2017-07-21 14:03:15 +0200153 throw new IllegalStateException(format("Pipeconf %s is not registered", pipeconfId));
154 }
Andrea Campanellaf9c409a2017-07-13 14:14:41 +0200155 // TODO remove the binding from the distributed Store when the lifecycle of a pipeconf is defined.
156 // pipeconfMappingStore.removeBindings(pipeconfId);
Carmelo Cascone96beb6f2018-06-27 18:07:12 +0200157 log.info("Removing pipeconf {}", pipeconfId);
158 pipeconfs.remove(pipeconfId);
Andrea Campanellaa9b3c9b2017-07-21 14:03:15 +0200159 }
160
161 @Override
Andrea Campanellabc112a92017-06-26 19:06:43 +0200162 public Iterable<PiPipeconf> getPipeconfs() {
Carmelo Cascone96beb6f2018-06-27 18:07:12 +0200163 return pipeconfs.values();
Andrea Campanellabc112a92017-06-26 19:06:43 +0200164 }
165
166 @Override
167 public Optional<PiPipeconf> getPipeconf(PiPipeconfId id) {
Carmelo Cascone96beb6f2018-06-27 18:07:12 +0200168 return Optional.ofNullable(pipeconfs.get(id));
Andrea Campanellabc112a92017-06-26 19:06:43 +0200169 }
170
171 @Override
Carmelo Cascone158b8c42018-07-04 19:42:37 +0200172 public void bindToDevice(PiPipeconfId pipeconfId, DeviceId deviceId) {
Carmelo Cascone0761cd32018-08-29 19:22:50 -0700173 PiPipeconfId existingPipeconfId = pipeconfMappingStore.getPipeconfId(deviceId);
174 if (existingPipeconfId != null && !existingPipeconfId.equals(pipeconfId)) {
175 log.error("Cannot set binding for {} to {} as one already exists ({})",
176 deviceId, pipeconfId, existingPipeconfId);
177 return;
178 }
Carmelo Cascone158b8c42018-07-04 19:42:37 +0200179 pipeconfMappingStore.createOrUpdateBinding(deviceId, pipeconfId);
180 }
181
182 @Override
Carmelo Cascone0761cd32018-08-29 19:22:50 -0700183 public String getMergedDriver(DeviceId deviceId, PiPipeconfId pipeconfId) {
Carmelo Cascone158b8c42018-07-04 19:42:37 +0200184 log.debug("Starting device driver merge of {} with {}...", deviceId, pipeconfId);
Carmelo Cascone96beb6f2018-06-27 18:07:12 +0200185 final BasicDeviceConfig basicDeviceConfig = cfgService.getConfig(
186 deviceId, BasicDeviceConfig.class);
Carmelo Cascone158b8c42018-07-04 19:42:37 +0200187 if (basicDeviceConfig == null) {
188 log.warn("Unable to get basic device config for {}, " +
Tian Jian855b1082018-10-23 16:22:47 +0800189 "aborting pipeconf driver merge", deviceId);
Carmelo Cascone158b8c42018-07-04 19:42:37 +0200190 return null;
Carmelo Cascone96beb6f2018-06-27 18:07:12 +0200191 }
Carmelo Cascone158b8c42018-07-04 19:42:37 +0200192 String baseDriverName = basicDeviceConfig.driver();
Carmelo Cascone9e4972c2018-08-30 00:29:16 -0700193 if (baseDriverName == null) {
194 log.warn("Missing driver from basic device config for {}, " +
195 "cannot produce merged driver", deviceId);
196 return null;
197 }
Carmelo Casconeda60a612018-08-24 00:01:34 -0700198 if (isMergedDriverName(baseDriverName)) {
Carmelo Cascone158b8c42018-07-04 19:42:37 +0200199 // The config already has driver name that is a merged one. We still
200 // need to make sure an instance of that merged driver is present in
201 // this node.
Carmelo Casconeda60a612018-08-24 00:01:34 -0700202 log.debug("Base driver of {} ({}) is a merged one",
203 deviceId, baseDriverName);
Carmelo Cascone158b8c42018-07-04 19:42:37 +0200204 baseDriverName = getBaseDriverNameFromMerged(baseDriverName);
Carmelo Cascone96beb6f2018-06-27 18:07:12 +0200205 }
Carmelo Cascone158b8c42018-07-04 19:42:37 +0200206
Carmelo Casconeda60a612018-08-24 00:01:34 -0700207 return doMergeDriver(baseDriverName, pipeconfId);
208 }
209
210 @Override
211 public Optional<PiPipeconfId> ofDevice(DeviceId deviceId) {
212 return Optional.ofNullable(pipeconfMappingStore.getPipeconfId(deviceId));
213 }
214
215 private String doMergeDriver(String baseDriverName, PiPipeconfId pipeconfId) {
Carmelo Cascone158b8c42018-07-04 19:42:37 +0200216 final String newDriverName = mergedDriverName(baseDriverName, pipeconfId);
Carmelo Casconeda60a612018-08-24 00:01:34 -0700217 // Serialize per newDriverName, avoid creating duplicates.
218 locks.get(newDriverName).lock();
Carmelo Cascone96beb6f2018-06-27 18:07:12 +0200219 try {
Carmelo Casconeda60a612018-08-24 00:01:34 -0700220 // If merged driver exists already we don't create a new one.
221 if (getDriver(newDriverName) != null) {
222 return newDriverName;
223 }
Carmelo Cascone96beb6f2018-06-27 18:07:12 +0200224 log.info("Creating merged driver {}...", newDriverName);
Carmelo Casconeda60a612018-08-24 00:01:34 -0700225 final Driver mergedDriver = buildMergedDriver(
226 pipeconfId, baseDriverName, newDriverName);
227 if (mergedDriver == null) {
228 // Error logged by buildMergedDriver
229 return null;
230 }
231 registerMergedDriver(mergedDriver);
232 if (missingMergedDrivers.remove(newDriverName)) {
233 log.info("There are still {} missing merged drivers",
234 missingMergedDrivers.size());
235 }
236 return newDriverName;
237 } finally {
238 locks.get(newDriverName).unlock();
Carmelo Cascone96beb6f2018-06-27 18:07:12 +0200239 }
Carmelo Cascone96beb6f2018-06-27 18:07:12 +0200240 }
241
Carmelo Cascone158b8c42018-07-04 19:42:37 +0200242 private String mergedDriverSuffix(PiPipeconfId pipeconfId) {
243 return MERGED_DRIVER_SEPARATOR + pipeconfId.id();
244 }
245
246 private String mergedDriverName(String baseDriverName, PiPipeconfId pipeconfId) {
247 return baseDriverName + mergedDriverSuffix(pipeconfId);
248 }
249
250 private String getBaseDriverNameFromMerged(String mergedDriverName) {
251 final String[] pieces = mergedDriverName.split(MERGED_DRIVER_SEPARATOR);
252 if (pieces.length != 2) {
Carmelo Cascone158b8c42018-07-04 19:42:37 +0200253 return null;
254 }
255 return pieces[0];
256 }
257
Carmelo Casconeda60a612018-08-24 00:01:34 -0700258 private PiPipeconfId getPipeconfIdFromMerged(String mergedDriverName) {
259 final String[] pieces = mergedDriverName.split(MERGED_DRIVER_SEPARATOR);
260 if (pieces.length != 2) {
261 return null;
262 }
263 return new PiPipeconfId(pieces[1]);
264 }
265
266 private boolean isMergedDriverName(String driverName) {
267 final String[] pieces = driverName.split(MERGED_DRIVER_SEPARATOR);
268 return pieces.length == 2;
269 }
270
Carmelo Cascone158b8c42018-07-04 19:42:37 +0200271 private Driver buildMergedDriver(PiPipeconfId pipeconfId, String baseDriverName,
272 String newDriverName) {
Carmelo Casconeda60a612018-08-24 00:01:34 -0700273 final Driver baseDriver = getDriver(baseDriverName);
274 if (baseDriver == null) {
Carmelo Cascone158b8c42018-07-04 19:42:37 +0200275 log.error("Base driver {} not found, cannot build a merged one",
276 baseDriverName);
277 return null;
278 }
279
280 final PiPipeconf pipeconf = pipeconfs.get(pipeconfId);
281 if (pipeconf == null) {
282 log.error("Pipeconf {} is not registered, cannot build a merged driver",
283 pipeconfId);
284 return null;
285 }
286
Carmelo Cascone96beb6f2018-06-27 18:07:12 +0200287 // extract the behaviours from the pipipeconf.
288 final Map<Class<? extends Behaviour>, Class<? extends Behaviour>> behaviours =
289 new HashMap<>();
290 pipeconf.behaviours().forEach(
291 b -> behaviours.put(b, pipeconf.implementation(b).get()));
292 final Driver piPipeconfDriver = new DefaultDriver(
293 newDriverName, baseDriver.parents(),
294 baseDriver.manufacturer(), baseDriver.hwVersion(),
295 baseDriver.swVersion(), behaviours, new HashMap<>());
296 // take the base driver created with the behaviours of the PiPeconf and
297 // merge it with the base driver that was assigned to the device
Carmelo Cascone158b8c42018-07-04 19:42:37 +0200298 return piPipeconfDriver.merge(baseDriver);
299 }
300
301 private void registerMergedDriver(Driver driver) {
302 final DriverProvider provider = new InternalDriverProvider(driver);
303 if (driverAdminService.getProviders().contains(provider)) {
304 // A provider for this driver already exist.
305 return;
306 }
Carmelo Cascone96beb6f2018-06-27 18:07:12 +0200307 driverAdminService.registerProvider(provider);
308 }
309
Carmelo Casconeda60a612018-08-24 00:01:34 -0700310 private Driver getDriver(String name) {
311 try {
Carmelo Cascone0761cd32018-08-29 19:22:50 -0700312 return driverAdminService.getDriver(name);
Carmelo Casconeda60a612018-08-24 00:01:34 -0700313 } catch (ItemNotFoundException e) {
314 return null;
315 }
316 }
317
Carmelo Casconeda0b5592018-09-14 12:54:15 -0700318 private boolean driverExists(String name) {
319 return getDriver(name) != null;
Carmelo Casconeda60a612018-08-24 00:01:34 -0700320 }
321
Carmelo Casconeda0b5592018-09-14 12:54:15 -0700322 private void checkMissingMergedDriver(DeviceId deviceId) {
323 final PiPipeconfId pipeconfId = pipeconfMappingStore.getPipeconfId(deviceId);
324 final BasicDeviceConfig cfg = cfgService.getConfig(deviceId, BasicDeviceConfig.class);
325
326 if (pipeconfId == null) {
327 // No pipeconf associated.
328 return;
329 }
330
331 if (cfg == null || cfg.driver() == null) {
332 log.warn("Missing basic device config or driver key in netcfg for " +
333 "{}, which is odd since it has a " +
334 "pipeconf associated ({})",
335 deviceId, pipeconfId);
336 return;
337 }
338
339 final String baseDriverName = cfg.driver();
340 final String mergedDriverName = mergedDriverName(baseDriverName, pipeconfId);
341
342 if (driverExists(mergedDriverName) ||
343 missingMergedDrivers.contains(mergedDriverName)) {
344 // Not missing, or already aware of it missing.
345 return;
346 }
347
348 log.info("Detected missing merged driver: {}", mergedDriverName);
349 missingMergedDrivers.add(mergedDriverName);
350 // Attempt building the driver now if all pieces are present.
351 // If not, either a driver or pipeconf event will re-trigger
352 // the process.
353 attemptDriverMerge(mergedDriverName);
354 }
355
356 private void attemptDriverMerge(String mergedDriverName) {
357 final String baseDriverName = getBaseDriverNameFromMerged(mergedDriverName);
358 final PiPipeconfId pipeconfId = getPipeconfIdFromMerged(mergedDriverName);
359 if (driverExists(baseDriverName) && pipeconfs.containsKey(pipeconfId)) {
360 doMergeDriver(baseDriverName, pipeconfId);
361 }
362 }
363
364 private void missingDriversWatchdogTask() {
365 while (true) {
366 // Most probably all missing drivers will be created before the
367 // watchdog interval, so wait before starting...
368 try {
369 TimeUnit.SECONDS.sleep(MISSING_DRIVER_WATCHDOG_INTERVAL);
370 } catch (InterruptedException e) {
371 log.warn("Interrupted! There are still {} missing merged drivers",
372 missingMergedDrivers.size());
373 }
374 if (missingMergedDrivers.isEmpty()) {
375 log.info("There are no more missing merged drivers!");
376 return;
377 }
378 log.info("Detected {} missing merged drivers, attempt merge...",
379 missingMergedDrivers.size());
380 missingMergedDrivers.forEach(this::attemptDriverMerge);
381 }
382 }
383
384 private void checkMissingMergedDrivers() {
385 cfgService.getSubjects(DeviceId.class, BasicDeviceConfig.class)
386 .forEach(this::checkMissingMergedDriver);
387 }
388
389 private void attemptMergeAll(String baseDriverName) {
Carmelo Casconeda60a612018-08-24 00:01:34 -0700390 missingMergedDrivers.stream()
Carmelo Casconeda0b5592018-09-14 12:54:15 -0700391 .filter(missingDriver -> {
392 // Filter missing merged drivers using this base driver.
393 final String xx = getBaseDriverNameFromMerged(missingDriver);
Carmelo Casconeda60a612018-08-24 00:01:34 -0700394 return xx != null && xx.equals(baseDriverName);
395 })
Carmelo Casconeda0b5592018-09-14 12:54:15 -0700396 .forEach(this::attemptDriverMerge);
Carmelo Casconeda60a612018-08-24 00:01:34 -0700397 }
398
Carmelo Casconeda0b5592018-09-14 12:54:15 -0700399 private void attemptMergeAll(PiPipeconfId pipeconfId) {
Carmelo Casconeda60a612018-08-24 00:01:34 -0700400 missingMergedDrivers.stream()
Carmelo Casconeda0b5592018-09-14 12:54:15 -0700401 .filter(missingDriver -> {
402 // Filter missing merged drivers using this pipeconf.
403 final PiPipeconfId xx = getPipeconfIdFromMerged(missingDriver);
Carmelo Casconeda60a612018-08-24 00:01:34 -0700404 return xx != null && xx.equals(pipeconfId);
405 })
Carmelo Casconeda0b5592018-09-14 12:54:15 -0700406 .forEach(this::attemptDriverMerge);
Carmelo Casconeda60a612018-08-24 00:01:34 -0700407 }
408
409 private class InternalDriverListener implements DriverListener {
410
411 @Override
412 public void event(DriverEvent event) {
Carmelo Casconeda0b5592018-09-14 12:54:15 -0700413 executor.execute(() -> attemptMergeAll(event.subject().name()));
Carmelo Casconeda60a612018-08-24 00:01:34 -0700414 }
415
416 @Override
417 public boolean isRelevant(DriverEvent event) {
418 return event.type() == DriverEvent.Type.DRIVER_ENHANCED;
419 }
420 }
421
Carmelo Cascone158b8c42018-07-04 19:42:37 +0200422 /**
423 * Internal driver provider used to register merged pipeconf drivers in the
424 * core.
425 */
426 private class InternalDriverProvider implements DriverProvider {
Andrea Campanellabc112a92017-06-26 19:06:43 +0200427
428 Driver driver;
429
Carmelo Cascone158b8c42018-07-04 19:42:37 +0200430 InternalDriverProvider(Driver driver) {
Andrea Campanellabc112a92017-06-26 19:06:43 +0200431 this.driver = driver;
432 }
433
434 @Override
435 public Set<Driver> getDrivers() {
436 return ImmutableSet.of(driver);
437 }
Carmelo Cascone158b8c42018-07-04 19:42:37 +0200438
439 @Override
440 public boolean equals(Object o) {
441 if (this == o) {
442 return true;
443 }
444 if (o == null || getClass() != o.getClass()) {
445 return false;
446 }
447 InternalDriverProvider that = (InternalDriverProvider) o;
Carmelo Casconeda60a612018-08-24 00:01:34 -0700448 return Objects.equals(driver.name(), that.driver.name());
Carmelo Cascone158b8c42018-07-04 19:42:37 +0200449 }
450
451 @Override
452 public int hashCode() {
453 return Objects.hashCode(driver.name());
454 }
Andrea Campanellabc112a92017-06-26 19:06:43 +0200455 }
Andrea Campanellabc112a92017-06-26 19:06:43 +0200456}