blob: 965309185c79a60cdff160920202114a7c7505cb [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;
Andrea Campanellabc112a92017-06-26 19:06:43 +020026import org.onosproject.net.config.NetworkConfigRegistry;
27import org.onosproject.net.config.basics.BasicDeviceConfig;
Andrea Campanellabc112a92017-06-26 19:06:43 +020028import org.onosproject.net.driver.Behaviour;
29import org.onosproject.net.driver.DefaultDriver;
30import org.onosproject.net.driver.Driver;
31import org.onosproject.net.driver.DriverAdminService;
Carmelo Casconeda60a612018-08-24 00:01:34 -070032import org.onosproject.net.driver.DriverEvent;
33import org.onosproject.net.driver.DriverListener;
Andrea Campanellabc112a92017-06-26 19:06:43 +020034import org.onosproject.net.driver.DriverProvider;
Andrea Campanellabc112a92017-06-26 19:06:43 +020035import org.onosproject.net.pi.model.PiPipeconf;
36import org.onosproject.net.pi.model.PiPipeconfId;
Carmelo Cascone39c28ca2017-11-15 13:03:57 -080037import org.onosproject.net.pi.service.PiPipeconfMappingStore;
38import org.onosproject.net.pi.service.PiPipeconfService;
Ray Milkeyd84f89b2018-08-17 14:54:17 -070039import org.osgi.service.component.annotations.Activate;
40import org.osgi.service.component.annotations.Component;
41import org.osgi.service.component.annotations.Deactivate;
42import org.osgi.service.component.annotations.Reference;
43import org.osgi.service.component.annotations.ReferenceCardinality;
Andrea Campanellabc112a92017-06-26 19:06:43 +020044import org.slf4j.Logger;
45
46import java.util.HashMap;
47import java.util.Map;
Carmelo Casconeda60a612018-08-24 00:01:34 -070048import java.util.Objects;
Andrea Campanellabc112a92017-06-26 19:06:43 +020049import java.util.Optional;
50import java.util.Set;
Andrea Campanellabc112a92017-06-26 19:06:43 +020051import java.util.concurrent.ConcurrentHashMap;
Carmelo Cascone96beb6f2018-06-27 18:07:12 +020052import java.util.concurrent.ConcurrentMap;
Andrea Campanellabc112a92017-06-26 19:06:43 +020053import java.util.concurrent.ExecutorService;
54import java.util.concurrent.Executors;
Carmelo Casconeda0b5592018-09-14 12:54:15 -070055import java.util.concurrent.TimeUnit;
Carmelo Casconeda60a612018-08-24 00:01:34 -070056import java.util.concurrent.locks.Lock;
Andrea Campanellabc112a92017-06-26 19:06:43 +020057
Carmelo Cascone44daf562017-07-16 23:55:08 -040058import static java.lang.String.format;
Andrea Campanellabc112a92017-06-26 19:06:43 +020059import static org.onlab.util.Tools.groupedThreads;
60import static org.slf4j.LoggerFactory.getLogger;
61
62
63/**
64 * Implementation of the PiPipeconfService.
65 */
Ray Milkeyd84f89b2018-08-17 14:54:17 -070066@Component(immediate = true, service = PiPipeconfService.class)
Andrea Campanella48f99fa2017-07-13 19:06:21 +020067@Beta
68public class PiPipeconfManager implements PiPipeconfService {
Andrea Campanellabc112a92017-06-26 19:06:43 +020069
70 private final Logger log = getLogger(getClass());
71
Carmelo Cascone158b8c42018-07-04 19:42:37 +020072 private static final String MERGED_DRIVER_SEPARATOR = ":";
Andrea Campanellabc112a92017-06-26 19:06:43 +020073
Carmelo Casconeda0b5592018-09-14 12:54:15 -070074 private static final int MISSING_DRIVER_WATCHDOG_INTERVAL = 5; // Seconds.
75
Ray Milkeyd84f89b2018-08-17 14:54:17 -070076 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Andrea Campanellabc112a92017-06-26 19:06:43 +020077 protected NetworkConfigRegistry cfgService;
78
Ray Milkeyd84f89b2018-08-17 14:54:17 -070079 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Andrea Campanellabc112a92017-06-26 19:06:43 +020080 protected DriverAdminService driverAdminService;
81
Ray Milkeyd84f89b2018-08-17 14:54:17 -070082 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Carmelo Cascone96beb6f2018-06-27 18:07:12 +020083 private PiPipeconfMappingStore pipeconfMappingStore;
Andrea Campanellaf9c409a2017-07-13 14:14:41 +020084
Carmelo Cascone96beb6f2018-06-27 18:07:12 +020085 // Registered pipeconf are replicated through the app subsystem and
86 // registered on app activated events. Hence, there should be no need of
87 // distributing this map.
88 protected ConcurrentMap<PiPipeconfId, PiPipeconf> pipeconfs = new ConcurrentHashMap<>();
Andrea Campanellabc112a92017-06-26 19:06:43 +020089
Carmelo Casconeda60a612018-08-24 00:01:34 -070090 private final DriverListener driverListener = new InternalDriverListener();
91 private final Set<String> missingMergedDrivers = Sets.newCopyOnWriteArraySet();
92 private final Striped<Lock> locks = Striped.lock(20);
93
Carmelo Cascone96beb6f2018-06-27 18:07:12 +020094 protected ExecutorService executor = Executors.newFixedThreadPool(
95 10, groupedThreads("onos/pipeconf-manager", "%d", log));
Andrea Campanellabc112a92017-06-26 19:06:43 +020096
Andrea Campanellabc112a92017-06-26 19:06:43 +020097 @Activate
98 public void activate() {
Carmelo Cascone0761cd32018-08-29 19:22:50 -070099 driverAdminService.addListener(driverListener);
Carmelo Casconeda60a612018-08-24 00:01:34 -0700100 checkMissingMergedDrivers();
Carmelo Casconeda0b5592018-09-14 12:54:15 -0700101 if (!missingMergedDrivers.isEmpty()) {
102 // Missing drivers should be created upon detecting registration
103 // events of a new pipeconf or a base driver. If, for any reason, we
104 // miss such event, here's a watchdog task.
105 SharedExecutors.getPoolThreadExecutor()
106 .execute(this::missingDriversWatchdogTask);
107 }
Andrea Campanellabc112a92017-06-26 19:06:43 +0200108 log.info("Started");
109 }
110
111
112 @Deactivate
113 public void deactivate() {
114 executor.shutdown();
Carmelo Cascone0761cd32018-08-29 19:22:50 -0700115 driverAdminService.removeListener(driverListener);
Carmelo Cascone96beb6f2018-06-27 18:07:12 +0200116 pipeconfs.clear();
Carmelo Casconeda60a612018-08-24 00:01:34 -0700117 missingMergedDrivers.clear();
Andrea Campanellabc112a92017-06-26 19:06:43 +0200118 cfgService = null;
119 driverAdminService = null;
Andrea Campanellabc112a92017-06-26 19:06:43 +0200120 log.info("Stopped");
121 }
122
123 @Override
124 public void register(PiPipeconf pipeconf) throws IllegalStateException {
Carmelo Cascone96beb6f2018-06-27 18:07:12 +0200125 if (pipeconfs.containsKey(pipeconf.id())) {
Carmelo Cascone44daf562017-07-16 23:55:08 -0400126 throw new IllegalStateException(format("Pipeconf %s is already registered", pipeconf.id()));
127 }
Carmelo Cascone96beb6f2018-06-27 18:07:12 +0200128 pipeconfs.put(pipeconf.id(), pipeconf);
Carmelo Cascone44daf562017-07-16 23:55:08 -0400129 log.info("New pipeconf registered: {}", pipeconf.id());
Carmelo Casconeda0b5592018-09-14 12:54:15 -0700130 executor.execute(() -> attemptMergeAll(pipeconf.id()));
Andrea Campanellabc112a92017-06-26 19:06:43 +0200131 }
132
133 @Override
Andrea Campanellaa9b3c9b2017-07-21 14:03:15 +0200134 public void remove(PiPipeconfId pipeconfId) throws IllegalStateException {
Carmelo Cascone96beb6f2018-06-27 18:07:12 +0200135 // TODO add mechanism to remove from device.
136 if (!pipeconfs.containsKey(pipeconfId)) {
Andrea Campanellaa9b3c9b2017-07-21 14:03:15 +0200137 throw new IllegalStateException(format("Pipeconf %s is not registered", pipeconfId));
138 }
Andrea Campanellaf9c409a2017-07-13 14:14:41 +0200139 // TODO remove the binding from the distributed Store when the lifecycle of a pipeconf is defined.
140 // pipeconfMappingStore.removeBindings(pipeconfId);
Carmelo Cascone96beb6f2018-06-27 18:07:12 +0200141 log.info("Removing pipeconf {}", pipeconfId);
142 pipeconfs.remove(pipeconfId);
Andrea Campanellaa9b3c9b2017-07-21 14:03:15 +0200143 }
144
145 @Override
Andrea Campanellabc112a92017-06-26 19:06:43 +0200146 public Iterable<PiPipeconf> getPipeconfs() {
Carmelo Cascone96beb6f2018-06-27 18:07:12 +0200147 return pipeconfs.values();
Andrea Campanellabc112a92017-06-26 19:06:43 +0200148 }
149
150 @Override
151 public Optional<PiPipeconf> getPipeconf(PiPipeconfId id) {
Carmelo Cascone96beb6f2018-06-27 18:07:12 +0200152 return Optional.ofNullable(pipeconfs.get(id));
Andrea Campanellabc112a92017-06-26 19:06:43 +0200153 }
154
155 @Override
Carmelo Cascone4c289b72019-01-22 15:30:45 -0800156 public Optional<PiPipeconf> getPipeconf(DeviceId deviceId) {
157 if (pipeconfMappingStore.getPipeconfId(deviceId) == null) {
158 return Optional.empty();
159 } else {
160 return Optional.ofNullable(pipeconfs.get(
161 pipeconfMappingStore.getPipeconfId(deviceId)));
162 }
163 }
164
165 @Override
Carmelo Cascone158b8c42018-07-04 19:42:37 +0200166 public void bindToDevice(PiPipeconfId pipeconfId, DeviceId deviceId) {
Carmelo Cascone0761cd32018-08-29 19:22:50 -0700167 PiPipeconfId existingPipeconfId = pipeconfMappingStore.getPipeconfId(deviceId);
168 if (existingPipeconfId != null && !existingPipeconfId.equals(pipeconfId)) {
169 log.error("Cannot set binding for {} to {} as one already exists ({})",
170 deviceId, pipeconfId, existingPipeconfId);
171 return;
172 }
Carmelo Cascone158b8c42018-07-04 19:42:37 +0200173 pipeconfMappingStore.createOrUpdateBinding(deviceId, pipeconfId);
174 }
175
176 @Override
Carmelo Cascone0761cd32018-08-29 19:22:50 -0700177 public String getMergedDriver(DeviceId deviceId, PiPipeconfId pipeconfId) {
Carmelo Cascone158b8c42018-07-04 19:42:37 +0200178 log.debug("Starting device driver merge of {} with {}...", deviceId, pipeconfId);
Carmelo Cascone96beb6f2018-06-27 18:07:12 +0200179 final BasicDeviceConfig basicDeviceConfig = cfgService.getConfig(
180 deviceId, BasicDeviceConfig.class);
Carmelo Cascone158b8c42018-07-04 19:42:37 +0200181 if (basicDeviceConfig == null) {
182 log.warn("Unable to get basic device config for {}, " +
Tian Jian855b1082018-10-23 16:22:47 +0800183 "aborting pipeconf driver merge", deviceId);
Carmelo Cascone158b8c42018-07-04 19:42:37 +0200184 return null;
Carmelo Cascone96beb6f2018-06-27 18:07:12 +0200185 }
Carmelo Cascone158b8c42018-07-04 19:42:37 +0200186 String baseDriverName = basicDeviceConfig.driver();
Carmelo Cascone9e4972c2018-08-30 00:29:16 -0700187 if (baseDriverName == null) {
188 log.warn("Missing driver from basic device config for {}, " +
189 "cannot produce merged driver", deviceId);
190 return null;
191 }
Carmelo Casconeda60a612018-08-24 00:01:34 -0700192 if (isMergedDriverName(baseDriverName)) {
Carmelo Cascone158b8c42018-07-04 19:42:37 +0200193 // The config already has driver name that is a merged one. We still
194 // need to make sure an instance of that merged driver is present in
195 // this node.
Carmelo Casconeda60a612018-08-24 00:01:34 -0700196 log.debug("Base driver of {} ({}) is a merged one",
197 deviceId, baseDriverName);
Carmelo Cascone158b8c42018-07-04 19:42:37 +0200198 baseDriverName = getBaseDriverNameFromMerged(baseDriverName);
Carmelo Cascone96beb6f2018-06-27 18:07:12 +0200199 }
Carmelo Cascone158b8c42018-07-04 19:42:37 +0200200
Carmelo Casconeda60a612018-08-24 00:01:34 -0700201 return doMergeDriver(baseDriverName, pipeconfId);
202 }
203
204 @Override
205 public Optional<PiPipeconfId> ofDevice(DeviceId deviceId) {
206 return Optional.ofNullable(pipeconfMappingStore.getPipeconfId(deviceId));
207 }
208
209 private String doMergeDriver(String baseDriverName, PiPipeconfId pipeconfId) {
Carmelo Cascone158b8c42018-07-04 19:42:37 +0200210 final String newDriverName = mergedDriverName(baseDriverName, pipeconfId);
Carmelo Casconeda60a612018-08-24 00:01:34 -0700211 // Serialize per newDriverName, avoid creating duplicates.
212 locks.get(newDriverName).lock();
Carmelo Cascone96beb6f2018-06-27 18:07:12 +0200213 try {
Carmelo Casconeda60a612018-08-24 00:01:34 -0700214 // If merged driver exists already we don't create a new one.
215 if (getDriver(newDriverName) != null) {
216 return newDriverName;
217 }
Carmelo Cascone3977ea42019-02-28 13:43:42 -0800218 log.debug("Creating merged driver {}...", newDriverName);
Carmelo Casconeda60a612018-08-24 00:01:34 -0700219 final Driver mergedDriver = buildMergedDriver(
220 pipeconfId, baseDriverName, newDriverName);
221 if (mergedDriver == null) {
222 // Error logged by buildMergedDriver
223 return null;
224 }
225 registerMergedDriver(mergedDriver);
226 if (missingMergedDrivers.remove(newDriverName)) {
227 log.info("There are still {} missing merged drivers",
228 missingMergedDrivers.size());
229 }
230 return newDriverName;
231 } finally {
232 locks.get(newDriverName).unlock();
Carmelo Cascone96beb6f2018-06-27 18:07:12 +0200233 }
Carmelo Cascone96beb6f2018-06-27 18:07:12 +0200234 }
235
Carmelo Cascone158b8c42018-07-04 19:42:37 +0200236 private String mergedDriverSuffix(PiPipeconfId pipeconfId) {
237 return MERGED_DRIVER_SEPARATOR + pipeconfId.id();
238 }
239
240 private String mergedDriverName(String baseDriverName, PiPipeconfId pipeconfId) {
241 return baseDriverName + mergedDriverSuffix(pipeconfId);
242 }
243
244 private String getBaseDriverNameFromMerged(String mergedDriverName) {
245 final String[] pieces = mergedDriverName.split(MERGED_DRIVER_SEPARATOR);
246 if (pieces.length != 2) {
Carmelo Cascone158b8c42018-07-04 19:42:37 +0200247 return null;
248 }
249 return pieces[0];
250 }
251
Carmelo Casconeda60a612018-08-24 00:01:34 -0700252 private PiPipeconfId getPipeconfIdFromMerged(String mergedDriverName) {
253 final String[] pieces = mergedDriverName.split(MERGED_DRIVER_SEPARATOR);
254 if (pieces.length != 2) {
255 return null;
256 }
257 return new PiPipeconfId(pieces[1]);
258 }
259
260 private boolean isMergedDriverName(String driverName) {
261 final String[] pieces = driverName.split(MERGED_DRIVER_SEPARATOR);
262 return pieces.length == 2;
263 }
264
Carmelo Cascone158b8c42018-07-04 19:42:37 +0200265 private Driver buildMergedDriver(PiPipeconfId pipeconfId, String baseDriverName,
266 String newDriverName) {
Carmelo Casconeda60a612018-08-24 00:01:34 -0700267 final Driver baseDriver = getDriver(baseDriverName);
268 if (baseDriver == null) {
Carmelo Cascone158b8c42018-07-04 19:42:37 +0200269 log.error("Base driver {} not found, cannot build a merged one",
270 baseDriverName);
271 return null;
272 }
273
274 final PiPipeconf pipeconf = pipeconfs.get(pipeconfId);
275 if (pipeconf == null) {
276 log.error("Pipeconf {} is not registered, cannot build a merged driver",
277 pipeconfId);
278 return null;
279 }
280
Carmelo Cascone96beb6f2018-06-27 18:07:12 +0200281 // extract the behaviours from the pipipeconf.
282 final Map<Class<? extends Behaviour>, Class<? extends Behaviour>> behaviours =
283 new HashMap<>();
284 pipeconf.behaviours().forEach(
285 b -> behaviours.put(b, pipeconf.implementation(b).get()));
286 final Driver piPipeconfDriver = new DefaultDriver(
287 newDriverName, baseDriver.parents(),
288 baseDriver.manufacturer(), baseDriver.hwVersion(),
289 baseDriver.swVersion(), behaviours, new HashMap<>());
290 // take the base driver created with the behaviours of the PiPeconf and
291 // merge it with the base driver that was assigned to the device
Carmelo Cascone158b8c42018-07-04 19:42:37 +0200292 return piPipeconfDriver.merge(baseDriver);
293 }
294
295 private void registerMergedDriver(Driver driver) {
296 final DriverProvider provider = new InternalDriverProvider(driver);
297 if (driverAdminService.getProviders().contains(provider)) {
298 // A provider for this driver already exist.
299 return;
300 }
Carmelo Cascone96beb6f2018-06-27 18:07:12 +0200301 driverAdminService.registerProvider(provider);
302 }
303
Carmelo Casconeda60a612018-08-24 00:01:34 -0700304 private Driver getDriver(String name) {
305 try {
Carmelo Cascone0761cd32018-08-29 19:22:50 -0700306 return driverAdminService.getDriver(name);
Carmelo Casconeda60a612018-08-24 00:01:34 -0700307 } catch (ItemNotFoundException e) {
308 return null;
309 }
310 }
311
Carmelo Casconeda0b5592018-09-14 12:54:15 -0700312 private boolean driverExists(String name) {
313 return getDriver(name) != null;
Carmelo Casconeda60a612018-08-24 00:01:34 -0700314 }
315
Carmelo Casconeda0b5592018-09-14 12:54:15 -0700316 private void checkMissingMergedDriver(DeviceId deviceId) {
317 final PiPipeconfId pipeconfId = pipeconfMappingStore.getPipeconfId(deviceId);
318 final BasicDeviceConfig cfg = cfgService.getConfig(deviceId, BasicDeviceConfig.class);
319
320 if (pipeconfId == null) {
321 // No pipeconf associated.
322 return;
323 }
324
325 if (cfg == null || cfg.driver() == null) {
326 log.warn("Missing basic device config or driver key in netcfg for " +
327 "{}, which is odd since it has a " +
328 "pipeconf associated ({})",
329 deviceId, pipeconfId);
330 return;
331 }
332
333 final String baseDriverName = cfg.driver();
334 final String mergedDriverName = mergedDriverName(baseDriverName, pipeconfId);
335
336 if (driverExists(mergedDriverName) ||
337 missingMergedDrivers.contains(mergedDriverName)) {
338 // Not missing, or already aware of it missing.
339 return;
340 }
341
342 log.info("Detected missing merged driver: {}", mergedDriverName);
343 missingMergedDrivers.add(mergedDriverName);
344 // Attempt building the driver now if all pieces are present.
345 // If not, either a driver or pipeconf event will re-trigger
346 // the process.
347 attemptDriverMerge(mergedDriverName);
348 }
349
350 private void attemptDriverMerge(String mergedDriverName) {
351 final String baseDriverName = getBaseDriverNameFromMerged(mergedDriverName);
352 final PiPipeconfId pipeconfId = getPipeconfIdFromMerged(mergedDriverName);
353 if (driverExists(baseDriverName) && pipeconfs.containsKey(pipeconfId)) {
354 doMergeDriver(baseDriverName, pipeconfId);
355 }
356 }
357
358 private void missingDriversWatchdogTask() {
359 while (true) {
360 // Most probably all missing drivers will be created before the
361 // watchdog interval, so wait before starting...
362 try {
363 TimeUnit.SECONDS.sleep(MISSING_DRIVER_WATCHDOG_INTERVAL);
364 } catch (InterruptedException e) {
365 log.warn("Interrupted! There are still {} missing merged drivers",
366 missingMergedDrivers.size());
367 }
368 if (missingMergedDrivers.isEmpty()) {
369 log.info("There are no more missing merged drivers!");
370 return;
371 }
372 log.info("Detected {} missing merged drivers, attempt merge...",
373 missingMergedDrivers.size());
374 missingMergedDrivers.forEach(this::attemptDriverMerge);
375 }
376 }
377
378 private void checkMissingMergedDrivers() {
379 cfgService.getSubjects(DeviceId.class, BasicDeviceConfig.class)
380 .forEach(this::checkMissingMergedDriver);
381 }
382
383 private void attemptMergeAll(String baseDriverName) {
Carmelo Casconeda60a612018-08-24 00:01:34 -0700384 missingMergedDrivers.stream()
Carmelo Casconeda0b5592018-09-14 12:54:15 -0700385 .filter(missingDriver -> {
386 // Filter missing merged drivers using this base driver.
387 final String xx = getBaseDriverNameFromMerged(missingDriver);
Carmelo Casconeda60a612018-08-24 00:01:34 -0700388 return xx != null && xx.equals(baseDriverName);
389 })
Carmelo Casconeda0b5592018-09-14 12:54:15 -0700390 .forEach(this::attemptDriverMerge);
Carmelo Casconeda60a612018-08-24 00:01:34 -0700391 }
392
Carmelo Casconeda0b5592018-09-14 12:54:15 -0700393 private void attemptMergeAll(PiPipeconfId pipeconfId) {
Carmelo Casconeda60a612018-08-24 00:01:34 -0700394 missingMergedDrivers.stream()
Carmelo Casconeda0b5592018-09-14 12:54:15 -0700395 .filter(missingDriver -> {
396 // Filter missing merged drivers using this pipeconf.
397 final PiPipeconfId xx = getPipeconfIdFromMerged(missingDriver);
Carmelo Casconeda60a612018-08-24 00:01:34 -0700398 return xx != null && xx.equals(pipeconfId);
399 })
Carmelo Casconeda0b5592018-09-14 12:54:15 -0700400 .forEach(this::attemptDriverMerge);
Carmelo Casconeda60a612018-08-24 00:01:34 -0700401 }
402
403 private class InternalDriverListener implements DriverListener {
404
405 @Override
406 public void event(DriverEvent event) {
Carmelo Casconeda0b5592018-09-14 12:54:15 -0700407 executor.execute(() -> attemptMergeAll(event.subject().name()));
Carmelo Casconeda60a612018-08-24 00:01:34 -0700408 }
409
410 @Override
411 public boolean isRelevant(DriverEvent event) {
412 return event.type() == DriverEvent.Type.DRIVER_ENHANCED;
413 }
414 }
415
Carmelo Cascone158b8c42018-07-04 19:42:37 +0200416 /**
417 * Internal driver provider used to register merged pipeconf drivers in the
418 * core.
419 */
420 private class InternalDriverProvider implements DriverProvider {
Andrea Campanellabc112a92017-06-26 19:06:43 +0200421
422 Driver driver;
423
Carmelo Cascone158b8c42018-07-04 19:42:37 +0200424 InternalDriverProvider(Driver driver) {
Andrea Campanellabc112a92017-06-26 19:06:43 +0200425 this.driver = driver;
426 }
427
428 @Override
429 public Set<Driver> getDrivers() {
430 return ImmutableSet.of(driver);
431 }
Carmelo Cascone158b8c42018-07-04 19:42:37 +0200432
433 @Override
434 public boolean equals(Object o) {
435 if (this == o) {
436 return true;
437 }
438 if (o == null || getClass() != o.getClass()) {
439 return false;
440 }
441 InternalDriverProvider that = (InternalDriverProvider) o;
Carmelo Casconeda60a612018-08-24 00:01:34 -0700442 return Objects.equals(driver.name(), that.driver.name());
Carmelo Cascone158b8c42018-07-04 19:42:37 +0200443 }
444
445 @Override
446 public int hashCode() {
447 return Objects.hashCode(driver.name());
448 }
Andrea Campanellabc112a92017-06-26 19:06:43 +0200449 }
Andrea Campanellabc112a92017-06-26 19:06:43 +0200450}