Merge "Added the missing Copyright headers to most of the java files."
[netvirt.git] / ovsdb / 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.Collection;
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.Executors;
21 import java.util.concurrent.ScheduledExecutorService;
22 import java.util.concurrent.TimeUnit;
23
24 import org.opendaylight.controller.sal.core.ConstructionException;
25 import org.opendaylight.controller.sal.core.Description;
26 import org.opendaylight.controller.sal.core.Node;
27 import org.opendaylight.controller.sal.core.NodeConnector;
28 import org.opendaylight.controller.sal.core.Property;
29 import org.opendaylight.controller.sal.core.UpdateType;
30 import org.opendaylight.controller.sal.inventory.IPluginInInventoryService;
31 import org.opendaylight.controller.sal.inventory.IPluginOutInventoryService;
32 import org.opendaylight.controller.sal.utils.HexEncode;
33 import org.opendaylight.controller.sal.utils.ServiceHelper;
34 import org.opendaylight.ovsdb.lib.database.DatabaseSchema;
35 import org.opendaylight.ovsdb.lib.message.TableUpdate;
36 import org.opendaylight.ovsdb.lib.message.TableUpdate.Row;
37 import org.opendaylight.ovsdb.lib.message.TableUpdates;
38 import org.opendaylight.ovsdb.lib.notation.OvsDBSet;
39 import org.opendaylight.ovsdb.lib.table.Bridge;
40 import org.opendaylight.ovsdb.lib.table.internal.Table;
41 import org.slf4j.Logger;
42 import org.slf4j.LoggerFactory;
43
44 import com.google.common.collect.Maps;
45
46 /**
47  * Stub Implementation for IPluginInReadService used by SAL
48  *
49  *
50  */
51 public class InventoryService implements IPluginInInventoryService, InventoryServiceInternal {
52     private static final Logger logger = LoggerFactory
53             .getLogger(InventoryService.class);
54     private final Set<IPluginOutInventoryService> pluginOutInventoryServices =
55             new CopyOnWriteArraySet<IPluginOutInventoryService>();
56     private ConcurrentMap<Node, Map<String, Property>> nodeProps;
57     private ConcurrentMap<NodeConnector, Map<String, Property>> nodeConnectorProps;
58     private Map<Node, NodeDB> dbCache = Maps.newHashMap();
59     private ScheduledExecutorService executor;
60
61     /**
62      * Function called by the dependency manager when all the required
63      * dependencies are satisfied
64      *
65      */
66     public void init() {
67         nodeProps = new ConcurrentHashMap<Node, Map<String, Property>>();
68         nodeConnectorProps = new ConcurrentHashMap<NodeConnector, Map<String, Property>>();
69         Node.NodeIDType.registerIDType("OVS", String.class);
70         NodeConnector.NodeConnectorIDType.registerIDType("OVS", String.class, "OVS");
71         this.executor = Executors.newSingleThreadScheduledExecutor();
72     }
73
74     /**
75      * Function called by the dependency manager when at least one dependency
76      * become unsatisfied or when the component is shutting down because for
77      * example bundle is being stopped.
78      *
79      */
80     public void destroy() {
81     }
82
83     /**
84      * Function called by dependency manager after "init ()" is called and after
85      * the services provided by the class are registered in the service registry
86      *
87      */
88     public void start() {
89     }
90
91     /**
92      * Function called by the dependency manager before the services exported by
93      * the component are unregistered, this will be followed by a "destroy ()"
94      * calls
95      *
96      */
97     public void stop() {
98         this.executor.shutdownNow();
99     }
100
101     public void setPluginOutInventoryServices(IPluginOutInventoryService service) {
102         if (this.pluginOutInventoryServices != null) {
103             this.pluginOutInventoryServices.add(service);
104         }
105     }
106
107     public void unsetPluginOutInventoryServices(
108             IPluginOutInventoryService service) {
109         if (this.pluginOutInventoryServices != null) {
110             this.pluginOutInventoryServices.remove(service);
111         }
112     }
113
114     /**
115      * Retrieve nodes from openflow
116      */
117     @Override
118     public ConcurrentMap<Node, Map<String, Property>> getNodeProps() {
119         return nodeProps;
120     }
121
122     /**
123      * Retrieve nodeConnectors from openflow
124      */
125     @Override
126     public ConcurrentMap<NodeConnector, Map<String, Property>> getNodeConnectorProps(
127             Boolean refresh) {
128         return nodeConnectorProps;
129     }
130
131
132     @Override
133     public Map<String, Map<String, Table<?>>> getCache(Node n) {
134         NodeDB db = dbCache.get(n);
135         if (db == null) return null;
136         return db.getTableCache();
137     }
138
139
140     @Override
141     public Map<String, Table<?>> getTableCache(Node n, String tableName) {
142         NodeDB db = dbCache.get(n);
143         if (db == null) return null;
144         return db.getTableCache(tableName);
145     }
146
147
148     @Override
149     public Table<?> getRow(Node n, String tableName, String uuid) {
150         NodeDB db = dbCache.get(n);
151         if (db == null) return null;
152         return db.getRow(tableName, uuid);
153     }
154
155     @Override
156     public void updateRow(Node n, String tableName, String uuid, Table<?> row) {
157         NodeDB db = dbCache.get(n);
158         if (db == null) {
159             db = new NodeDB();
160             dbCache.put(n, db);
161         }
162         db.updateRow(tableName, uuid, row);
163     }
164
165     @Override
166     public void removeRow(Node n, String tableName, String uuid) {
167         NodeDB db = dbCache.get(n);
168         if (db != null) db.removeRow(tableName, uuid);
169     }
170
171     @Override
172     public void processTableUpdates(Node n, TableUpdates tableUpdates) {
173         NodeDB db = dbCache.get(n);
174         if (db == null) {
175             db = new NodeDB();
176             dbCache.put(n, db);
177         }
178
179         OVSDBInventoryListener inventoryListener = (OVSDBInventoryListener)ServiceHelper.getGlobalInstance(OVSDBInventoryListener.class, this);
180         Set<Table.Name> available = tableUpdates.availableUpdates();
181         for (Table.Name name : available) {
182             TableUpdate tableUpdate = tableUpdates.getUpdate(name);
183             Collection<TableUpdate.Row<?>> rows = tableUpdate.getRows();
184             for (Row<?> row : rows) {
185                 String uuid = row.getId();
186                 Table<?> newRow = (Table<?>)row.getNew();
187                 Table<?> oldRow = (Table<?>)row.getOld();
188                 if (newRow != null) {
189                     db.updateRow(name.getName(), uuid, newRow);
190                     if (name.getName().equalsIgnoreCase("bridge")) {
191                         logger.debug("Received Bridge Table udpate for node {}", n);
192                         // OVSDB has the Bridge name info while OpenFlow Spec is not
193                         // Clear on that. From a user/manageability standpoint, it is easier
194                         // to handle Bridge names compared to dpids.
195                         // Updating the Openflow bridge name via the SAL Description update.
196                         updateOFBridgeName(n, (Bridge)newRow);
197                     }
198                     if ((oldRow == null) && (inventoryListener != null)) {
199                         inventoryListener.rowAdded(n, name.getName(), uuid, newRow);
200                     } else if (inventoryListener != null) {
201                         inventoryListener.rowUpdated(n, name.getName(), uuid, oldRow, newRow);
202                     }
203                 } else if (oldRow != null) {
204                     if (inventoryListener != null) {
205                         inventoryListener.rowRemoved(n, name.getName(), uuid, oldRow);
206                     }
207                     db.removeRow(name.getName(), uuid);
208                 }
209             }
210         }
211     }
212
213     private void updateOFBridgeName(final Node node, final Bridge bridge) {
214         Runnable updateNameRunnable = new Runnable() {
215             @Override
216             public void run() {
217                 OvsDBSet<String> dpids = bridge.getDatapath_id();
218                 String bridgeName = bridge.getName();
219                 if (dpids == null || bridgeName == null) return;
220                 for (String dpid : dpids) {
221                     Long dpidLong = Long.valueOf(HexEncode.stringToLong(dpid));
222                     try {
223                         Node ofNode = new Node(Node.NodeIDType.OPENFLOW, dpidLong);
224                         Description descProp = new Description(bridgeName);
225                         Set<Property> props = new HashSet<Property>();
226                         props.add(descProp);
227
228                         IPluginOutInventoryService salInventoryService = (IPluginOutInventoryService) ServiceHelper.getInstance(
229                                 IPluginOutInventoryService.class, "default", this);
230                         if (salInventoryService != null) {
231                             logger.debug("Updating Bridge Name {} on OF node {}", bridgeName, ofNode);
232                             salInventoryService.updateNode(ofNode, UpdateType.CHANGED, props);
233                         } else {
234                             logger.error("Error accessing SAL Inventory plugin");
235                         }
236                     } catch (ConstructionException e) {
237                         logger.error("Failed to construct node for " + dpid, e);
238                     }
239                 }
240             }
241         };
242         executor.execute(updateNameRunnable);
243         // Add a delay & re-execute to compensate for the current OpenFlow plugin bug of
244         // overriding the Description with a Null value after the first statistics timer.
245         // Hopefully this will be resolved in the newer version of the Openflow plugin.
246         executor.schedule(updateNameRunnable, 30, TimeUnit.SECONDS);
247     }
248
249     @Override
250     public void printCache(Node n) {
251         NodeDB db = dbCache.get(n);
252         if (db != null) db.printTableCache();
253     }
254
255     @Override
256     public void addNode(Node node, Set<Property> props) {
257         addNodeProperty(node, UpdateType.ADDED, props);
258     }
259
260     @Override
261     public void notifyNodeAdded(Node node) {
262         OVSDBInventoryListener inventoryListener = (OVSDBInventoryListener)ServiceHelper.getGlobalInstance(OVSDBInventoryListener.class, this);
263         if (inventoryListener != null) {
264             inventoryListener.nodeAdded(node);
265         }
266     }
267
268     @Override
269     public void addNodeProperty(Node node, UpdateType type, Set<Property> props) {
270         Map<String, Property> nProp = nodeProps.get(node);
271         if (nProp == null) nProp = new HashMap<String, Property>();
272         for (Property prop : props) {
273             nProp.put(prop.getName(), prop);
274         }
275         nodeProps.put(node, nProp);
276         for (IPluginOutInventoryService service : pluginOutInventoryServices) {
277             service.updateNode(node, type, props);
278         }
279     }
280
281     @Override
282     public DatabaseSchema getDatabaseSchema(Node n) {
283         NodeDB db = dbCache.get(n);
284         if (db != null) return db.getSchema();
285         return null;
286     }
287
288     @Override
289     public void updateDatabaseSchema(Node n, DatabaseSchema schema) {
290         NodeDB db = dbCache.get(n);
291         if (db == null) {
292             db = new NodeDB();
293             dbCache.put(n, db);
294         }
295         db.setSchema(schema);
296     }
297
298     @Override
299     public void removeNode(Node node) {
300         OVSDBInventoryListener inventoryListener = (OVSDBInventoryListener)ServiceHelper.getGlobalInstance(OVSDBInventoryListener.class, this);
301         if (inventoryListener != null) {
302             inventoryListener.nodeRemoved(node);
303         }
304
305         for (IPluginOutInventoryService service : pluginOutInventoryServices) {
306             service.updateNode(node, UpdateType.REMOVED, null);
307         }
308         nodeProps.remove(node);
309         dbCache.remove(node);
310     }
311 }