blob: fc5e04a1f7d773709ed8af4e5d8f76058fcefead [file] [log] [blame]
Thomas Vachuskaa8f4e7d2015-01-08 17:31:55 -08001/*
2 * Copyright 2015 Open Networking Laboratory
3 *
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;
Thomas Vachuska635c2d72015-05-08 14:32:13 -070019import com.google.common.collect.Maps;
Thomas Vachuskaa8f4e7d2015-01-08 17:31:55 -080020import org.apache.commons.configuration.ConfigurationException;
21import org.apache.commons.configuration.HierarchicalConfiguration;
22import org.apache.commons.configuration.XMLConfiguration;
23
24import java.io.IOException;
25import java.io.InputStream;
26import java.util.Map;
27
28/**
29 * Utility capable of reading driver configuration XML resources and producing
30 * a device driver provider as a result.
31 * <p>
32 * The drivers stream structure is as follows:
33 * </p>
34 * <pre>
35 * &lt;drivers&gt;
36 * &lt;driver name=“...” [manufacturer="..." hwVersion="..." swVersion="..."]&gt;
37 * &lt;behaviour api="..." impl="..."/&gt;
38 * ...
39 * [&lt;property name=“key”&gt;value&lt;/key&gt;]
40 * ...
41 * &lt;/driver&gt;
42 * ...
43 * &lt;/drivers&gt;
44 * </pre>
45 */
46public class XmlDriverLoader {
47
48 private static final String DRIVERS = "drivers";
49 private static final String DRIVER = "driver";
50
51 private static final String BEHAVIOUR = "behaviour";
52 private static final String PROPERTY = "property";
53
54 private static final String NAME = "[@name]";
Thomas Vachuska635c2d72015-05-08 14:32:13 -070055 private static final String EXTENDS = "[@extends]";
Thomas Vachuskaa8f4e7d2015-01-08 17:31:55 -080056 private static final String MFG = "[@manufacturer]";
57 private static final String HW = "[@hwVersion]";
58 private static final String SW = "[@swVersion]";
59 private static final String API = "[@api]";
60 private static final String IMPL = "[@impl]";
61
62 private final ClassLoader classLoader;
63
Thomas Vachuska635c2d72015-05-08 14:32:13 -070064 private Map<String, Driver> drivers = Maps.newHashMap();
65
Thomas Vachuskaa8f4e7d2015-01-08 17:31:55 -080066 /**
67 * Creates a new driver loader capable of loading drivers from the supplied
68 * class loader.
69 *
70 * @param classLoader class loader to use
71 */
72 public XmlDriverLoader(ClassLoader classLoader) {
73 this.classLoader = classLoader;
74 }
75
76 /**
77 * Loads the specified drivers resource as an XML stream and parses it to
78 * produce a ready-to-register driver provider.
79 *
80 * @param driversStream stream containing the drivers definitions
Thomas Vachuska635c2d72015-05-08 14:32:13 -070081 * @param resolver driver resolver
Thomas Vachuskaa8f4e7d2015-01-08 17:31:55 -080082 * @return driver provider
83 * @throws java.io.IOException if issues are encountered reading the stream
84 * or parsing the driver definitions within
85 */
Thomas Vachuska635c2d72015-05-08 14:32:13 -070086 public DefaultDriverProvider loadDrivers(InputStream driversStream,
87 DriverResolver resolver) throws IOException {
Thomas Vachuskaa8f4e7d2015-01-08 17:31:55 -080088 try {
89 XMLConfiguration cfg = new XMLConfiguration();
90 cfg.setRootElementName(DRIVERS);
91 cfg.setAttributeSplittingDisabled(true);
92
93 cfg.load(driversStream);
Thomas Vachuska635c2d72015-05-08 14:32:13 -070094 return loadDrivers(cfg, resolver);
Thomas Vachuskaa8f4e7d2015-01-08 17:31:55 -080095 } catch (ConfigurationException e) {
96 throw new IOException("Unable to load drivers", e);
97 }
98 }
99
100 /**
101 * Loads a driver provider from the supplied hierarchical configuration.
102 *
103 * @param driversCfg hierarchical configuration containing the drivers definitions
Thomas Vachuska635c2d72015-05-08 14:32:13 -0700104 * @param resolver driver resolver
Thomas Vachuskaa8f4e7d2015-01-08 17:31:55 -0800105 * @return driver provider
106 */
Thomas Vachuska635c2d72015-05-08 14:32:13 -0700107 public DefaultDriverProvider loadDrivers(HierarchicalConfiguration driversCfg,
108 DriverResolver resolver) {
Thomas Vachuskaa8f4e7d2015-01-08 17:31:55 -0800109 DefaultDriverProvider provider = new DefaultDriverProvider();
110 for (HierarchicalConfiguration cfg : driversCfg.configurationsAt(DRIVER)) {
Thomas Vachuska635c2d72015-05-08 14:32:13 -0700111 DefaultDriver driver = loadDriver(cfg, resolver);
112 drivers.put(driver.name(), driver);
113 provider.addDriver(driver);
Thomas Vachuskaa8f4e7d2015-01-08 17:31:55 -0800114 }
Thomas Vachuska635c2d72015-05-08 14:32:13 -0700115 drivers.clear();
Thomas Vachuskaa8f4e7d2015-01-08 17:31:55 -0800116 return provider;
117 }
118
119 /**
120 * Loads a driver from the supplied hierarchical configuration.
121 *
122 * @param driverCfg hierarchical configuration containing the driver definition
Thomas Vachuska635c2d72015-05-08 14:32:13 -0700123 * @param resolver driver resolver
Thomas Vachuskaa8f4e7d2015-01-08 17:31:55 -0800124 * @return driver
125 */
Thomas Vachuska635c2d72015-05-08 14:32:13 -0700126 public DefaultDriver loadDriver(HierarchicalConfiguration driverCfg,
127 DriverResolver resolver) {
Thomas Vachuskaa8f4e7d2015-01-08 17:31:55 -0800128 String name = driverCfg.getString(NAME);
Thomas Vachuska635c2d72015-05-08 14:32:13 -0700129 String parentName = driverCfg.getString(EXTENDS);
Thomas Vachuskaa8f4e7d2015-01-08 17:31:55 -0800130 String manufacturer = driverCfg.getString(MFG, "");
131 String hwVersion = driverCfg.getString(HW, "");
132 String swVersion = driverCfg.getString(SW, "");
133
Thomas Vachuska635c2d72015-05-08 14:32:13 -0700134 Driver parent = parentName != null ? resolve(parentName, resolver) : null;
135 return new DefaultDriver(name, parent, manufacturer, hwVersion, swVersion,
Thomas Vachuskaa8f4e7d2015-01-08 17:31:55 -0800136 parseBehaviours(driverCfg),
137 parseProperties(driverCfg));
138 }
139
Thomas Vachuska635c2d72015-05-08 14:32:13 -0700140 // Resolves the driver by name locally at first and then using the specified resolver.
141 private Driver resolve(String parentName, DriverResolver resolver) {
142 Driver driver = drivers.get(parentName);
143 return driver != null ? driver :
144 (resolver != null ? resolver.getDriver(parentName) : null);
145 }
146
Thomas Vachuskaa8f4e7d2015-01-08 17:31:55 -0800147 // Parses the behaviours section.
148 private Map<Class<? extends Behaviour>, Class<? extends Behaviour>>
149 parseBehaviours(HierarchicalConfiguration driverCfg) {
150 ImmutableMap.Builder<Class<? extends Behaviour>,
151 Class<? extends Behaviour>> behaviours = ImmutableMap.builder();
152 for (HierarchicalConfiguration b : driverCfg.configurationsAt(BEHAVIOUR)) {
153 behaviours.put(getClass(b.getString(API)), getClass(b.getString(IMPL)));
154 }
155 return behaviours.build();
156 }
157
158 // Parses the properties section.
159 private Map<String, String> parseProperties(HierarchicalConfiguration driverCfg) {
160 ImmutableMap.Builder<String, String> properties = ImmutableMap.builder();
161 for (HierarchicalConfiguration b : driverCfg.configurationsAt(PROPERTY)) {
162 properties.put(b.getString(NAME), (String) b.getRootNode().getValue());
163 }
164 return properties.build();
165 }
166
167 @SuppressWarnings("unchecked")
168 private Class<? extends Behaviour> getClass(String className) {
169 try {
170 return (Class<? extends Behaviour>) classLoader.loadClass(className);
171 } catch (ClassNotFoundException e) {
172 throw new IllegalArgumentException("Unable to load class " + className, e);
173 }
174 }
175
176}