blob: 02850ff8cfd5d08cf33a1fa0f87969713ee0324e [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.apache.felix.scr.annotations.Activate;
24import org.apache.felix.scr.annotations.Component;
25import org.apache.felix.scr.annotations.Deactivate;
26import org.apache.felix.scr.annotations.Reference;
27import org.apache.felix.scr.annotations.ReferenceCardinality;
28import org.apache.felix.scr.annotations.Service;
29import org.onlab.util.ItemNotFoundException;
Carmelo Casconeda0b5592018-09-14 12:54:15 -070030import org.onlab.util.SharedExecutors;
Andrea Campanellabc112a92017-06-26 19:06:43 +020031import org.onosproject.net.DeviceId;
32import org.onosproject.net.config.ConfigFactory;
Andrea Campanellabc112a92017-06-26 19:06:43 +020033import org.onosproject.net.config.NetworkConfigRegistry;
34import org.onosproject.net.config.basics.BasicDeviceConfig;
35import org.onosproject.net.config.basics.SubjectFactories;
36import org.onosproject.net.driver.Behaviour;
37import org.onosproject.net.driver.DefaultDriver;
38import org.onosproject.net.driver.Driver;
39import org.onosproject.net.driver.DriverAdminService;
Carmelo Casconeda60a612018-08-24 00:01:34 -070040import org.onosproject.net.driver.DriverEvent;
41import org.onosproject.net.driver.DriverListener;
Andrea Campanellabc112a92017-06-26 19:06:43 +020042import org.onosproject.net.driver.DriverProvider;
Andrea Campanellabc112a92017-06-26 19:06:43 +020043import org.onosproject.net.pi.model.PiPipeconf;
44import org.onosproject.net.pi.model.PiPipeconfId;
Carmelo Cascone39c28ca2017-11-15 13:03:57 -080045import org.onosproject.net.pi.service.PiPipeconfConfig;
46import org.onosproject.net.pi.service.PiPipeconfMappingStore;
47import org.onosproject.net.pi.service.PiPipeconfService;
Andrea Campanellabc112a92017-06-26 19:06:43 +020048import org.slf4j.Logger;
49
50import java.util.HashMap;
51import java.util.Map;
Carmelo Casconeda60a612018-08-24 00:01:34 -070052import java.util.Objects;
Andrea Campanellabc112a92017-06-26 19:06:43 +020053import java.util.Optional;
54import java.util.Set;
Andrea Campanellabc112a92017-06-26 19:06:43 +020055import java.util.concurrent.ConcurrentHashMap;
Carmelo Cascone96beb6f2018-06-27 18:07:12 +020056import java.util.concurrent.ConcurrentMap;
Andrea Campanellabc112a92017-06-26 19:06:43 +020057import java.util.concurrent.ExecutorService;
58import java.util.concurrent.Executors;
Carmelo Casconeda0b5592018-09-14 12:54:15 -070059import java.util.concurrent.TimeUnit;
Carmelo Casconeda60a612018-08-24 00:01:34 -070060import java.util.concurrent.locks.Lock;
Andrea Campanellabc112a92017-06-26 19:06:43 +020061
Carmelo Cascone44daf562017-07-16 23:55:08 -040062import static java.lang.String.format;
Andrea Campanellabc112a92017-06-26 19:06:43 +020063import static org.onlab.util.Tools.groupedThreads;
64import static org.slf4j.LoggerFactory.getLogger;
65
66
67/**
68 * Implementation of the PiPipeconfService.
69 */
70@Component(immediate = true)
71@Service
Andrea Campanella48f99fa2017-07-13 19:06:21 +020072@Beta
73public class PiPipeconfManager implements PiPipeconfService {
Andrea Campanellabc112a92017-06-26 19:06:43 +020074
75 private final Logger log = getLogger(getClass());
76
Carmelo Cascone158b8c42018-07-04 19:42:37 +020077 private static final String MERGED_DRIVER_SEPARATOR = ":";
Andrea Campanellabc112a92017-06-26 19:06:43 +020078 private static final String CFG_SCHEME = "piPipeconf";
79
Carmelo Casconeda0b5592018-09-14 12:54:15 -070080 private static final int MISSING_DRIVER_WATCHDOG_INTERVAL = 5; // Seconds.
81
Andrea Campanellabc112a92017-06-26 19:06:43 +020082 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
83 protected NetworkConfigRegistry cfgService;
84
85 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Andrea Campanellabc112a92017-06-26 19:06:43 +020086 protected DriverAdminService driverAdminService;
87
Andrea Campanellaf9c409a2017-07-13 14:14:41 +020088 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Carmelo Cascone96beb6f2018-06-27 18:07:12 +020089 private PiPipeconfMappingStore pipeconfMappingStore;
Andrea Campanellaf9c409a2017-07-13 14:14:41 +020090
Carmelo Cascone96beb6f2018-06-27 18:07:12 +020091 // Registered pipeconf are replicated through the app subsystem and
92 // registered on app activated events. Hence, there should be no need of
93 // distributing this map.
94 protected ConcurrentMap<PiPipeconfId, PiPipeconf> pipeconfs = new ConcurrentHashMap<>();
Andrea Campanellabc112a92017-06-26 19:06:43 +020095
Carmelo Casconeda60a612018-08-24 00:01:34 -070096 private final DriverListener driverListener = new InternalDriverListener();
97 private final Set<String> missingMergedDrivers = Sets.newCopyOnWriteArraySet();
98 private final Striped<Lock> locks = Striped.lock(20);
99
Carmelo Cascone96beb6f2018-06-27 18:07:12 +0200100 protected ExecutorService executor = Executors.newFixedThreadPool(
101 10, groupedThreads("onos/pipeconf-manager", "%d", log));
Andrea Campanellabc112a92017-06-26 19:06:43 +0200102
Carmelo Cascone96beb6f2018-06-27 18:07:12 +0200103 protected final ConfigFactory configFactory =
Andrea Campanellabc112a92017-06-26 19:06:43 +0200104 new ConfigFactory<DeviceId, PiPipeconfConfig>(
105 SubjectFactories.DEVICE_SUBJECT_FACTORY,
106 PiPipeconfConfig.class, CFG_SCHEME) {
107 @Override
108 public PiPipeconfConfig createConfig() {
109 return new PiPipeconfConfig();
110 }
111 };
112
Andrea Campanellabc112a92017-06-26 19:06:43 +0200113 @Activate
114 public void activate() {
Carmelo Cascone96beb6f2018-06-27 18:07:12 +0200115 cfgService.registerConfigFactory(configFactory);
Carmelo Cascone0761cd32018-08-29 19:22:50 -0700116 driverAdminService.addListener(driverListener);
Carmelo Casconeda60a612018-08-24 00:01:34 -0700117 checkMissingMergedDrivers();
Carmelo Casconeda0b5592018-09-14 12:54:15 -0700118 if (!missingMergedDrivers.isEmpty()) {
119 // Missing drivers should be created upon detecting registration
120 // events of a new pipeconf or a base driver. If, for any reason, we
121 // miss such event, here's a watchdog task.
122 SharedExecutors.getPoolThreadExecutor()
123 .execute(this::missingDriversWatchdogTask);
124 }
Andrea Campanellabc112a92017-06-26 19:06:43 +0200125 log.info("Started");
126 }
127
128
129 @Deactivate
130 public void deactivate() {
131 executor.shutdown();
Carmelo Cascone96beb6f2018-06-27 18:07:12 +0200132 cfgService.unregisterConfigFactory(configFactory);
Carmelo Cascone0761cd32018-08-29 19:22:50 -0700133 driverAdminService.removeListener(driverListener);
Carmelo Cascone96beb6f2018-06-27 18:07:12 +0200134 pipeconfs.clear();
Carmelo Casconeda60a612018-08-24 00:01:34 -0700135 missingMergedDrivers.clear();
Andrea Campanellabc112a92017-06-26 19:06:43 +0200136 cfgService = null;
137 driverAdminService = null;
Andrea Campanellabc112a92017-06-26 19:06:43 +0200138 log.info("Stopped");
139 }
140
141 @Override
142 public void register(PiPipeconf pipeconf) throws IllegalStateException {
Carmelo Cascone96beb6f2018-06-27 18:07:12 +0200143 if (pipeconfs.containsKey(pipeconf.id())) {
Carmelo Cascone44daf562017-07-16 23:55:08 -0400144 throw new IllegalStateException(format("Pipeconf %s is already registered", pipeconf.id()));
145 }
Carmelo Cascone96beb6f2018-06-27 18:07:12 +0200146 pipeconfs.put(pipeconf.id(), pipeconf);
Carmelo Cascone44daf562017-07-16 23:55:08 -0400147 log.info("New pipeconf registered: {}", pipeconf.id());
Carmelo Casconeda0b5592018-09-14 12:54:15 -0700148 executor.execute(() -> attemptMergeAll(pipeconf.id()));
Andrea Campanellabc112a92017-06-26 19:06:43 +0200149 }
150
151 @Override
Andrea Campanellaa9b3c9b2017-07-21 14:03:15 +0200152 public void remove(PiPipeconfId pipeconfId) throws IllegalStateException {
Carmelo Cascone96beb6f2018-06-27 18:07:12 +0200153 // TODO add mechanism to remove from device.
154 if (!pipeconfs.containsKey(pipeconfId)) {
Andrea Campanellaa9b3c9b2017-07-21 14:03:15 +0200155 throw new IllegalStateException(format("Pipeconf %s is not registered", pipeconfId));
156 }
Andrea Campanellaf9c409a2017-07-13 14:14:41 +0200157 // TODO remove the binding from the distributed Store when the lifecycle of a pipeconf is defined.
158 // pipeconfMappingStore.removeBindings(pipeconfId);
Carmelo Cascone96beb6f2018-06-27 18:07:12 +0200159 log.info("Removing pipeconf {}", pipeconfId);
160 pipeconfs.remove(pipeconfId);
Andrea Campanellaa9b3c9b2017-07-21 14:03:15 +0200161 }
162
163 @Override
Andrea Campanellabc112a92017-06-26 19:06:43 +0200164 public Iterable<PiPipeconf> getPipeconfs() {
Carmelo Cascone96beb6f2018-06-27 18:07:12 +0200165 return pipeconfs.values();
Andrea Campanellabc112a92017-06-26 19:06:43 +0200166 }
167
168 @Override
169 public Optional<PiPipeconf> getPipeconf(PiPipeconfId id) {
Carmelo Cascone96beb6f2018-06-27 18:07:12 +0200170 return Optional.ofNullable(pipeconfs.get(id));
Andrea Campanellabc112a92017-06-26 19:06:43 +0200171 }
172
173 @Override
Carmelo Cascone158b8c42018-07-04 19:42:37 +0200174 public void bindToDevice(PiPipeconfId pipeconfId, DeviceId deviceId) {
Carmelo Cascone0761cd32018-08-29 19:22:50 -0700175 PiPipeconfId existingPipeconfId = pipeconfMappingStore.getPipeconfId(deviceId);
176 if (existingPipeconfId != null && !existingPipeconfId.equals(pipeconfId)) {
177 log.error("Cannot set binding for {} to {} as one already exists ({})",
178 deviceId, pipeconfId, existingPipeconfId);
179 return;
180 }
Carmelo Cascone158b8c42018-07-04 19:42:37 +0200181 pipeconfMappingStore.createOrUpdateBinding(deviceId, pipeconfId);
182 }
183
184 @Override
Carmelo Cascone0761cd32018-08-29 19:22:50 -0700185 public String getMergedDriver(DeviceId deviceId, PiPipeconfId pipeconfId) {
Carmelo Cascone158b8c42018-07-04 19:42:37 +0200186 log.debug("Starting device driver merge of {} with {}...", deviceId, pipeconfId);
Carmelo Cascone96beb6f2018-06-27 18:07:12 +0200187 final BasicDeviceConfig basicDeviceConfig = cfgService.getConfig(
188 deviceId, BasicDeviceConfig.class);
Carmelo Cascone158b8c42018-07-04 19:42:37 +0200189 if (basicDeviceConfig == null) {
190 log.warn("Unable to get basic device config for {}, " +
Tian Jian855b1082018-10-23 16:22:47 +0800191 "aborting pipeconf driver merge", deviceId);
Carmelo Cascone158b8c42018-07-04 19:42:37 +0200192 return null;
Carmelo Cascone96beb6f2018-06-27 18:07:12 +0200193 }
Carmelo Cascone158b8c42018-07-04 19:42:37 +0200194 String baseDriverName = basicDeviceConfig.driver();
Carmelo Cascone9e4972c2018-08-30 00:29:16 -0700195 if (baseDriverName == null) {
196 log.warn("Missing driver from basic device config for {}, " +
197 "cannot produce merged driver", deviceId);
198 return null;
199 }
Carmelo Casconeda60a612018-08-24 00:01:34 -0700200 if (isMergedDriverName(baseDriverName)) {
Carmelo Cascone158b8c42018-07-04 19:42:37 +0200201 // The config already has driver name that is a merged one. We still
202 // need to make sure an instance of that merged driver is present in
203 // this node.
Carmelo Casconeda60a612018-08-24 00:01:34 -0700204 log.debug("Base driver of {} ({}) is a merged one",
205 deviceId, baseDriverName);
Carmelo Cascone158b8c42018-07-04 19:42:37 +0200206 baseDriverName = getBaseDriverNameFromMerged(baseDriverName);
Carmelo Cascone96beb6f2018-06-27 18:07:12 +0200207 }
Carmelo Cascone158b8c42018-07-04 19:42:37 +0200208
Carmelo Casconeda60a612018-08-24 00:01:34 -0700209 return doMergeDriver(baseDriverName, pipeconfId);
210 }
211
212 @Override
213 public Optional<PiPipeconfId> ofDevice(DeviceId deviceId) {
214 return Optional.ofNullable(pipeconfMappingStore.getPipeconfId(deviceId));
215 }
216
217 private String doMergeDriver(String baseDriverName, PiPipeconfId pipeconfId) {
Carmelo Cascone158b8c42018-07-04 19:42:37 +0200218 final String newDriverName = mergedDriverName(baseDriverName, pipeconfId);
Carmelo Casconeda60a612018-08-24 00:01:34 -0700219 // Serialize per newDriverName, avoid creating duplicates.
220 locks.get(newDriverName).lock();
Carmelo Cascone96beb6f2018-06-27 18:07:12 +0200221 try {
Carmelo Casconeda60a612018-08-24 00:01:34 -0700222 // If merged driver exists already we don't create a new one.
223 if (getDriver(newDriverName) != null) {
224 return newDriverName;
225 }
Carmelo Cascone96beb6f2018-06-27 18:07:12 +0200226 log.info("Creating merged driver {}...", newDriverName);
Carmelo Casconeda60a612018-08-24 00:01:34 -0700227 final Driver mergedDriver = buildMergedDriver(
228 pipeconfId, baseDriverName, newDriverName);
229 if (mergedDriver == null) {
230 // Error logged by buildMergedDriver
231 return null;
232 }
233 registerMergedDriver(mergedDriver);
234 if (missingMergedDrivers.remove(newDriverName)) {
235 log.info("There are still {} missing merged drivers",
236 missingMergedDrivers.size());
237 }
238 return newDriverName;
239 } finally {
240 locks.get(newDriverName).unlock();
Carmelo Cascone96beb6f2018-06-27 18:07:12 +0200241 }
Carmelo Cascone96beb6f2018-06-27 18:07:12 +0200242 }
243
Carmelo Cascone158b8c42018-07-04 19:42:37 +0200244 private String mergedDriverSuffix(PiPipeconfId pipeconfId) {
245 return MERGED_DRIVER_SEPARATOR + pipeconfId.id();
246 }
247
248 private String mergedDriverName(String baseDriverName, PiPipeconfId pipeconfId) {
249 return baseDriverName + mergedDriverSuffix(pipeconfId);
250 }
251
252 private String getBaseDriverNameFromMerged(String mergedDriverName) {
253 final String[] pieces = mergedDriverName.split(MERGED_DRIVER_SEPARATOR);
254 if (pieces.length != 2) {
Carmelo Cascone158b8c42018-07-04 19:42:37 +0200255 return null;
256 }
257 return pieces[0];
258 }
259
Carmelo Casconeda60a612018-08-24 00:01:34 -0700260 private PiPipeconfId getPipeconfIdFromMerged(String mergedDriverName) {
261 final String[] pieces = mergedDriverName.split(MERGED_DRIVER_SEPARATOR);
262 if (pieces.length != 2) {
263 return null;
264 }
265 return new PiPipeconfId(pieces[1]);
266 }
267
268 private boolean isMergedDriverName(String driverName) {
269 final String[] pieces = driverName.split(MERGED_DRIVER_SEPARATOR);
270 return pieces.length == 2;
271 }
272
Carmelo Cascone158b8c42018-07-04 19:42:37 +0200273 private Driver buildMergedDriver(PiPipeconfId pipeconfId, String baseDriverName,
274 String newDriverName) {
Carmelo Casconeda60a612018-08-24 00:01:34 -0700275 final Driver baseDriver = getDriver(baseDriverName);
276 if (baseDriver == null) {
Carmelo Cascone158b8c42018-07-04 19:42:37 +0200277 log.error("Base driver {} not found, cannot build a merged one",
278 baseDriverName);
279 return null;
280 }
281
282 final PiPipeconf pipeconf = pipeconfs.get(pipeconfId);
283 if (pipeconf == null) {
284 log.error("Pipeconf {} is not registered, cannot build a merged driver",
285 pipeconfId);
286 return null;
287 }
288
Carmelo Cascone96beb6f2018-06-27 18:07:12 +0200289 // extract the behaviours from the pipipeconf.
290 final Map<Class<? extends Behaviour>, Class<? extends Behaviour>> behaviours =
291 new HashMap<>();
292 pipeconf.behaviours().forEach(
293 b -> behaviours.put(b, pipeconf.implementation(b).get()));
294 final Driver piPipeconfDriver = new DefaultDriver(
295 newDriverName, baseDriver.parents(),
296 baseDriver.manufacturer(), baseDriver.hwVersion(),
297 baseDriver.swVersion(), behaviours, new HashMap<>());
298 // take the base driver created with the behaviours of the PiPeconf and
299 // merge it with the base driver that was assigned to the device
Carmelo Cascone158b8c42018-07-04 19:42:37 +0200300 return piPipeconfDriver.merge(baseDriver);
301 }
302
303 private void registerMergedDriver(Driver driver) {
304 final DriverProvider provider = new InternalDriverProvider(driver);
305 if (driverAdminService.getProviders().contains(provider)) {
306 // A provider for this driver already exist.
307 return;
308 }
Carmelo Cascone96beb6f2018-06-27 18:07:12 +0200309 driverAdminService.registerProvider(provider);
310 }
311
Carmelo Casconeda60a612018-08-24 00:01:34 -0700312 private Driver getDriver(String name) {
313 try {
Carmelo Cascone0761cd32018-08-29 19:22:50 -0700314 return driverAdminService.getDriver(name);
Carmelo Casconeda60a612018-08-24 00:01:34 -0700315 } catch (ItemNotFoundException e) {
316 return null;
317 }
318 }
319
Carmelo Casconeda0b5592018-09-14 12:54:15 -0700320 private boolean driverExists(String name) {
321 return getDriver(name) != null;
Carmelo Casconeda60a612018-08-24 00:01:34 -0700322 }
323
Carmelo Casconeda0b5592018-09-14 12:54:15 -0700324 private void checkMissingMergedDriver(DeviceId deviceId) {
325 final PiPipeconfId pipeconfId = pipeconfMappingStore.getPipeconfId(deviceId);
326 final BasicDeviceConfig cfg = cfgService.getConfig(deviceId, BasicDeviceConfig.class);
327
328 if (pipeconfId == null) {
329 // No pipeconf associated.
330 return;
331 }
332
333 if (cfg == null || cfg.driver() == null) {
334 log.warn("Missing basic device config or driver key in netcfg for " +
335 "{}, which is odd since it has a " +
336 "pipeconf associated ({})",
337 deviceId, pipeconfId);
338 return;
339 }
340
341 final String baseDriverName = cfg.driver();
342 final String mergedDriverName = mergedDriverName(baseDriverName, pipeconfId);
343
344 if (driverExists(mergedDriverName) ||
345 missingMergedDrivers.contains(mergedDriverName)) {
346 // Not missing, or already aware of it missing.
347 return;
348 }
349
350 log.info("Detected missing merged driver: {}", mergedDriverName);
351 missingMergedDrivers.add(mergedDriverName);
352 // Attempt building the driver now if all pieces are present.
353 // If not, either a driver or pipeconf event will re-trigger
354 // the process.
355 attemptDriverMerge(mergedDriverName);
356 }
357
358 private void attemptDriverMerge(String mergedDriverName) {
359 final String baseDriverName = getBaseDriverNameFromMerged(mergedDriverName);
360 final PiPipeconfId pipeconfId = getPipeconfIdFromMerged(mergedDriverName);
361 if (driverExists(baseDriverName) && pipeconfs.containsKey(pipeconfId)) {
362 doMergeDriver(baseDriverName, pipeconfId);
363 }
364 }
365
366 private void missingDriversWatchdogTask() {
367 while (true) {
368 // Most probably all missing drivers will be created before the
369 // watchdog interval, so wait before starting...
370 try {
371 TimeUnit.SECONDS.sleep(MISSING_DRIVER_WATCHDOG_INTERVAL);
372 } catch (InterruptedException e) {
373 log.warn("Interrupted! There are still {} missing merged drivers",
374 missingMergedDrivers.size());
375 }
376 if (missingMergedDrivers.isEmpty()) {
377 log.info("There are no more missing merged drivers!");
378 return;
379 }
380 log.info("Detected {} missing merged drivers, attempt merge...",
381 missingMergedDrivers.size());
382 missingMergedDrivers.forEach(this::attemptDriverMerge);
383 }
384 }
385
386 private void checkMissingMergedDrivers() {
387 cfgService.getSubjects(DeviceId.class, BasicDeviceConfig.class)
388 .forEach(this::checkMissingMergedDriver);
389 }
390
391 private void attemptMergeAll(String baseDriverName) {
Carmelo Casconeda60a612018-08-24 00:01:34 -0700392 missingMergedDrivers.stream()
Carmelo Casconeda0b5592018-09-14 12:54:15 -0700393 .filter(missingDriver -> {
394 // Filter missing merged drivers using this base driver.
395 final String xx = getBaseDriverNameFromMerged(missingDriver);
Carmelo Casconeda60a612018-08-24 00:01:34 -0700396 return xx != null && xx.equals(baseDriverName);
397 })
Carmelo Casconeda0b5592018-09-14 12:54:15 -0700398 .forEach(this::attemptDriverMerge);
Carmelo Casconeda60a612018-08-24 00:01:34 -0700399 }
400
Carmelo Casconeda0b5592018-09-14 12:54:15 -0700401 private void attemptMergeAll(PiPipeconfId pipeconfId) {
Carmelo Casconeda60a612018-08-24 00:01:34 -0700402 missingMergedDrivers.stream()
Carmelo Casconeda0b5592018-09-14 12:54:15 -0700403 .filter(missingDriver -> {
404 // Filter missing merged drivers using this pipeconf.
405 final PiPipeconfId xx = getPipeconfIdFromMerged(missingDriver);
Carmelo Casconeda60a612018-08-24 00:01:34 -0700406 return xx != null && xx.equals(pipeconfId);
407 })
Carmelo Casconeda0b5592018-09-14 12:54:15 -0700408 .forEach(this::attemptDriverMerge);
Carmelo Casconeda60a612018-08-24 00:01:34 -0700409 }
410
411 private class InternalDriverListener implements DriverListener {
412
413 @Override
414 public void event(DriverEvent event) {
Carmelo Casconeda0b5592018-09-14 12:54:15 -0700415 executor.execute(() -> attemptMergeAll(event.subject().name()));
Carmelo Casconeda60a612018-08-24 00:01:34 -0700416 }
417
418 @Override
419 public boolean isRelevant(DriverEvent event) {
420 return event.type() == DriverEvent.Type.DRIVER_ENHANCED;
421 }
422 }
423
Carmelo Cascone158b8c42018-07-04 19:42:37 +0200424 /**
425 * Internal driver provider used to register merged pipeconf drivers in the
426 * core.
427 */
428 private class InternalDriverProvider implements DriverProvider {
Andrea Campanellabc112a92017-06-26 19:06:43 +0200429
430 Driver driver;
431
Carmelo Cascone158b8c42018-07-04 19:42:37 +0200432 InternalDriverProvider(Driver driver) {
Andrea Campanellabc112a92017-06-26 19:06:43 +0200433 this.driver = driver;
434 }
435
436 @Override
437 public Set<Driver> getDrivers() {
438 return ImmutableSet.of(driver);
439 }
Carmelo Cascone158b8c42018-07-04 19:42:37 +0200440
441 @Override
442 public boolean equals(Object o) {
443 if (this == o) {
444 return true;
445 }
446 if (o == null || getClass() != o.getClass()) {
447 return false;
448 }
449 InternalDriverProvider that = (InternalDriverProvider) o;
Carmelo Casconeda60a612018-08-24 00:01:34 -0700450 return Objects.equals(driver.name(), that.driver.name());
Carmelo Cascone158b8c42018-07-04 19:42:37 +0200451 }
452
453 @Override
454 public int hashCode() {
455 return Objects.hashCode(driver.name());
456 }
Andrea Campanellabc112a92017-06-26 19:06:43 +0200457 }
Andrea Campanellabc112a92017-06-26 19:06:43 +0200458}