Plugin migration to use the new Schema independent Library.
[netvirt.git] / plugin / src / main / java / org / opendaylight / ovsdb / plugin / InventoryService.java
1 /*
2  * Copyright (C) 2013 Red Hat, Inc.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  *
8  * Authors : Madhu Venugopal, Brent Salisbury
9  */
10 package org.opendaylight.ovsdb.plugin;
11
12 import java.util.Collections;
13 import java.util.HashMap;
14 import java.util.HashSet;
15 import java.util.Map;
16 import java.util.Set;
17 import java.util.concurrent.ConcurrentHashMap;
18 import java.util.concurrent.ConcurrentMap;
19 import java.util.concurrent.CopyOnWriteArraySet;
20 import java.util.concurrent.ExecutionException;
21 import java.util.concurrent.Executors;
22 import java.util.concurrent.ScheduledExecutorService;
23 import java.util.concurrent.TimeUnit;
24
25 import org.opendaylight.controller.sal.core.ConstructionException;
26 import org.opendaylight.controller.sal.core.Description;
27 import org.opendaylight.controller.sal.core.Node;
28 import org.opendaylight.controller.sal.core.NodeConnector;
29 import org.opendaylight.controller.sal.core.Property;
30 import org.opendaylight.controller.sal.core.UpdateType;
31 import org.opendaylight.controller.sal.inventory.IPluginInInventoryService;
32 import org.opendaylight.controller.sal.inventory.IPluginOutInventoryService;
33 import org.opendaylight.controller.sal.utils.HexEncode;
34 import org.opendaylight.controller.sal.utils.ServiceHelper;
35 import org.opendaylight.ovsdb.lib.message.TableUpdate;
36 import org.opendaylight.ovsdb.lib.message.TableUpdates;
37 import org.opendaylight.ovsdb.lib.notation.Row;
38 import org.opendaylight.ovsdb.schema.openvswitch.Bridge;
39 import org.slf4j.Logger;
40 import org.slf4j.LoggerFactory;
41
42 import com.google.common.collect.Maps;
43
44 /**
45  * Stub Implementation for IPluginInReadService used by SAL
46  *
47  *
48  */
49 public class InventoryService implements IPluginInInventoryService, InventoryServiceInternal {
50     private static final Logger logger = LoggerFactory
51             .getLogger(InventoryService.class);
52     private final Set<IPluginOutInventoryService> pluginOutInventoryServices =
53             new CopyOnWriteArraySet<IPluginOutInventoryService>();
54     private ConcurrentMap<Node, Map<String, Property>> nodeProps;
55     private ConcurrentMap<NodeConnector, Map<String, Property>> nodeConnectorProps;
56     private ConcurrentMap<Node, NodeDB> dbCache = Maps.newConcurrentMap();
57     private ScheduledExecutorService executor;
58     private OVSDBConfigService configurationService;
59
60     /**
61      * Function called by the dependency manager when all the required
62      * dependencies are satisfied
63      *
64      */
65     public void init() {
66         nodeProps = new ConcurrentHashMap<Node, Map<String, Property>>();
67         nodeConnectorProps = new ConcurrentHashMap<NodeConnector, Map<String, Property>>();
68         Node.NodeIDType.registerIDType("OVS", String.class);
69         NodeConnector.NodeConnectorIDType.registerIDType("OVS", String.class, "OVS");
70         this.executor = Executors.newSingleThreadScheduledExecutor();
71     }
72
73     /**
74      * Function called by the dependency manager when at least one dependency
75      * become unsatisfied or when the component is shutting down because for
76      * example bundle is being stopped.
77      *
78      */
79     public void destroy() {
80     }
81
82     /**
83      * Function called by dependency manager after "init ()" is called and after
84      * the services provided by the class are registered in the service registry
85      *
86      */
87     public void start() {
88     }
89
90     /**
91      * Function called by the dependency manager before the services exported by
92      * the component are unregistered, this will be followed by a "destroy ()"
93      * calls
94      *
95      */
96     public void stop() {
97         this.executor.shutdownNow();
98     }
99
100     public void setPluginOutInventoryServices(IPluginOutInventoryService service) {
101             this.pluginOutInventoryServices.add(service);
102     }
103
104     public void unsetPluginOutInventoryServices(IPluginOutInventoryService service) {
105             this.pluginOutInventoryServices.remove(service);
106     }
107
108     public void setConfigurationService(OVSDBConfigService service) {
109         configurationService = service;
110     }
111
112     public void unsetConfigurationService(OVSDBConfigService service) {
113         configurationService = null;
114     }
115
116     /**
117      * Retrieve nodes from openflow
118      */
119     @Override
120     public ConcurrentMap<Node, Map<String, Property>> getNodeProps() {
121         return nodeProps;
122     }
123
124     /**
125      * Retrieve nodeConnectors from openflow
126      */
127     @Override
128     public ConcurrentMap<NodeConnector, Map<String, Property>> getNodeConnectorProps(
129             Boolean refresh) {
130         return nodeConnectorProps;
131     }
132
133
134     @Override
135     public ConcurrentMap<String, ConcurrentMap<String, Row>> getCache(Node n, String databaseName) {
136         NodeDB db = dbCache.get(n);
137         if (db == null) return null;
138         return db.getDatabase(databaseName);
139     }
140
141
142     @Override
143     public ConcurrentMap<String, Row> getTableCache(Node n, String databaseName, String tableName) {
144         NodeDB db = dbCache.get(n);
145         if (db == null) return null;
146         return db.getTableCache(databaseName, tableName);
147     }
148
149
150     @Override
151     public Row getRow(Node n, String databaseName, String tableName, String uuid) {
152         NodeDB db = dbCache.get(n);
153         if (db == null) return null;
154         return db.getRow(databaseName, tableName, uuid);
155     }
156
157     @Override
158     public void updateRow(Node n, String databaseName, String tableName, String uuid, Row row) {
159         NodeDB db = dbCache.get(n);
160         if (db == null) {
161             db = new NodeDB();
162             dbCache.put(n, db);
163         }
164         db.updateRow(databaseName, tableName, uuid, row);
165     }
166
167     @Override
168     public void removeRow(Node n, String databaseName, String tableName, String uuid) {
169         NodeDB db = dbCache.get(n);
170         if (db != null) db.removeRow(databaseName, tableName, uuid);
171     }
172
173     @Override
174     public void processTableUpdates(Node n, String databaseName, TableUpdates tableUpdates) {
175         NodeDB db = dbCache.get(n);
176         if (db == null) {
177             db = new NodeDB();
178             dbCache.put(n, db);
179         }
180
181         OVSDBInventoryListener inventoryListener = (OVSDBInventoryListener)ServiceHelper.getGlobalInstance(OVSDBInventoryListener.class, this);
182         for (String tableName : tableUpdates.getUpdates().keySet()) {
183             Map<String, Row> tCache = db.getTableCache(databaseName, tableName);
184             TableUpdate update = tableUpdates.getUpdates().get(tableName);
185
186             if (update.getNew() != null) {
187                 boolean isNewRow = (tCache == null || tCache.get(update.getUuid().toString()) == null) ? true : false;
188                 db.updateRow(databaseName, tableName, update.getUuid().toString(), update.getNew());
189                 if (isNewRow) {
190                     this.handleOpenVSwitchSpecialCase(n, databaseName, tableName, update);
191                     if (inventoryListener != null) inventoryListener.rowAdded(n, tableName, update.getUuid().toString(), update.getNew());
192                 } else {
193                     if (inventoryListener != null) inventoryListener.rowUpdated(n, tableName, update.getUuid().toString(), update.getOld(), update.getNew());
194                 }
195             } else if (update.getOld() != null){
196                 if (tCache != null) {
197                     if (inventoryListener != null) inventoryListener.rowRemoved(n, tableName, update.getUuid().toString(), update.getOld(), update.getNew());
198                 }
199                 db.removeRow(databaseName, tableName, update.getUuid().toString());
200             }
201         }
202     }
203
204     private void handleOpenVSwitchSpecialCase(Node node, String databaseName, String tableName, TableUpdate update) {
205         if (OvsVswitchdSchemaConstants.shouldConfigureController(databaseName, tableName)) {
206             try {
207                 if (configurationService != null) configurationService.setOFController(node, update.getUuid().toString());
208             } catch (InterruptedException | ExecutionException e) {
209                 e.printStackTrace();
210             }
211         }
212     }
213
214     private void updateOFBridgeName(final Node node, final Bridge bridge) {
215         Runnable updateNameRunnable = new Runnable() {
216             @Override
217             public void run() {
218                 Set<String> dpids = bridge.getDatapathIdColumn().getData();
219                 String bridgeName = bridge.getName();
220                 if (dpids == null || bridgeName == null) return;
221                 for (String dpid : dpids) {
222                     Long dpidLong = Long.valueOf(HexEncode.stringToLong(dpid));
223                     try {
224                         Node ofNode = new Node(Node.NodeIDType.OPENFLOW, dpidLong);
225                         Description descProp = new Description(bridgeName);
226                         Set<Property> props = new HashSet<Property>();
227                         props.add(descProp);
228
229                         IPluginOutInventoryService salInventoryService = (IPluginOutInventoryService) ServiceHelper.getInstance(
230                                 IPluginOutInventoryService.class, "default", this);
231                         if (salInventoryService != null) {
232                             logger.debug("Updating Bridge Name {} on OF node {}", bridgeName, ofNode);
233                             salInventoryService.updateNode(ofNode, UpdateType.CHANGED, props);
234                         } else {
235                             logger.error("Error accessing SAL Inventory plugin");
236                         }
237                     } catch (ConstructionException e) {
238                         logger.error("Failed to construct node for " + dpid, e);
239                     }
240                 }
241             }
242         };
243         executor.execute(updateNameRunnable);
244         // Add a delay & re-execute to compensate for the current OpenFlow plugin bug of
245         // overriding the Description with a Null value after the first statistics timer.
246         // Hopefully this will be resolved in the newer version of the Openflow plugin.
247         executor.schedule(updateNameRunnable, 30, TimeUnit.SECONDS);
248     }
249
250     @Override
251     public void printCache(Node n) {
252         NodeDB db = dbCache.get(n);
253         if (db != null) db.printTableCache();
254     }
255
256     @Override
257     public void addNode(Node node, Set<Property> props) {
258         addNodeProperty(node, UpdateType.ADDED, props);
259     }
260
261     @Override
262     public void notifyNodeAdded(Node node) {
263         OVSDBInventoryListener inventoryListener = (OVSDBInventoryListener)ServiceHelper.getGlobalInstance(OVSDBInventoryListener.class, this);
264         if (inventoryListener != null) {
265             inventoryListener.nodeAdded(node);
266         }
267     }
268
269     @Override
270     public void addNodeProperty(Node node, UpdateType type, Set<Property> props) {
271         Map<String, Property> nProp = nodeProps.get(node);
272         if (nProp == null) nProp = new HashMap<String, Property>();
273         for (Property prop : props) {
274             nProp.put(prop.getName(), prop);
275         }
276         nodeProps.put(node, nProp);
277         for (IPluginOutInventoryService service : pluginOutInventoryServices) {
278             service.updateNode(node, type, props);
279         }
280     }
281
282     @Override
283     public void removeNode(Node node) {
284         OVSDBInventoryListener inventoryListener = (OVSDBInventoryListener)ServiceHelper.getGlobalInstance(OVSDBInventoryListener.class, this);
285         if (inventoryListener != null) {
286             inventoryListener.nodeRemoved(node);
287         }
288
289         for (IPluginOutInventoryService service : pluginOutInventoryServices) {
290             service.updateNode(node, UpdateType.REMOVED, null);
291         }
292         nodeProps.remove(node);
293         dbCache.remove(node);
294     }
295
296     @Override
297     public Set<Node> getConfiguredNotConnectedNodes() {
298         return Collections.emptySet();
299     }
300 }