blob: 29deb4f54846d185d986f43a2e520e42ec85ef00 [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;
Carmelo Casconeab5d41e2019-03-06 18:02:34 -080028import org.onosproject.net.device.PortStatisticsDiscovery;
Andrea Campanellabc112a92017-06-26 19:06:43 +020029import org.onosproject.net.driver.Behaviour;
30import org.onosproject.net.driver.DefaultDriver;
31import org.onosproject.net.driver.Driver;
32import org.onosproject.net.driver.DriverAdminService;
Carmelo Casconeda60a612018-08-24 00:01:34 -070033import org.onosproject.net.driver.DriverEvent;
34import org.onosproject.net.driver.DriverListener;
Andrea Campanellabc112a92017-06-26 19:06:43 +020035import org.onosproject.net.driver.DriverProvider;
Andrea Campanellabc112a92017-06-26 19:06:43 +020036import org.onosproject.net.pi.model.PiPipeconf;
37import org.onosproject.net.pi.model.PiPipeconfId;
Carmelo Cascone39c28ca2017-11-15 13:03:57 -080038import org.onosproject.net.pi.service.PiPipeconfMappingStore;
39import org.onosproject.net.pi.service.PiPipeconfService;
Ray Milkeyd84f89b2018-08-17 14:54:17 -070040import org.osgi.service.component.annotations.Activate;
41import org.osgi.service.component.annotations.Component;
42import org.osgi.service.component.annotations.Deactivate;
43import org.osgi.service.component.annotations.Reference;
44import org.osgi.service.component.annotations.ReferenceCardinality;
Andrea Campanellabc112a92017-06-26 19:06:43 +020045import org.slf4j.Logger;
46
47import java.util.HashMap;
48import java.util.Map;
Carmelo Casconeda60a612018-08-24 00:01:34 -070049import java.util.Objects;
Andrea Campanellabc112a92017-06-26 19:06:43 +020050import java.util.Optional;
51import java.util.Set;
Andrea Campanellabc112a92017-06-26 19:06:43 +020052import java.util.concurrent.ConcurrentHashMap;
Carmelo Cascone96beb6f2018-06-27 18:07:12 +020053import java.util.concurrent.ConcurrentMap;
Andrea Campanellabc112a92017-06-26 19:06:43 +020054import java.util.concurrent.ExecutorService;
55import java.util.concurrent.Executors;
Carmelo Casconeda0b5592018-09-14 12:54:15 -070056import java.util.concurrent.TimeUnit;
Carmelo Casconeda60a612018-08-24 00:01:34 -070057import java.util.concurrent.locks.Lock;
Andrea Campanellabc112a92017-06-26 19:06:43 +020058
Carmelo Cascone44daf562017-07-16 23:55:08 -040059import static java.lang.String.format;
Andrea Campanellabc112a92017-06-26 19:06:43 +020060import static org.onlab.util.Tools.groupedThreads;
61import static org.slf4j.LoggerFactory.getLogger;
62
63
64/**
65 * Implementation of the PiPipeconfService.
66 */
Ray Milkeyd84f89b2018-08-17 14:54:17 -070067@Component(immediate = true, service = PiPipeconfService.class)
Andrea Campanella48f99fa2017-07-13 19:06:21 +020068@Beta
69public class PiPipeconfManager implements PiPipeconfService {
Andrea Campanellabc112a92017-06-26 19:06:43 +020070
71 private final Logger log = getLogger(getClass());
72
Carmelo Cascone158b8c42018-07-04 19:42:37 +020073 private static final String MERGED_DRIVER_SEPARATOR = ":";
Andrea Campanellabc112a92017-06-26 19:06:43 +020074
Carmelo Casconeda0b5592018-09-14 12:54:15 -070075 private static final int MISSING_DRIVER_WATCHDOG_INTERVAL = 5; // Seconds.
76
Ray Milkeyd84f89b2018-08-17 14:54:17 -070077 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Andrea Campanellabc112a92017-06-26 19:06:43 +020078 protected NetworkConfigRegistry cfgService;
79
Ray Milkeyd84f89b2018-08-17 14:54:17 -070080 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Andrea Campanellabc112a92017-06-26 19:06:43 +020081 protected DriverAdminService driverAdminService;
82
Ray Milkeyd84f89b2018-08-17 14:54:17 -070083 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Carmelo Cascone96beb6f2018-06-27 18:07:12 +020084 private PiPipeconfMappingStore pipeconfMappingStore;
Andrea Campanellaf9c409a2017-07-13 14:14:41 +020085
Carmelo Cascone96beb6f2018-06-27 18:07:12 +020086 // Registered pipeconf are replicated through the app subsystem and
87 // registered on app activated events. Hence, there should be no need of
88 // distributing this map.
89 protected ConcurrentMap<PiPipeconfId, PiPipeconf> pipeconfs = new ConcurrentHashMap<>();
Andrea Campanellabc112a92017-06-26 19:06:43 +020090
Carmelo Casconeda60a612018-08-24 00:01:34 -070091 private final DriverListener driverListener = new InternalDriverListener();
92 private final Set<String> missingMergedDrivers = Sets.newCopyOnWriteArraySet();
93 private final Striped<Lock> locks = Striped.lock(20);
94
Carmelo Cascone96beb6f2018-06-27 18:07:12 +020095 protected ExecutorService executor = Executors.newFixedThreadPool(
96 10, groupedThreads("onos/pipeconf-manager", "%d", log));
Andrea Campanellabc112a92017-06-26 19:06:43 +020097
Andrea Campanellabc112a92017-06-26 19:06:43 +020098 @Activate
99 public void activate() {
Carmelo Cascone0761cd32018-08-29 19:22:50 -0700100 driverAdminService.addListener(driverListener);
Carmelo Casconeda60a612018-08-24 00:01:34 -0700101 checkMissingMergedDrivers();
Carmelo Casconeda0b5592018-09-14 12:54:15 -0700102 if (!missingMergedDrivers.isEmpty()) {
103 // Missing drivers should be created upon detecting registration
104 // events of a new pipeconf or a base driver. If, for any reason, we
105 // miss such event, here's a watchdog task.
106 SharedExecutors.getPoolThreadExecutor()
107 .execute(this::missingDriversWatchdogTask);
108 }
Andrea Campanellabc112a92017-06-26 19:06:43 +0200109 log.info("Started");
110 }
111
112
113 @Deactivate
114 public void deactivate() {
115 executor.shutdown();
Carmelo Cascone0761cd32018-08-29 19:22:50 -0700116 driverAdminService.removeListener(driverListener);
Carmelo Cascone96beb6f2018-06-27 18:07:12 +0200117 pipeconfs.clear();
Carmelo Casconeda60a612018-08-24 00:01:34 -0700118 missingMergedDrivers.clear();
Andrea Campanellabc112a92017-06-26 19:06:43 +0200119 cfgService = null;
120 driverAdminService = null;
Andrea Campanellabc112a92017-06-26 19:06:43 +0200121 log.info("Stopped");
122 }
123
124 @Override
125 public void register(PiPipeconf pipeconf) throws IllegalStateException {
Carmelo Cascone96beb6f2018-06-27 18:07:12 +0200126 if (pipeconfs.containsKey(pipeconf.id())) {
Carmelo Cascone44daf562017-07-16 23:55:08 -0400127 throw new IllegalStateException(format("Pipeconf %s is already registered", pipeconf.id()));
128 }
Carmelo Cascone96beb6f2018-06-27 18:07:12 +0200129 pipeconfs.put(pipeconf.id(), pipeconf);
Carmelo Cascone44daf562017-07-16 23:55:08 -0400130 log.info("New pipeconf registered: {}", pipeconf.id());
Carmelo Casconeda0b5592018-09-14 12:54:15 -0700131 executor.execute(() -> attemptMergeAll(pipeconf.id()));
Andrea Campanellabc112a92017-06-26 19:06:43 +0200132 }
133
134 @Override
Andrea Campanellaa9b3c9b2017-07-21 14:03:15 +0200135 public void remove(PiPipeconfId pipeconfId) throws IllegalStateException {
Carmelo Cascone96beb6f2018-06-27 18:07:12 +0200136 // TODO add mechanism to remove from device.
137 if (!pipeconfs.containsKey(pipeconfId)) {
Andrea Campanellaa9b3c9b2017-07-21 14:03:15 +0200138 throw new IllegalStateException(format("Pipeconf %s is not registered", pipeconfId));
139 }
Andrea Campanellaf9c409a2017-07-13 14:14:41 +0200140 // TODO remove the binding from the distributed Store when the lifecycle of a pipeconf is defined.
141 // pipeconfMappingStore.removeBindings(pipeconfId);
Carmelo Cascone96beb6f2018-06-27 18:07:12 +0200142 log.info("Removing pipeconf {}", pipeconfId);
143 pipeconfs.remove(pipeconfId);
Andrea Campanellaa9b3c9b2017-07-21 14:03:15 +0200144 }
145
146 @Override
Andrea Campanellabc112a92017-06-26 19:06:43 +0200147 public Iterable<PiPipeconf> getPipeconfs() {
Carmelo Cascone96beb6f2018-06-27 18:07:12 +0200148 return pipeconfs.values();
Andrea Campanellabc112a92017-06-26 19:06:43 +0200149 }
150
151 @Override
152 public Optional<PiPipeconf> getPipeconf(PiPipeconfId id) {
Carmelo Cascone96beb6f2018-06-27 18:07:12 +0200153 return Optional.ofNullable(pipeconfs.get(id));
Andrea Campanellabc112a92017-06-26 19:06:43 +0200154 }
155
156 @Override
Carmelo Cascone4c289b72019-01-22 15:30:45 -0800157 public Optional<PiPipeconf> getPipeconf(DeviceId deviceId) {
158 if (pipeconfMappingStore.getPipeconfId(deviceId) == null) {
159 return Optional.empty();
160 } else {
161 return Optional.ofNullable(pipeconfs.get(
162 pipeconfMappingStore.getPipeconfId(deviceId)));
163 }
164 }
165
166 @Override
Carmelo Cascone158b8c42018-07-04 19:42:37 +0200167 public void bindToDevice(PiPipeconfId pipeconfId, DeviceId deviceId) {
Carmelo Cascone0761cd32018-08-29 19:22:50 -0700168 PiPipeconfId existingPipeconfId = pipeconfMappingStore.getPipeconfId(deviceId);
169 if (existingPipeconfId != null && !existingPipeconfId.equals(pipeconfId)) {
170 log.error("Cannot set binding for {} to {} as one already exists ({})",
171 deviceId, pipeconfId, existingPipeconfId);
172 return;
173 }
Carmelo Cascone158b8c42018-07-04 19:42:37 +0200174 pipeconfMappingStore.createOrUpdateBinding(deviceId, pipeconfId);
175 }
176
177 @Override
Carmelo Cascone0761cd32018-08-29 19:22:50 -0700178 public String getMergedDriver(DeviceId deviceId, PiPipeconfId pipeconfId) {
Carmelo Cascone158b8c42018-07-04 19:42:37 +0200179 log.debug("Starting device driver merge of {} with {}...", deviceId, pipeconfId);
Carmelo Cascone96beb6f2018-06-27 18:07:12 +0200180 final BasicDeviceConfig basicDeviceConfig = cfgService.getConfig(
181 deviceId, BasicDeviceConfig.class);
Carmelo Cascone158b8c42018-07-04 19:42:37 +0200182 if (basicDeviceConfig == null) {
183 log.warn("Unable to get basic device config for {}, " +
Tian Jian855b1082018-10-23 16:22:47 +0800184 "aborting pipeconf driver merge", deviceId);
Carmelo Cascone158b8c42018-07-04 19:42:37 +0200185 return null;
Carmelo Cascone96beb6f2018-06-27 18:07:12 +0200186 }
Carmelo Cascone158b8c42018-07-04 19:42:37 +0200187 String baseDriverName = basicDeviceConfig.driver();
Carmelo Cascone9e4972c2018-08-30 00:29:16 -0700188 if (baseDriverName == null) {
189 log.warn("Missing driver from basic device config for {}, " +
190 "cannot produce merged driver", deviceId);
191 return null;
192 }
Carmelo Casconeda60a612018-08-24 00:01:34 -0700193 if (isMergedDriverName(baseDriverName)) {
Carmelo Cascone158b8c42018-07-04 19:42:37 +0200194 // The config already has driver name that is a merged one. We still
195 // need to make sure an instance of that merged driver is present in
196 // this node.
Carmelo Casconeda60a612018-08-24 00:01:34 -0700197 log.debug("Base driver of {} ({}) is a merged one",
198 deviceId, baseDriverName);
Carmelo Cascone158b8c42018-07-04 19:42:37 +0200199 baseDriverName = getBaseDriverNameFromMerged(baseDriverName);
Carmelo Cascone96beb6f2018-06-27 18:07:12 +0200200 }
Carmelo Cascone158b8c42018-07-04 19:42:37 +0200201
Carmelo Casconeda60a612018-08-24 00:01:34 -0700202 return doMergeDriver(baseDriverName, pipeconfId);
203 }
204
205 @Override
206 public Optional<PiPipeconfId> ofDevice(DeviceId deviceId) {
207 return Optional.ofNullable(pipeconfMappingStore.getPipeconfId(deviceId));
208 }
209
210 private String doMergeDriver(String baseDriverName, PiPipeconfId pipeconfId) {
Carmelo Cascone158b8c42018-07-04 19:42:37 +0200211 final String newDriverName = mergedDriverName(baseDriverName, pipeconfId);
Carmelo Casconeda60a612018-08-24 00:01:34 -0700212 // Serialize per newDriverName, avoid creating duplicates.
213 locks.get(newDriverName).lock();
Carmelo Cascone96beb6f2018-06-27 18:07:12 +0200214 try {
Carmelo Casconeda60a612018-08-24 00:01:34 -0700215 // If merged driver exists already we don't create a new one.
216 if (getDriver(newDriverName) != null) {
217 return newDriverName;
218 }
Carmelo Cascone3977ea42019-02-28 13:43:42 -0800219 log.debug("Creating merged driver {}...", newDriverName);
Carmelo Casconeda60a612018-08-24 00:01:34 -0700220 final Driver mergedDriver = buildMergedDriver(
221 pipeconfId, baseDriverName, newDriverName);
222 if (mergedDriver == null) {
223 // Error logged by buildMergedDriver
224 return null;
225 }
226 registerMergedDriver(mergedDriver);
227 if (missingMergedDrivers.remove(newDriverName)) {
228 log.info("There are still {} missing merged drivers",
229 missingMergedDrivers.size());
230 }
231 return newDriverName;
232 } finally {
233 locks.get(newDriverName).unlock();
Carmelo Cascone96beb6f2018-06-27 18:07:12 +0200234 }
Carmelo Cascone96beb6f2018-06-27 18:07:12 +0200235 }
236
Carmelo Cascone158b8c42018-07-04 19:42:37 +0200237 private String mergedDriverSuffix(PiPipeconfId pipeconfId) {
238 return MERGED_DRIVER_SEPARATOR + pipeconfId.id();
239 }
240
241 private String mergedDriverName(String baseDriverName, PiPipeconfId pipeconfId) {
242 return baseDriverName + mergedDriverSuffix(pipeconfId);
243 }
244
245 private String getBaseDriverNameFromMerged(String mergedDriverName) {
246 final String[] pieces = mergedDriverName.split(MERGED_DRIVER_SEPARATOR);
247 if (pieces.length != 2) {
Carmelo Cascone158b8c42018-07-04 19:42:37 +0200248 return null;
249 }
250 return pieces[0];
251 }
252
Carmelo Casconeda60a612018-08-24 00:01:34 -0700253 private PiPipeconfId getPipeconfIdFromMerged(String mergedDriverName) {
254 final String[] pieces = mergedDriverName.split(MERGED_DRIVER_SEPARATOR);
255 if (pieces.length != 2) {
256 return null;
257 }
258 return new PiPipeconfId(pieces[1]);
259 }
260
261 private boolean isMergedDriverName(String driverName) {
262 final String[] pieces = driverName.split(MERGED_DRIVER_SEPARATOR);
263 return pieces.length == 2;
264 }
265
Carmelo Cascone158b8c42018-07-04 19:42:37 +0200266 private Driver buildMergedDriver(PiPipeconfId pipeconfId, String baseDriverName,
267 String newDriverName) {
Carmelo Casconeda60a612018-08-24 00:01:34 -0700268 final Driver baseDriver = getDriver(baseDriverName);
269 if (baseDriver == null) {
Carmelo Cascone158b8c42018-07-04 19:42:37 +0200270 log.error("Base driver {} not found, cannot build a merged one",
271 baseDriverName);
272 return null;
273 }
274
275 final PiPipeconf pipeconf = pipeconfs.get(pipeconfId);
276 if (pipeconf == null) {
277 log.error("Pipeconf {} is not registered, cannot build a merged driver",
278 pipeconfId);
279 return null;
280 }
281
Carmelo Cascone96beb6f2018-06-27 18:07:12 +0200282 // extract the behaviours from the pipipeconf.
283 final Map<Class<? extends Behaviour>, Class<? extends Behaviour>> behaviours =
284 new HashMap<>();
285 pipeconf.behaviours().forEach(
286 b -> behaviours.put(b, pipeconf.implementation(b).get()));
Carmelo Casconeab5d41e2019-03-06 18:02:34 -0800287
288 // FIXME: remove this check when stratum_bmv2 will be open source and we
289 // will no longer need to read port counters from the p4 program. Here
290 // we ignore the PortStatisticsDiscovery behaviour from the pipeconf if
291 // the base driver (e.g. stratum with gnmi) already has it. But in
292 // general, we should give higher priority to pipeconf behaviours.
293 if (baseDriver.hasBehaviour(PortStatisticsDiscovery.class)
294 && behaviours.remove(PortStatisticsDiscovery.class) != null) {
295 log.warn("Ignoring {} behaviour from pipeconf {}, but using " +
296 "the one provided by {} driver...",
297 PortStatisticsDiscovery.class.getSimpleName(), pipeconfId,
298 baseDriver.name());
299 }
300
Carmelo Cascone96beb6f2018-06-27 18:07:12 +0200301 final Driver piPipeconfDriver = new DefaultDriver(
302 newDriverName, baseDriver.parents(),
303 baseDriver.manufacturer(), baseDriver.hwVersion(),
304 baseDriver.swVersion(), behaviours, new HashMap<>());
305 // take the base driver created with the behaviours of the PiPeconf and
306 // merge it with the base driver that was assigned to the device
Carmelo Cascone158b8c42018-07-04 19:42:37 +0200307 return piPipeconfDriver.merge(baseDriver);
308 }
309
310 private void registerMergedDriver(Driver driver) {
311 final DriverProvider provider = new InternalDriverProvider(driver);
312 if (driverAdminService.getProviders().contains(provider)) {
313 // A provider for this driver already exist.
314 return;
315 }
Carmelo Cascone96beb6f2018-06-27 18:07:12 +0200316 driverAdminService.registerProvider(provider);
317 }
318
Carmelo Casconeda60a612018-08-24 00:01:34 -0700319 private Driver getDriver(String name) {
320 try {
Carmelo Cascone0761cd32018-08-29 19:22:50 -0700321 return driverAdminService.getDriver(name);
Carmelo Casconeda60a612018-08-24 00:01:34 -0700322 } catch (ItemNotFoundException e) {
323 return null;
324 }
325 }
326
Carmelo Casconeda0b5592018-09-14 12:54:15 -0700327 private boolean driverExists(String name) {
328 return getDriver(name) != null;
Carmelo Casconeda60a612018-08-24 00:01:34 -0700329 }
330
Carmelo Casconeda0b5592018-09-14 12:54:15 -0700331 private void checkMissingMergedDriver(DeviceId deviceId) {
332 final PiPipeconfId pipeconfId = pipeconfMappingStore.getPipeconfId(deviceId);
333 final BasicDeviceConfig cfg = cfgService.getConfig(deviceId, BasicDeviceConfig.class);
334
335 if (pipeconfId == null) {
336 // No pipeconf associated.
337 return;
338 }
339
340 if (cfg == null || cfg.driver() == null) {
341 log.warn("Missing basic device config or driver key in netcfg for " +
342 "{}, which is odd since it has a " +
343 "pipeconf associated ({})",
344 deviceId, pipeconfId);
345 return;
346 }
347
348 final String baseDriverName = cfg.driver();
349 final String mergedDriverName = mergedDriverName(baseDriverName, pipeconfId);
350
351 if (driverExists(mergedDriverName) ||
352 missingMergedDrivers.contains(mergedDriverName)) {
353 // Not missing, or already aware of it missing.
354 return;
355 }
356
357 log.info("Detected missing merged driver: {}", mergedDriverName);
358 missingMergedDrivers.add(mergedDriverName);
359 // Attempt building the driver now if all pieces are present.
360 // If not, either a driver or pipeconf event will re-trigger
361 // the process.
362 attemptDriverMerge(mergedDriverName);
363 }
364
365 private void attemptDriverMerge(String mergedDriverName) {
366 final String baseDriverName = getBaseDriverNameFromMerged(mergedDriverName);
367 final PiPipeconfId pipeconfId = getPipeconfIdFromMerged(mergedDriverName);
368 if (driverExists(baseDriverName) && pipeconfs.containsKey(pipeconfId)) {
369 doMergeDriver(baseDriverName, pipeconfId);
370 }
371 }
372
373 private void missingDriversWatchdogTask() {
374 while (true) {
375 // Most probably all missing drivers will be created before the
376 // watchdog interval, so wait before starting...
377 try {
378 TimeUnit.SECONDS.sleep(MISSING_DRIVER_WATCHDOG_INTERVAL);
379 } catch (InterruptedException e) {
380 log.warn("Interrupted! There are still {} missing merged drivers",
381 missingMergedDrivers.size());
382 }
383 if (missingMergedDrivers.isEmpty()) {
384 log.info("There are no more missing merged drivers!");
385 return;
386 }
387 log.info("Detected {} missing merged drivers, attempt merge...",
388 missingMergedDrivers.size());
389 missingMergedDrivers.forEach(this::attemptDriverMerge);
390 }
391 }
392
393 private void checkMissingMergedDrivers() {
394 cfgService.getSubjects(DeviceId.class, BasicDeviceConfig.class)
395 .forEach(this::checkMissingMergedDriver);
396 }
397
398 private void attemptMergeAll(String baseDriverName) {
Carmelo Casconeda60a612018-08-24 00:01:34 -0700399 missingMergedDrivers.stream()
Carmelo Casconeda0b5592018-09-14 12:54:15 -0700400 .filter(missingDriver -> {
401 // Filter missing merged drivers using this base driver.
402 final String xx = getBaseDriverNameFromMerged(missingDriver);
Carmelo Casconeda60a612018-08-24 00:01:34 -0700403 return xx != null && xx.equals(baseDriverName);
404 })
Carmelo Casconeda0b5592018-09-14 12:54:15 -0700405 .forEach(this::attemptDriverMerge);
Carmelo Casconeda60a612018-08-24 00:01:34 -0700406 }
407
Carmelo Casconeda0b5592018-09-14 12:54:15 -0700408 private void attemptMergeAll(PiPipeconfId pipeconfId) {
Carmelo Casconeda60a612018-08-24 00:01:34 -0700409 missingMergedDrivers.stream()
Carmelo Casconeda0b5592018-09-14 12:54:15 -0700410 .filter(missingDriver -> {
411 // Filter missing merged drivers using this pipeconf.
412 final PiPipeconfId xx = getPipeconfIdFromMerged(missingDriver);
Carmelo Casconeda60a612018-08-24 00:01:34 -0700413 return xx != null && xx.equals(pipeconfId);
414 })
Carmelo Casconeda0b5592018-09-14 12:54:15 -0700415 .forEach(this::attemptDriverMerge);
Carmelo Casconeda60a612018-08-24 00:01:34 -0700416 }
417
418 private class InternalDriverListener implements DriverListener {
419
420 @Override
421 public void event(DriverEvent event) {
Carmelo Casconeda0b5592018-09-14 12:54:15 -0700422 executor.execute(() -> attemptMergeAll(event.subject().name()));
Carmelo Casconeda60a612018-08-24 00:01:34 -0700423 }
424
425 @Override
426 public boolean isRelevant(DriverEvent event) {
427 return event.type() == DriverEvent.Type.DRIVER_ENHANCED;
428 }
429 }
430
Carmelo Cascone158b8c42018-07-04 19:42:37 +0200431 /**
432 * Internal driver provider used to register merged pipeconf drivers in the
433 * core.
434 */
435 private class InternalDriverProvider implements DriverProvider {
Andrea Campanellabc112a92017-06-26 19:06:43 +0200436
437 Driver driver;
438
Carmelo Cascone158b8c42018-07-04 19:42:37 +0200439 InternalDriverProvider(Driver driver) {
Andrea Campanellabc112a92017-06-26 19:06:43 +0200440 this.driver = driver;
441 }
442
443 @Override
444 public Set<Driver> getDrivers() {
445 return ImmutableSet.of(driver);
446 }
Carmelo Cascone158b8c42018-07-04 19:42:37 +0200447
448 @Override
449 public boolean equals(Object o) {
450 if (this == o) {
451 return true;
452 }
453 if (o == null || getClass() != o.getClass()) {
454 return false;
455 }
456 InternalDriverProvider that = (InternalDriverProvider) o;
Carmelo Casconeda60a612018-08-24 00:01:34 -0700457 return Objects.equals(driver.name(), that.driver.name());
Carmelo Cascone158b8c42018-07-04 19:42:37 +0200458 }
459
460 @Override
461 public int hashCode() {
462 return Objects.hashCode(driver.name());
463 }
Andrea Campanellabc112a92017-06-26 19:06:43 +0200464 }
Andrea Campanellabc112a92017-06-26 19:06:43 +0200465}