blob: 7ed674b429f997b2ebcd591c7a5ca3eb3352d092 [file] [log] [blame]
Thomas Vachuskaa8f4e7d2015-01-08 17:31:55 -08001/*
Brian O'Connor5ab426f2016-04-09 01:19:45 -07002 * Copyright 2015-present Open Networking Laboratory
Thomas Vachuskaa8f4e7d2015-01-08 17:31:55 -08003 *
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 */
16package org.onosproject.net.driver;
17
18import com.google.common.collect.ImmutableMap;
Andrea Campanella80520b82016-01-05 17:55:29 -080019import com.google.common.collect.Lists;
alshabib975617b2015-04-09 13:26:53 -070020import com.google.common.collect.Maps;
Andrea Campanella80520b82016-01-05 17:55:29 -080021import org.slf4j.Logger;
Thomas Vachuskaa8f4e7d2015-01-08 17:31:55 -080022
Andrea Campanella28dbe8f2016-01-28 17:51:58 -080023import java.util.ArrayList;
Andrea Campanella80520b82016-01-05 17:55:29 -080024import java.util.List;
Thomas Vachuskaa8f4e7d2015-01-08 17:31:55 -080025import java.util.Map;
Thomas Vachuska635c2d72015-05-08 14:32:13 -070026import java.util.Objects;
Thomas Vachuskaa8f4e7d2015-01-08 17:31:55 -080027import java.util.Set;
28
29import static com.google.common.base.MoreObjects.toStringHelper;
30import static com.google.common.base.Preconditions.checkArgument;
31import static com.google.common.base.Preconditions.checkNotNull;
32import static com.google.common.collect.ImmutableMap.copyOf;
Andrea Campanella80520b82016-01-05 17:55:29 -080033import static org.slf4j.LoggerFactory.getLogger;
Thomas Vachuskaa8f4e7d2015-01-08 17:31:55 -080034
35/**
36 * Default implementation of extensible driver.
37 */
38public class DefaultDriver implements Driver {
39
Andrea Campanella80520b82016-01-05 17:55:29 -080040 private final Logger log = getLogger(getClass());
41
Thomas Vachuskaa8f4e7d2015-01-08 17:31:55 -080042 private final String name;
Andrea Campanella80520b82016-01-05 17:55:29 -080043 private final List<Driver> parents;
Thomas Vachuskaa8f4e7d2015-01-08 17:31:55 -080044
45 private final String manufacturer;
46 private final String hwVersion;
47 private final String swVersion;
48
49 private final Map<Class<? extends Behaviour>, Class<? extends Behaviour>> behaviours;
50 private final Map<String, String> properties;
51
Thomas Vachuskaa8f4e7d2015-01-08 17:31:55 -080052 /**
53 * Creates a driver with the specified name.
54 *
55 * @param name driver name
Andrea Campanella80520b82016-01-05 17:55:29 -080056 * @param parents optional parent drivers
57 * @param manufacturer device manufacturer
58 * @param hwVersion device hardware version
59 * @param swVersion device software version
60 * @param behaviours device behaviour classes
61 * @param properties properties for configuration of device behaviour classes
62 */
63 public DefaultDriver(String name, List<Driver> parents, String manufacturer,
64 String hwVersion, String swVersion,
65 Map<Class<? extends Behaviour>, Class<? extends Behaviour>> behaviours,
66 Map<String, String> properties) {
67 this.name = checkNotNull(name, "Name cannot be null");
68 this.parents = parents == null || parents.isEmpty() ? null : parents;
Thomas Vachuskaa8f4e7d2015-01-08 17:31:55 -080069 this.manufacturer = checkNotNull(manufacturer, "Manufacturer cannot be null");
70 this.hwVersion = checkNotNull(hwVersion, "HW version cannot be null");
71 this.swVersion = checkNotNull(swVersion, "SW version cannot be null");
72 this.behaviours = copyOf(checkNotNull(behaviours, "Behaviours cannot be null"));
73 this.properties = copyOf(checkNotNull(properties, "Properties cannot be null"));
74 }
75
Thomas Vachuska5c2f8132015-04-08 23:09:08 -070076 @Override
77 public Driver merge(Driver other) {
Andrea Campanella80520b82016-01-05 17:55:29 -080078 checkArgument(parents == null || Objects.equals(parent(), other.parent()),
Thomas Vachuska635c2d72015-05-08 14:32:13 -070079 "Parent drivers are not the same");
Thomas Vachuskaa8f4e7d2015-01-08 17:31:55 -080080 // Merge the behaviours.
alshabib975617b2015-04-09 13:26:53 -070081 Map<Class<? extends Behaviour>, Class<? extends Behaviour>>
82 behaviours = Maps.newHashMap();
Thomas Vachuska5c2f8132015-04-08 23:09:08 -070083 behaviours.putAll(this.behaviours);
84 other.behaviours().forEach(b -> behaviours.put(b, other.implementation(b)));
Thomas Vachuskaa8f4e7d2015-01-08 17:31:55 -080085
86 // Merge the properties.
87 ImmutableMap.Builder<String, String> properties = ImmutableMap.builder();
Thomas Vachuska5c2f8132015-04-08 23:09:08 -070088 properties.putAll(this.properties).putAll(other.properties());
Andrea Campanella28dbe8f2016-01-28 17:51:58 -080089 List<Driver> completeParents = new ArrayList<>();
Thomas Vachuskaa8f4e7d2015-01-08 17:31:55 -080090
Andrea Campanella28dbe8f2016-01-28 17:51:58 -080091 if (parents != null) {
92 parents.forEach(parent -> other.parents().forEach(otherParent -> {
93 if (otherParent.name().equals(parent.name())) {
94 completeParents.add(parent.merge(otherParent));
95 } else if (!completeParents.contains(otherParent)) {
96 completeParents.add(otherParent);
97 } else if (!completeParents.contains(parent)) {
98 completeParents.add(parent);
99 }
100 }));
101 }
Jon Hallcbd1b392017-01-18 20:15:44 -0800102 return new DefaultDriver(name, !completeParents.isEmpty() ? completeParents : other.parents(),
Andrea Campanella80520b82016-01-05 17:55:29 -0800103 manufacturer, hwVersion, swVersion,
alshabib975617b2015-04-09 13:26:53 -0700104 ImmutableMap.copyOf(behaviours), properties.build());
Thomas Vachuskaa8f4e7d2015-01-08 17:31:55 -0800105 }
106
107 @Override
108 public String name() {
109 return name;
110 }
111
112 @Override
113 public String manufacturer() {
114 return manufacturer;
115 }
116
117 @Override
118 public String hwVersion() {
119 return hwVersion;
120 }
121
122 @Override
123 public String swVersion() {
124 return swVersion;
125 }
126
127 @Override
Thomas Vachuska635c2d72015-05-08 14:32:13 -0700128 public Driver parent() {
Andrea Campanella80520b82016-01-05 17:55:29 -0800129 return parents == null ? null : parents.get(0);
130 }
131
132 @Override
133 public List<Driver> parents() {
134 return parents;
Thomas Vachuska635c2d72015-05-08 14:32:13 -0700135 }
136
137 @Override
Thomas Vachuskaa8f4e7d2015-01-08 17:31:55 -0800138 public Set<Class<? extends Behaviour>> behaviours() {
139 return behaviours.keySet();
140 }
141
142 @Override
Thomas Vachuska5c2f8132015-04-08 23:09:08 -0700143 public Class<? extends Behaviour> implementation(Class<? extends Behaviour> behaviour) {
144 return behaviours.get(behaviour);
145 }
146
147 @Override
Thomas Vachuskaa8f4e7d2015-01-08 17:31:55 -0800148 public boolean hasBehaviour(Class<? extends Behaviour> behaviourClass) {
Thomas Vachuska635c2d72015-05-08 14:32:13 -0700149 return behaviours.containsKey(behaviourClass) ||
Andrea Campanella80520b82016-01-05 17:55:29 -0800150 (parents != null && parents.stream()
151 .filter(parent -> parent.hasBehaviour(behaviourClass)).count() > 0);
Thomas Vachuskaa8f4e7d2015-01-08 17:31:55 -0800152 }
153
Thomas Vachuskafacc3f52015-04-10 08:58:36 -0700154 @Override
Thomas Vachuskaa8f4e7d2015-01-08 17:31:55 -0800155 public <T extends Behaviour> T createBehaviour(DriverData data,
Thomas Vachuskafacc3f52015-04-10 08:58:36 -0700156 Class<T> behaviourClass) {
Thomas Vachuska635c2d72015-05-08 14:32:13 -0700157 T behaviour = createBehaviour(data, null, behaviourClass);
158 if (behaviour != null) {
159 return behaviour;
Andrea Campanella80520b82016-01-05 17:55:29 -0800160 } else if (parents != null) {
161 for (Driver parent : Lists.reverse(parents)) {
162 try {
163 return parent.createBehaviour(data, behaviourClass);
164 } catch (IllegalArgumentException e) {
165 log.debug("Parent {} does not support behaviour {}", parent, behaviourClass);
166 }
167 }
Thomas Vachuska635c2d72015-05-08 14:32:13 -0700168 }
169 throw new IllegalArgumentException(behaviourClass.getName() + " not supported");
Thomas Vachuskafacc3f52015-04-10 08:58:36 -0700170 }
171
172 @Override
173 public <T extends Behaviour> T createBehaviour(DriverHandler handler,
174 Class<T> behaviourClass) {
Thomas Vachuska635c2d72015-05-08 14:32:13 -0700175 T behaviour = createBehaviour(handler.data(), handler, behaviourClass);
176 if (behaviour != null) {
177 return behaviour;
Andrea Campanella80520b82016-01-05 17:55:29 -0800178 } else if (parents != null && !parents.isEmpty()) {
179 for (Driver parent : Lists.reverse(parents)) {
180 try {
181 return parent.createBehaviour(handler, behaviourClass);
182 } catch (IllegalArgumentException e) {
183 log.debug("Parent {} does not support behaviour {}", parent, behaviourClass);
184 }
185 }
Thomas Vachuska635c2d72015-05-08 14:32:13 -0700186 }
187 throw new IllegalArgumentException(behaviourClass.getName() + " not supported");
Thomas Vachuskafacc3f52015-04-10 08:58:36 -0700188 }
189
190 // Creates an instance of behaviour primed with the specified driver data.
191 private <T extends Behaviour> T createBehaviour(DriverData data, DriverHandler handler,
192 Class<T> behaviourClass) {
CNluciusa66c3972015-09-06 20:31:29 +0800193 //checkArgument(handler != null || !HandlerBehaviour.class.isAssignableFrom(behaviourClass),
194 // "{} is applicable only to handler context", behaviourClass.getName());
Thomas Vachuskaa8f4e7d2015-01-08 17:31:55 -0800195
196 // Locate the implementation of the requested behaviour.
197 Class<? extends Behaviour> implementation = behaviours.get(behaviourClass);
Thomas Vachuska635c2d72015-05-08 14:32:13 -0700198 if (implementation != null) {
199 // Create an instance of the behaviour and apply data as its context.
200 T behaviour = createBehaviour(behaviourClass, implementation);
201 behaviour.setData(data);
Thomas Vachuskaa8f4e7d2015-01-08 17:31:55 -0800202
Thomas Vachuska635c2d72015-05-08 14:32:13 -0700203 // If this is a handler behaviour, also apply handler as its context.
204 if (handler != null) {
205 ((HandlerBehaviour) behaviour).setHandler(handler);
206 }
207 return behaviour;
Thomas Vachuskafacc3f52015-04-10 08:58:36 -0700208 }
Thomas Vachuska635c2d72015-05-08 14:32:13 -0700209 return null;
Thomas Vachuskaa8f4e7d2015-01-08 17:31:55 -0800210 }
211
212 @SuppressWarnings("unchecked")
213 private <T extends Behaviour> T createBehaviour(Class<T> behaviourClass,
214 Class<? extends Behaviour> implementation) {
215 try {
216 return (T) implementation.newInstance();
217 } catch (InstantiationException | IllegalAccessException e) {
218 // TODO: add a specific unchecked exception
219 throw new IllegalArgumentException("Unable to create behaviour", e);
220 }
221 }
222
223 @Override
224 public Set<String> keys() {
225 return properties.keySet();
226 }
227
228 @Override
229 public String value(String key) {
230 return properties.get(key);
231 }
232
233 @Override
234 public Map<String, String> properties() {
235 return properties;
236 }
237
238 @Override
239 public String toString() {
240 return toStringHelper(this)
241 .add("name", name)
Andrea Campanella80520b82016-01-05 17:55:29 -0800242 .add("parents", parents)
Thomas Vachuskaa8f4e7d2015-01-08 17:31:55 -0800243 .add("manufacturer", manufacturer)
244 .add("hwVersion", hwVersion)
245 .add("swVersion", swVersion)
246 .add("behaviours", behaviours)
247 .add("properties", properties)
248 .toString();
249 }
250
Andrea Campanella238d96e2016-01-20 11:52:02 -0800251 @Override
252 public boolean equals(Object driverToBeCompared) {
253 if (this == driverToBeCompared) {
254 return true;
255 }
256 if (driverToBeCompared == null || getClass() != driverToBeCompared.getClass()) {
257 return false;
258 }
259
260 DefaultDriver driver = (DefaultDriver) driverToBeCompared;
261
262 return name.equals(driver.name());
263
264 }
265
266 @Override
267 public int hashCode() {
268 return Objects.hashCode(name);
269 }
Thomas Vachuskaa8f4e7d2015-01-08 17:31:55 -0800270}