Fixed a minor bug that causes the deprecated CSIT Integration Bridge Domain addPort...
[ovsdb.git] / plugin / src / main / java / org / opendaylight / ovsdb / plugin / impl / ConfigurationServiceImpl.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, Keith Burns
9  */
10 package org.opendaylight.ovsdb.plugin.impl;
11
12 import static org.opendaylight.ovsdb.lib.operations.Operations.op;
13
14 import java.net.InetAddress;
15 import java.net.UnknownHostException;
16 import java.util.AbstractMap;
17 import java.util.ArrayList;
18 import java.util.Collection;
19 import java.util.HashMap;
20 import java.util.HashSet;
21 import java.util.List;
22 import java.util.Map;
23 import java.util.Set;
24 import java.util.concurrent.ConcurrentMap;
25 import java.util.concurrent.ExecutionException;
26
27 import org.eclipse.osgi.framework.console.CommandInterpreter;
28 import org.eclipse.osgi.framework.console.CommandProvider;
29 import org.opendaylight.controller.clustering.services.IClusterGlobalServices;
30 import org.opendaylight.controller.sal.connection.ConnectionConstants;
31 import org.opendaylight.controller.sal.core.Node;
32 import org.opendaylight.controller.sal.core.NodeConnector;
33 import org.opendaylight.controller.sal.networkconfig.bridgedomain.ConfigConstants;
34 import org.opendaylight.controller.sal.networkconfig.bridgedomain.IPluginInBridgeDomainConfigService;
35 import org.opendaylight.controller.sal.utils.Status;
36 import org.opendaylight.controller.sal.utils.StatusCode;
37 import org.opendaylight.ovsdb.lib.OvsdbClient;
38 import org.opendaylight.ovsdb.lib.error.SchemaVersionMismatchException;
39 import org.opendaylight.ovsdb.lib.notation.Column;
40 import org.opendaylight.ovsdb.lib.notation.Mutator;
41 import org.opendaylight.ovsdb.lib.notation.OvsdbSet;
42 import org.opendaylight.ovsdb.lib.notation.ReferencedRow;
43 import org.opendaylight.ovsdb.lib.notation.Row;
44 import org.opendaylight.ovsdb.lib.notation.UUID;
45 import org.opendaylight.ovsdb.lib.operations.Insert;
46 import org.opendaylight.ovsdb.lib.operations.Operation;
47 import org.opendaylight.ovsdb.lib.operations.OperationResult;
48 import org.opendaylight.ovsdb.lib.operations.TransactionBuilder;
49 import org.opendaylight.ovsdb.lib.schema.ColumnSchema;
50 import org.opendaylight.ovsdb.lib.schema.DatabaseSchema;
51 import org.opendaylight.ovsdb.lib.schema.GenericTableSchema;
52 import org.opendaylight.ovsdb.lib.schema.TableSchema;
53 import org.opendaylight.ovsdb.lib.schema.typed.TypedBaseTable;
54 import org.opendaylight.ovsdb.plugin.OvsdbConfigService;
55 import org.opendaylight.ovsdb.plugin.api.Connection;
56 import org.opendaylight.ovsdb.plugin.api.OvsVswitchdSchemaConstants;
57 import org.opendaylight.ovsdb.plugin.api.OvsdbConfigurationService;
58 import org.opendaylight.ovsdb.plugin.api.OvsdbConnectionService;
59 import org.opendaylight.ovsdb.plugin.api.OvsdbInventoryService;
60 import org.opendaylight.ovsdb.plugin.api.StatusWithUuid;
61 import org.opendaylight.ovsdb.plugin.error.OvsdbPluginException;
62 import org.opendaylight.ovsdb.schema.openvswitch.Bridge;
63 import org.opendaylight.ovsdb.schema.openvswitch.Controller;
64 import org.opendaylight.ovsdb.schema.openvswitch.Interface;
65 import org.opendaylight.ovsdb.schema.openvswitch.Manager;
66 import org.opendaylight.ovsdb.schema.openvswitch.OpenVSwitch;
67 import org.opendaylight.ovsdb.schema.openvswitch.Port;
68 import org.osgi.framework.BundleContext;
69 import org.osgi.framework.FrameworkUtil;
70 import org.slf4j.Logger;
71 import org.slf4j.LoggerFactory;
72
73 import com.fasterxml.jackson.databind.node.ObjectNode;
74 import com.google.common.collect.ImmutableSet;
75 import com.google.common.collect.Maps;
76 import com.google.common.util.concurrent.ListenableFuture;
77
78 public class ConfigurationServiceImpl implements IPluginInBridgeDomainConfigService,
79                                                  OvsdbConfigurationService,
80                                                  OvsdbConfigService,
81                                                  CommandProvider
82 {
83     private static final Logger logger = LoggerFactory
84             .getLogger(ConfigurationServiceImpl.class);
85
86     OvsdbConnectionService connectionService;
87     OvsdbInventoryService ovsdbInventoryService;
88     boolean forceConnect = false;
89     protected static final String OPENFLOW_10 = "1.0";
90     protected static final String OPENFLOW_13 = "1.3";
91
92     void init() {
93     }
94
95     /**
96      * Function called by the dependency manager when at least one dependency
97      * become unsatisfied or when the component is shutting down because for
98      * example bundle is being stopped.
99      *
100      */
101     void destroy() {
102     }
103
104     /**
105      * Function called by dependency manager after "init ()" is called and after
106      * the services provided by the class are registered in the service registry
107      *
108      */
109     void start() {
110         registerWithOSGIConsole();
111     }
112
113     private void registerWithOSGIConsole() {
114         BundleContext bundleContext = FrameworkUtil.getBundle(this.getClass())
115                 .getBundleContext();
116         bundleContext.registerService(CommandProvider.class.getName(), this,
117                 null);
118     }
119
120     /**
121      * Function called by the dependency manager before the services exported by
122      * the component are unregistered, this will be followed by a "destroy ()"
123      * calls
124      *
125      */
126     void stop() {
127     }
128
129     public void setConnectionServiceInternal(OvsdbConnectionService connectionService) {
130         this.connectionService = connectionService;
131     }
132
133     public void unsetConnectionServiceInternal(OvsdbConnectionService connectionService) {
134         if (this.connectionService == connectionService) {
135             this.connectionService = null;
136         }
137     }
138
139     public void setOvsdbInventoryService(OvsdbInventoryService ovsdbInventoryService) {
140         this.ovsdbInventoryService = ovsdbInventoryService;
141     }
142
143     public void unsetInventoryServiceInternal(OvsdbInventoryService ovsdbInventoryService) {
144         if (this.ovsdbInventoryService == ovsdbInventoryService) {
145             this.ovsdbInventoryService = null;
146         }
147     }
148
149     private IClusterGlobalServices clusterServices;
150
151     public void setClusterServices(IClusterGlobalServices i) {
152         this.clusterServices = i;
153     }
154
155     public void unsetClusterServices(IClusterGlobalServices i) {
156         if (this.clusterServices == i) {
157             this.clusterServices = null;
158         }
159     }
160
161     private Connection getConnection (Node node) {
162         Connection connection = connectionService.getConnection(node);
163         if (connection == null || !connection.getClient().isActive()) {
164             return null;
165         }
166
167         return connection;
168     }
169     /*
170      * There are a few Open_vSwitch schema specific special case handling to be done for
171      * the older API (such as by inserting a mandatory Interface row automatically upon inserting
172      * a Port row.
173      */
174     private void handleSpecialInsertCase(OvsdbClient client, String databaseName,
175             String tableName, String uuid, Row<GenericTableSchema> row, TransactionBuilder transactionBuilder) {
176         Port port = client.getTypedRowWrapper(Port.class, null);
177         if (databaseName.equals(OvsVswitchdSchemaConstants.DATABASE_NAME) && tableName.equals(port.getSchema().getName())) {
178             port = client.getTypedRowWrapper(Port.class, row);
179             DatabaseSchema dbSchema = client.getDatabaseSchema(databaseName);
180             TableSchema<GenericTableSchema> tableSchema = dbSchema.table(tableName, GenericTableSchema.class);
181             ColumnSchema<GenericTableSchema, Set<UUID>> columnSchema = tableSchema.multiValuedColumn("interfaces", UUID.class);
182             String namedUuid = "Special_"+tableName;
183             List<Operation> priorOperations = transactionBuilder.getOperations();
184             Insert portOperation = (Insert)priorOperations.get(0);
185             portOperation.value(columnSchema, new UUID(namedUuid));
186
187             Column<GenericTableSchema, ?> nameColumn = port.getNameColumn();
188             List<Column<GenericTableSchema, ?>> columns = new ArrayList<Column<GenericTableSchema, ?>>();
189             columns.add(nameColumn);
190             Row<GenericTableSchema> intfRow = new Row<GenericTableSchema>(tableSchema, columns);
191             this.processTypedInsertTransaction(client, databaseName, "Interface", null, null, null, namedUuid, intfRow, transactionBuilder);
192         }
193     }
194
195     /*
196      * A common Transaction that takes in old API style Parent_uuid and inserts a mutation on
197      * the parent table for the newly inserted Child.
198      * Due to some additional special case(s), the Transaction is further amended by handleSpecialInsertCase
199      */
200     private void processTypedInsertTransaction(OvsdbClient client, String databaseName, String childTable,
201                                     String parentTable, String parentUuid, String parentColumn, String namedUuid,
202                                     Row<GenericTableSchema> row, TransactionBuilder transactionBuilder) {
203         this.processInsertTransaction(client, databaseName, childTable, parentTable, new UUID(parentUuid), parentColumn,
204                                       namedUuid, row, transactionBuilder);
205         /*
206          * There are a few Open_vSwitch schema specific special case handling to be done for
207          * the older API (such as by inserting a mandatory Interface row automatically upon inserting
208          * a Port row.
209          */
210         handleSpecialInsertCase(client, databaseName, childTable, namedUuid, row, transactionBuilder);
211     }
212
213     /*
214      * TODO : Move all the Special Cases out of ConfigurationService and into the Schema specific bundles.
215      * But that makes plugin more reliant on the Typed Bundles more than just API wrapper.
216      * Keeping these Special Handling locally till we introduce the full schema independent APIs in the
217      * plugin layer.
218      */
219     public String getSpecialCaseParentUUID(Node node, String databaseName, String childTableName) {
220         if (!databaseName.equals(OvsVswitchdSchemaConstants.DATABASE_NAME)) return null;
221         String[] parentColumn = OvsVswitchdSchemaConstants.getParentColumnToMutate(childTableName);
222         if (parentColumn != null && parentColumn[0].equals(OvsVswitchdSchemaConstants.DATABASE_NAME)) {
223             Connection connection = connectionService.getConnection(node);
224             OpenVSwitch openVSwitch = connection.getClient().getTypedRowWrapper(OpenVSwitch.class, null);
225             ConcurrentMap<String, Row> row = this.getRows(node, openVSwitch.getSchema().getName());
226             if (row == null || row.size() == 0) return null;
227             return (String)row.keySet().toArray()[0];
228         }
229         return null;
230     }
231
232     /*
233      * Though this is a New API that takes in Row object, this still is considered a
234      * Deprecated call because of the assumption with a Single Row insertion.
235      * An ideal insertRow must be able to take in multiple Rows, which includes the
236      * Row being inserted in one Table and other Rows that needs mutate in other Tables.
237      */
238     @Override
239     @Deprecated
240     public StatusWithUuid insertRow(Node node, String tableName, String parentUuid, Row<GenericTableSchema> row) {
241         String[] parentColumn = OvsVswitchdSchemaConstants.getParentColumnToMutate(tableName);
242         if (parentColumn == null) {
243             parentColumn = new String[]{null, null};
244         }
245
246         Connection connection = connectionService.getConnection(node);
247         OvsdbClient client = connection.getClient();
248
249         if (parentUuid == null) {
250             parentUuid = this.getSpecialCaseParentUUID(node, OvsVswitchdSchemaConstants.DATABASE_NAME, tableName);
251         }
252         logger.debug("insertRow Connection : {} Table : {} ParentTable : {} Parent Column: {} Parent UUID : {} Row : {}",
253                      client.getConnectionInfo(), tableName, parentColumn[0], parentColumn[1], parentUuid, row);
254
255         DatabaseSchema dbSchema = client.getDatabaseSchema(OvsVswitchdSchemaConstants.DATABASE_NAME);
256         TransactionBuilder transactionBuilder = client.transactBuilder(dbSchema);
257
258         String namedUuid = "Transaction_"+ tableName;
259         this.processTypedInsertTransaction(client, OvsVswitchdSchemaConstants.DATABASE_NAME, tableName,
260                                 parentColumn[0], parentUuid, parentColumn[1], namedUuid,
261                                 row, transactionBuilder);
262
263         ListenableFuture<List<OperationResult>> results = transactionBuilder.execute();
264         List<OperationResult> operationResults;
265         try {
266             operationResults = results.get();
267             if (operationResults.isEmpty() || (transactionBuilder.getOperations().size() != operationResults.size())) {
268                 return new StatusWithUuid(StatusCode.INTERNALERROR);
269             }
270             for (OperationResult result : operationResults) {
271                 if (result.getError() != null) {
272                     return new StatusWithUuid(StatusCode.BADREQUEST, result.getError());
273                 }
274             }
275             UUID uuid = operationResults.get(0).getUuid();
276             return new StatusWithUuid(StatusCode.SUCCESS, uuid);
277         } catch (InterruptedException | ExecutionException e) {
278             // TODO Auto-generated catch block
279             return new StatusWithUuid(StatusCode.INTERNALERROR, e.getLocalizedMessage());
280         }
281
282     }
283
284     @Override
285     @Deprecated
286     public Status updateRow (Node node, String tableName, String parentUUID, String rowUUID, Row row) {
287         String databaseName = OvsVswitchdSchemaConstants.DATABASE_NAME;
288         Connection connection = connectionService.getConnection(node);
289         OvsdbClient client = connection.getClient();
290
291         logger.debug("updateRow : Connection : {} databaseName : {} tableName : {} rowUUID : {} row : {}",
292                       client.getConnectionInfo(), databaseName, tableName, rowUUID, row.toString());
293         try{
294             DatabaseSchema dbSchema = client.getDatabaseSchema(databaseName);
295             TransactionBuilder transactionBuilder = client.transactBuilder(dbSchema);
296             TableSchema<GenericTableSchema> tableSchema = dbSchema.table(tableName, GenericTableSchema.class);
297             ColumnSchema<GenericTableSchema, UUID> _uuid = tableSchema.column("_uuid", UUID.class);
298             transactionBuilder.add(op.update(tableSchema, row)
299                                      .where(_uuid.opEqual(new UUID(rowUUID)))
300                                      .build());
301
302             ListenableFuture<List<OperationResult>> results = transactionBuilder.execute();
303             List<OperationResult> operationResults = results.get();
304             if (operationResults.isEmpty() || (transactionBuilder.getOperations().size() != operationResults.size())) {
305                 return new StatusWithUuid(StatusCode.INTERNALERROR);
306             }
307             for (OperationResult result : operationResults) {
308                 if (result.getError() != null) {
309                     return new StatusWithUuid(StatusCode.BADREQUEST, result.getError());
310                 }
311             }
312             return new StatusWithUuid(StatusCode.SUCCESS);
313         } catch(Exception e){
314             logger.error("Error in updateRow(): ",e);
315         }
316         return new Status(StatusCode.INTERNALERROR);
317     }
318
319     private void processDeleteTransaction(OvsdbClient client, String databaseName, String childTable,
320                                     String parentTable, String parentColumn, String uuid, TransactionBuilder transactionBuilder) {
321         DatabaseSchema dbSchema = client.getDatabaseSchema(databaseName);
322         TableSchema<GenericTableSchema> childTableSchema = dbSchema.table(childTable, GenericTableSchema.class);
323
324         if (parentColumn != null) {
325             TableSchema<GenericTableSchema> parentTableSchema = dbSchema.table(parentTable, GenericTableSchema.class);
326             ColumnSchema<GenericTableSchema, UUID> parentColumnSchema = parentTableSchema.column(parentColumn, UUID.class);
327             transactionBuilder
328                 .add(op.mutate(parentTableSchema)
329                         .addMutation(parentColumnSchema, Mutator.DELETE, new UUID(uuid))
330                         .where(parentColumnSchema.opIncludes(new UUID(uuid)))
331                         .build());
332         }
333
334         ColumnSchema<GenericTableSchema, UUID> _uuid = childTableSchema.column("_uuid", UUID.class);
335         transactionBuilder.add(op.delete(childTableSchema)
336                 .where(_uuid.opEqual(new UUID(uuid)))
337                 .build());
338     }
339
340     @Override
341     @Deprecated
342     public Status deleteRow(Node node, String tableName, String uuid) {
343         String databaseName = OvsVswitchdSchemaConstants.DATABASE_NAME;
344         Connection connection = connectionService.getConnection(node);
345         OvsdbClient client = connection.getClient();
346
347         String[] parentColumn = OvsVswitchdSchemaConstants.getParentColumnToMutate(tableName);
348         if (parentColumn == null) {
349             parentColumn = new String[]{null, null};
350         }
351
352         logger.debug("deleteRow : Connection : {} databaseName : {} tableName : {} Uuid : {} ParentTable : {} ParentColumn : {}",
353                 client.getConnectionInfo(), databaseName, tableName, uuid, parentColumn[0], parentColumn[1]);
354
355         DatabaseSchema dbSchema = client.getDatabaseSchema(databaseName);
356         TransactionBuilder transactionBuilder = client.transactBuilder(dbSchema);
357         this.processDeleteTransaction(client, OvsVswitchdSchemaConstants.DATABASE_NAME, tableName,
358                                       parentColumn[0], parentColumn[1], uuid, transactionBuilder);
359
360         ListenableFuture<List<OperationResult>> results = transactionBuilder.execute();
361         List<OperationResult> operationResults;
362         try {
363             operationResults = results.get();
364             if (operationResults.isEmpty() || (transactionBuilder.getOperations().size() != operationResults.size())) {
365                 return new StatusWithUuid(StatusCode.INTERNALERROR);
366             }
367             for (OperationResult result : operationResults) {
368                 if (result.getError() != null) {
369                     return new StatusWithUuid(StatusCode.BADREQUEST, result.getError());
370                 }
371             }
372         } catch (InterruptedException | ExecutionException e) {
373             // TODO Auto-generated catch block
374             e.printStackTrace();
375         }
376
377         return new Status(StatusCode.SUCCESS);
378     }
379
380     @Override
381     @Deprecated
382     public ConcurrentMap<String, Row> getRows(Node node, String tableName) {
383         ConcurrentMap<String, Row> ovsTable = ovsdbInventoryService.getTableCache(node, OvsVswitchdSchemaConstants.DATABASE_NAME,  tableName);
384         return ovsTable;
385     }
386
387     @Override
388     @Deprecated
389     public Row getRow(Node node, String tableName, String uuid) {
390         Map<String, Row> ovsTable = ovsdbInventoryService.getTableCache(node, OvsVswitchdSchemaConstants.DATABASE_NAME,  tableName);
391         if (ovsTable == null) return null;
392         return ovsTable.get(uuid);
393     }
394
395     @Override
396     @Deprecated
397     public List<String> getTables(Node node) {
398         ConcurrentMap<String, ConcurrentMap<String, Row>> cache  = ovsdbInventoryService.getCache(node, OvsVswitchdSchemaConstants.DATABASE_NAME);
399         if (cache == null) return null;
400         return new ArrayList<String>(cache.keySet());
401     }
402
403     private List<InetAddress> getControllerIPAddresses(Connection connection) {
404         List<InetAddress> controllers = null;
405         InetAddress controllerIP = null;
406
407         controllers = new ArrayList<InetAddress>();
408         String addressString = System.getProperty("ovsdb.controller.address");
409
410         if (addressString != null) {
411             try {
412                 controllerIP = InetAddress.getByName(addressString);
413                 if (controllerIP != null) {
414                     controllers.add(controllerIP);
415                     return controllers;
416                 }
417             } catch (UnknownHostException e) {
418                 logger.error("Host {} is invalid", addressString);
419             }
420         }
421
422         if (clusterServices != null) {
423             controllers = clusterServices.getClusteredControllers();
424             if (controllers != null && controllers.size() > 0) {
425                 if (controllers.size() == 1) {
426                     InetAddress controller = controllers.get(0);
427                     if (!controller.equals(InetAddress.getLoopbackAddress())) {
428                         return controllers;
429                     }
430                 } else {
431                     return controllers;
432                 }
433             }
434         }
435
436         addressString = System.getProperty("of.address");
437
438         if (addressString != null) {
439             try {
440                 controllerIP = InetAddress.getByName(addressString);
441                 if (controllerIP != null) {
442                     controllers.add(controllerIP);
443                     return controllers;
444                 }
445             } catch (UnknownHostException e) {
446                 logger.error("Host {} is invalid", addressString);
447             }
448         }
449
450         try {
451             controllerIP = connection.getClient().getConnectionInfo().getLocalAddress();
452             controllers.add(controllerIP);
453             return controllers;
454         } catch (Exception e) {
455             logger.debug("Invalid connection provided to getControllerIPAddresses", e);
456         }
457         return controllers;
458     }
459
460     private short getControllerOFPort() {
461         Short defaultOpenFlowPort = 6633;
462         Short openFlowPort = defaultOpenFlowPort;
463         String portString = System.getProperty("of.listenPort");
464         if (portString != null) {
465             try {
466                 openFlowPort = Short.decode(portString).shortValue();
467             } catch (NumberFormatException e) {
468                 logger.warn("Invalid port:{}, use default({})", portString,
469                         openFlowPort);
470             }
471         }
472         return openFlowPort;
473     }
474
475     @Override
476     public Boolean setOFController(Node node, String bridgeUUID) throws InterruptedException, ExecutionException {
477         Connection connection = this.getConnection(node);
478         if (connection == null) {
479             return false;
480         }
481
482         Bridge bridge = connection.getClient().createTypedRowWrapper(Bridge.class);
483
484         Status updateOperationStatus = null;
485         try {
486             OvsdbSet<String> protocols = new OvsdbSet<String>();
487
488             String ofVersion = System.getProperty("ovsdb.of.version", OPENFLOW_10);
489             switch (ofVersion) {
490                 case OPENFLOW_13:
491                     protocols.add("OpenFlow13");
492                     break;
493                 case OPENFLOW_10:
494                     //fall through
495                 default:
496                     protocols.add("OpenFlow10");
497                     break;
498             }
499             bridge.setProtocols(protocols);
500             updateOperationStatus = this.updateRow(node, bridge.getSchema().getName(),
501                                                    null, bridgeUUID, bridge.getRow());
502             logger.debug("Bridge {} updated to {} with Status {}", bridgeUUID,
503                          protocols.toArray()[0],updateOperationStatus);
504
505         } catch (SchemaVersionMismatchException e){
506             logger.debug(e.toString());
507         }
508
509         // If we fail to update the protocols
510         if (updateOperationStatus != null && !updateOperationStatus.isSuccess()) {
511             return updateOperationStatus.isSuccess();
512         }
513
514         Status status = null;
515         List<InetAddress> ofControllerAddrs = this.getControllerIPAddresses(connection);
516         short ofControllerPort = getControllerOFPort();
517         for (InetAddress ofControllerAddress : ofControllerAddrs) {
518             String newController = "tcp:"+ofControllerAddress.getHostAddress()+":"+ofControllerPort;
519             Controller controllerRow = connection.getClient().createTypedRowWrapper(Controller.class);
520             controllerRow.setTarget(newController);
521             //ToDo: Status gets overwritten on each iteration. If any operation other than the last fails it's ignored.
522             status = this.insertRow(node, controllerRow.getSchema().getName(), bridgeUUID, controllerRow.getRow());
523         }
524
525         if (status != null) {
526             return status.isSuccess();
527         }
528
529         return false;
530     }
531
532
533     public Boolean setBridgeOFController(Node node, String bridgeIdentifier) {
534         if (connectionService == null) {
535             logger.error("Couldn't refer to the ConnectionService");
536             return false;
537         }
538
539         try{
540             Connection connection = connectionService.getConnection(node);
541             Bridge bridge = connection.getClient().getTypedRowWrapper(Bridge.class, null);
542
543             Map<String, Row> brTableCache = ovsdbInventoryService.getTableCache(node, OvsVswitchdSchemaConstants.DATABASE_NAME, bridge.getSchema().getName());
544             for (String uuid : brTableCache.keySet()) {
545                 bridge = connection.getClient().getTypedRowWrapper(Bridge.class, brTableCache.get(uuid));
546                 if (bridge.getName().contains(bridgeIdentifier)) {
547                     return setOFController(node, uuid);
548                 }
549             }
550         } catch(Exception e) {
551             logger.error("Error in setBridgeOFController()",e);
552         }
553         return false;
554     }
555
556     @Override
557     public <T extends TypedBaseTable<?>> String getTableName(Node node, Class<T> typedClass) {
558         Connection connection = connectionService.getConnection(node);
559         if (connection == null) return null;
560         OvsdbClient client = connection.getClient();
561         TypedBaseTable<?> typedTable = client.getTypedRowWrapper(typedClass, null);
562         if (typedTable == null) return null;
563         return typedTable.getSchema().getName();
564     }
565
566     @Override
567     public <T extends TypedBaseTable<?>> T getTypedRow(Node node, Class<T> typedClass, Row row) {
568         Connection connection = connectionService.getConnection(node);
569         if (connection == null) return null;
570         OvsdbClient client = connection.getClient();
571         return (T)client.getTypedRowWrapper(typedClass, row);
572     }
573
574     @Override
575     public <T extends TypedBaseTable<?>> T createTypedRow(Node node, Class<T> typedClass) {
576         Connection connection = connectionService.getConnection(node);
577         if (connection == null) return null;
578         OvsdbClient client = connection.getClient();
579         return client.createTypedRowWrapper(typedClass);
580     }
581
582     public void _ovsconnect (CommandInterpreter ci) {
583         String bridgeName = ci.nextArgument();
584         if (bridgeName == null) {
585             ci.println("Please enter Bridge Name");
586             return;
587         }
588
589         String ovsdbserver = ci.nextArgument();
590         if (ovsdbserver == null) {
591             ci.println("Please enter valid IP-Address");
592             return;
593         }
594         try {
595             InetAddress.getByName(ovsdbserver);
596         }  catch (UnknownHostException e) {
597             logger.error("Unable to resolve " + ovsdbserver, e);
598             ci.println("Please enter valid IP-Address");
599             return;
600         }
601         String port = ci.nextArgument();
602         if (port == null) {
603             port = "6634";
604         }
605
606         ci.println("connecting to ovsdb server : "+ovsdbserver+":"+port+" ... ");
607         Map<ConnectionConstants, String> params = new HashMap<ConnectionConstants, String>();
608         params.put(ConnectionConstants.ADDRESS, ovsdbserver);
609         params.put(ConnectionConstants.PORT, port);
610         Node node = connectionService.connect(bridgeName, params);
611         if (node != null) ci.println("Node Name: "+node.toString());
612         else ci.println("Could not connect to Node");
613     }
614
615     public void _addBridge (CommandInterpreter ci) {
616         String nodeName = ci.nextArgument();
617         if (nodeName == null) {
618             ci.println("Please enter Node Name");
619             return;
620         }
621         String bridgeName = ci.nextArgument();
622         if (bridgeName == null) {
623             ci.println("Please enter Bridge Name");
624             return;
625         }
626         Status status;
627
628         Node node = Node.fromString(nodeName);
629         if (node == null) {
630             ci.println("Invalid Node");
631             return;
632         }
633         status = this.createBridgeDomain(node, bridgeName, null);
634         ci.println("Bridge creation status : "+status.toString());
635     }
636
637     public void _getBridgeDomains (CommandInterpreter ci) {
638         String nodeName = ci.nextArgument();
639         if (nodeName == null) {
640             ci.println("Please enter Node Name");
641             return;
642         }
643
644         List<String> brlist = new ArrayList<String>();
645         Node node = Node.fromString(nodeName);
646         brlist = this.getBridgeDomains(node);
647         if (node == null) {
648             ci.println("Invalid Node");
649             return;
650         }
651         ci.println("Existing Bridges: "+brlist.toString());
652     }
653
654     public void _deleteBridgeDomain (CommandInterpreter ci) {
655         String nodeName = ci.nextArgument();
656         if (nodeName == null) {
657             ci.println("Please enter Node Name");
658             return;
659         }
660         String bridgeName = ci.nextArgument();
661         if (bridgeName == null) {
662             ci.println("Please enter Bridge Name");
663             return;
664         }
665         Status status;
666         Node node = Node.fromString(nodeName);
667         if (node == null) {
668             ci.println("Invalid Node");
669             return;
670         }
671         status = this.deleteBridgeDomain(node, bridgeName);
672         ci.println("Bridge deletion status : "+status.toString());
673     }
674
675     public void _addPort (CommandInterpreter ci) {
676         String nodeName = ci.nextArgument();
677         if (nodeName == null) {
678             ci.println("Please enter Node Name");
679             return;
680         }
681
682         String bridgeName = ci.nextArgument();
683         if (bridgeName == null) {
684             ci.println("Please enter Bridge Name");
685             return;
686         }
687
688         String portName = ci.nextArgument();
689         if (portName == null) {
690             ci.println("Please enter Port Name");
691             return;
692         }
693
694         String type = ci.nextArgument();
695
696         Map<String, String> configs = new HashMap<String, String>();
697         while(true) {
698             String configKey = ci.nextArgument();
699             if (configKey == null) break;
700             String configValue = ci.nextArgument();
701             if (configValue == null) break;
702             configs.put(configKey, configValue);
703         }
704
705         Map<ConfigConstants, Object> customConfigs = null;
706         if (type != null) {
707             customConfigs = new HashMap<ConfigConstants, Object>();
708             customConfigs.put(ConfigConstants.TYPE, type);
709         }
710
711         if (configs.size() > 0) {
712             if (customConfigs == null) customConfigs = new HashMap<ConfigConstants, Object>();
713             customConfigs.put(ConfigConstants.CUSTOM, configs);
714             ci.println(customConfigs.toString());
715         }
716         Status status;
717         Node node = Node.fromString(nodeName);
718         if (node == null) {
719             ci.println("Invalid Node");
720             return;
721         }
722         status = this.addPort(node, bridgeName, portName, customConfigs);
723         ci.println("Port creation status : "+status.toString());
724     }
725
726     public void _deletePort (CommandInterpreter ci) {
727         String nodeName = ci.nextArgument();
728         if (nodeName == null) {
729             ci.println("Please enter Node Name");
730             return;
731         }
732
733         String bridgeName = ci.nextArgument();
734         if (bridgeName == null) {
735             ci.println("Please enter Bridge Name");
736             return;
737         }
738
739         String portName = ci.nextArgument();
740         if (portName == null) {
741             ci.println("Please enter Port Name");
742             return;
743         }
744
745         Status status;
746         Node node = Node.fromString(nodeName);
747         if (node == null) {
748             ci.println("Invalid Node");
749             return;
750         }
751         status = this.deletePort(node, bridgeName, portName);
752         ci.println("Port deletion status : "+status.toString());
753     }
754
755     public void _addPortVlan (CommandInterpreter ci) {
756         String nodeName = ci.nextArgument();
757         if (nodeName == null) {
758             ci.println("Please enter Node Name");
759             return;
760         }
761
762         String bridgeName = ci.nextArgument();
763         if (bridgeName == null) {
764             ci.println("Please enter Bridge Name");
765             return;
766         }
767
768         String portName = ci.nextArgument();
769         if (portName == null) {
770             ci.println("Please enter Port Name");
771             return;
772         }
773
774         String vlan = ci.nextArgument();
775         if (vlan == null) {
776             ci.println("Please enter Valid Vlan");
777             return;
778         } else {
779             try {
780             Integer.parseInt(vlan);
781             } catch (NumberFormatException e) {
782                 ci.println("Please enter Valid Vlan");
783                 return;
784             }
785         }
786
787         Map<ConfigConstants, Object> configs = new HashMap<ConfigConstants, Object>();
788         configs.put(ConfigConstants.TYPE, "VLAN");
789         configs.put(ConfigConstants.VLAN, vlan);
790
791         Status status;
792         Node node = Node.fromString(nodeName);
793         if (node == null) {
794             ci.println("Invalid Node");
795             return;
796         }
797         status = this.addPort(node, bridgeName, portName, configs);
798         ci.println("Port creation status : "+status.toString());
799     }
800
801     public void _addTunnel (CommandInterpreter ci) {
802         String nodeName = ci.nextArgument();
803         if (nodeName == null) {
804             ci.println("Please enter Node Name");
805             return;
806         }
807
808         String bridgeName = ci.nextArgument();
809         if (bridgeName == null) {
810             ci.println("Please enter Bridge Name");
811             return;
812         }
813
814         String portName = ci.nextArgument();
815         if (portName == null) {
816             ci.println("Please enter Port Name");
817             return;
818         }
819
820         String tunnelType = ci.nextArgument();
821         if (tunnelType == null) {
822             ci.println("Please enter Tunnel Type");
823             return;
824         }
825
826         String remoteIp = ci.nextArgument();
827         if (remoteIp == null) {
828             ci.println("Please enter valid Remote IP Address");
829             return;
830         }
831
832         try {
833             InetAddress.getByName(remoteIp);
834         }  catch (Exception e) {
835             logger.error("Unable to resolve " + remoteIp, e);
836             ci.println("Please enter valid Remote IP Address");
837             return;
838         }
839
840         Map<ConfigConstants, Object> configs = new HashMap<ConfigConstants, Object>();
841         configs.put(ConfigConstants.TYPE, "TUNNEL");
842         configs.put(ConfigConstants.TUNNEL_TYPE, tunnelType);
843         configs.put(ConfigConstants.DEST_IP, remoteIp);
844
845         Status status;
846         Node node = Node.fromString(nodeName);
847         if (node == null) {
848             ci.println("Invalid Node");
849             return;
850         }
851         status = this.addPort(node, bridgeName, portName, configs);
852         ci.println("Port creation status : "+status.toString());
853     }
854
855     public void _printCache (CommandInterpreter ci) {
856         String nodeName = ci.nextArgument();
857         if (nodeName == null) {
858             ci.println("Please enter Node Name");
859             return;
860         }
861         Node node = Node.fromString(nodeName);
862         if (node == null) {
863             ci.println("Invalid Node");
864             return;
865         }
866         ovsdbInventoryService.printCache(node);
867     }
868
869     public void _forceConnect (CommandInterpreter ci) {
870         String force = ci.nextArgument();
871         if (force.equalsIgnoreCase("YES")) {
872             forceConnect = true;
873         }
874         else if (force.equalsIgnoreCase("NO")) {
875             forceConnect = false;
876         }
877         else {
878             ci.println("Please enter YES or NO.");
879         }
880         ci.println("Current ForceConnect State : "+forceConnect);
881     }
882
883     @Override
884     public String getHelp() {
885         StringBuilder help = new StringBuilder();
886         help.append("---OVSDB CLI---\n");
887         help.append("\t ovsconnect <ConnectionName> <ip-address>                        - Connect to OVSDB\n");
888         help.append("\t addBridge <Node> <BridgeName>                                   - Add Bridge\n");
889         help.append("\t getBridgeDomains <Node>                                         - Get Bridges\n");
890         help.append("\t deleteBridgeDomain <Node> <BridgeName>                          - Delete a Bridge\n");
891         help.append("\t addPort <Node> <BridgeName> <PortName> <type> <options pairs>   - Add Port\n");
892         help.append("\t deletePort <Node> <BridgeName> <PortName>                       - Delete Port\n");
893         help.append("\t addPortVlan <Node> <BridgeName> <PortName> <vlan>               - Add Port, Vlan\n");
894         help.append("\t addTunnel <Node> <Bridge> <Port> <tunnel-type> <remote-ip>      - Add Tunnel\n");
895         help.append("\t printCache <Node>                                               - Prints Table Cache");
896         return help.toString();
897     }
898
899
900     /**
901      * Add a new bridge
902      * @param node Node serving this configuration service
903      * @param bridgeIdentifier String representation of a Bridge Connector
904      * @return Bridge Connector configurations
905      */
906     @Override
907     @Deprecated
908     public Status createBridgeDomain(Node node, String bridgeIdentifier, Map<ConfigConstants, Object> configs) {
909         Connection connection = connectionService.getConnection(node);
910         OvsdbClient client = connection.getClient();
911         Bridge bridge = client.createTypedRowWrapper(Bridge.class);
912         bridge.setName(bridgeIdentifier);
913
914         String ovsTableUuid = this.getSpecialCaseParentUUID(node, OvsVswitchdSchemaConstants.DATABASE_NAME, bridge.getSchema().getName());
915         return this.insertRow(node, bridge.getSchema().getName(), ovsTableUuid, bridge.getRow());
916     }
917
918     /**
919      * Create a Port Attached to a Bridge
920      * Ex. ovs-vsctl add-port br0 vif0
921      * @param node Node serving this configuration service
922      * @param bridgeIdentifier String representation of a Bridge Domain
923      * @param portIdentifier String representation of a user defined Port Name
924      */
925     @Override
926     @Deprecated
927     public Status addPort(Node node, String bridgeIdentifier, String portIdentifier,
928                           Map<ConfigConstants, Object> configs) {
929         Connection connection = connectionService.getConnection(node);
930         OvsdbClient client = connection.getClient();
931
932         Bridge bridge = client.getTypedRowWrapper(Bridge.class, null);
933         ConcurrentMap<String, Row> rows = this.getRows(node, bridge.getSchema().getName());
934         if (rows == null || rows.size() == 0) {
935             return new Status(StatusCode.NOTFOUND);
936         }
937         for (String bridgeUuid : rows.keySet()) {
938             Row bridgeRow = rows.get(bridgeUuid);
939             bridge = client.getTypedRowWrapper(Bridge.class, bridgeRow);
940             if (bridge.getName().equals(bridgeIdentifier)) break;
941         }
942         if (bridge.getName() == null || !bridge.getName().equals(bridgeIdentifier)) {
943             return new Status(StatusCode.NOTFOUND);
944         }
945
946         Map<String, String> options = null;
947         String type = null;
948         Set<Long> tags = null;
949         if (configs != null) {
950             type = (String) configs.get(ConfigConstants.TYPE);
951             Map<String, String> customConfigs = (Map<String, String>) configs.get(ConfigConstants.CUSTOM);
952             if (customConfigs != null) {
953                 options = new HashMap<String, String>();
954                 for (String customConfig : customConfigs.keySet()) {
955                     options.put(customConfig, customConfigs.get(customConfig));
956                 }
957             }
958         }
959
960         if (type != null) {
961             logger.debug("Port type : " + type);
962             if (type.equalsIgnoreCase(OvsVswitchdSchemaConstants.PortType.VLAN.name())) {
963                 tags = new HashSet<Long>();
964                 tags.add(Long.parseLong((String)configs.get(ConfigConstants.VLAN)));
965             }
966         }
967
968         Port port = client.createTypedRowWrapper(Port.class);
969         port.setName(portIdentifier);
970         if (tags != null) port.setTag(tags);
971         StatusWithUuid portStatus = this.insertRow(node, port.getSchema().getName(), bridge.getUuid().toString(), port.getRow());
972
973         if (!portStatus.isSuccess()) return portStatus;
974         // Ugly hack by adding a sleep for the Monitor Update to catch up.
975         // TODO : Remove this once the Select operation is in place.
976         // We are currently relying on the local Cache for any GET operation and that might fail if we try to
977         // fetch the last installed entry. Hence we need the Select operation to work.
978
979         try {
980             Thread.sleep(2000);
981         } catch (InterruptedException e) {
982             // TODO Auto-generated catch block
983             e.printStackTrace();
984         }
985
986         Interface interfaceRow = client.createTypedRowWrapper(Interface.class);
987         ConcurrentMap<String, Row> intfRows = this.getRows(node, interfaceRow.getSchema().getName());
988         if (intfRows == null || intfRows.size() == 0) {
989             return new Status(StatusCode.NOTFOUND);
990         }
991         for (String intfUuid : intfRows.keySet()) {
992             Row intfRow = intfRows.get(intfUuid);
993             interfaceRow = client.getTypedRowWrapper(Interface.class, intfRow);
994             if (interfaceRow == null || interfaceRow.getName() == null) continue;
995             if (interfaceRow.getName().equals(portIdentifier)) break;
996         }
997         if (interfaceRow.getName() == null || !interfaceRow.getName().equals(portIdentifier)) {
998             return new Status(StatusCode.NOTFOUND);
999         }
1000         Interface updateInterface = client.createTypedRowWrapper(Interface.class);
1001         if (type != null) {
1002             logger.debug("Interface type : " + type);
1003             if (type.equalsIgnoreCase(OvsVswitchdSchemaConstants.PortType.TUNNEL.name())) {
1004                 updateInterface.setType((String)configs.get(ConfigConstants.TUNNEL_TYPE));
1005                 if (options == null) options = new HashMap<String, String>();
1006                 options.put("remote_ip", (String)configs.get(ConfigConstants.DEST_IP));
1007             } else if (type.equalsIgnoreCase(OvsVswitchdSchemaConstants.PortType.PATCH.name()) ||
1008                        type.equalsIgnoreCase(OvsVswitchdSchemaConstants.PortType.INTERNAL.name())) {
1009                 updateInterface.setType(type.toLowerCase());
1010             }
1011         }
1012         if (options != null) {
1013             updateInterface.setOptions(options);
1014         }
1015
1016         Status intfStatus = null;
1017         intfStatus = this.updateRow(node, interfaceRow.getSchema().getName(), portStatus.getUuid().toString(),
1018                                     interfaceRow.getUuid().toString(), updateInterface.getRow());
1019
1020         if (intfStatus.isSuccess()) return portStatus;
1021         return intfStatus;
1022     }
1023
1024     /**
1025      * Implements the OVS Connection for Managers
1026      *
1027      * @param node Node serving this configuration service
1028      * @param managerip String Representing IP and connection types
1029      */
1030     @SuppressWarnings("unchecked")
1031     @Deprecated
1032     public boolean setManager(Node node, String managerip) {
1033         Connection connection = connectionService.getConnection(node);
1034         OvsdbClient client = connection.getClient();
1035         Manager manager = client.createTypedRowWrapper(Manager.class);
1036         manager.setTarget(ImmutableSet.of(managerip));
1037
1038         OpenVSwitch openVSwitch = connection.getClient().getTypedRowWrapper(OpenVSwitch.class, null);
1039         ConcurrentMap<String, Row> row = this.getRows(node, openVSwitch.getSchema().getName());
1040         if (row == null || row.size() == 0) {
1041             return false;
1042         }
1043         String ovsTableUuid = (String)row.keySet().toArray()[0];
1044
1045         Status status = this.insertRow(node, manager.getSchema().getName(), ovsTableUuid, manager.getRow());
1046         return status.isSuccess();
1047     }
1048
1049     @Override
1050     @Deprecated
1051     public Status addBridgeDomainConfig(Node node, String bridgeIdentfier,
1052             Map<ConfigConstants, Object> configs) {
1053         String mgmt = (String)configs.get(ConfigConstants.MGMT);
1054         if (mgmt != null) {
1055             if (setManager(node, mgmt)) return new Status(StatusCode.SUCCESS);
1056         }
1057         return new Status(StatusCode.BADREQUEST);
1058     }
1059
1060     @Override
1061     @Deprecated
1062     public Status deletePort(Node node, String bridgeIdentifier, String portIdentifier) {
1063         Connection connection = connectionService.getConnection(node);
1064         OvsdbClient client = connection.getClient();
1065
1066         Port port = client.getTypedRowWrapper(Port.class, null);
1067         ConcurrentMap<String, Row> rows = this.getRows(node, port.getSchema().getName());
1068         if (rows == null || rows.size() == 0) {
1069             return new Status(StatusCode.NOTFOUND);
1070         }
1071         for (String portUuid : rows.keySet()) {
1072             Row portRow = rows.get(portUuid);
1073             port = client.getTypedRowWrapper(Port.class, portRow);
1074             if (port.getName().equals(portIdentifier)) break;
1075         }
1076         if (port.getName() == null || !port.getName().equals(portIdentifier)) {
1077             return new Status(StatusCode.NOTFOUND);
1078         }
1079         return this.deleteRow(node, port.getSchema().getName(), port.getUuid().toString());
1080     }
1081
1082     @Override
1083     @Deprecated
1084     public Status deleteBridgeDomain(Node node, String bridgeIdentifier) {
1085         Connection connection = connectionService.getConnection(node);
1086         OvsdbClient client = connection.getClient();
1087
1088         Bridge bridge = client.getTypedRowWrapper(Bridge.class, null);
1089         ConcurrentMap<String, Row> rows = this.getRows(node, bridge.getSchema().getName());
1090         if (rows == null || rows.size() == 0) {
1091             return new Status(StatusCode.NOTFOUND);
1092         }
1093         for (String bridgeUuid : rows.keySet()) {
1094             Row bridgeRow = rows.get(bridgeUuid);
1095             bridge = client.getTypedRowWrapper(Bridge.class, bridgeRow);
1096             if (bridge.getName().equals(bridgeIdentifier)) break;
1097         }
1098         if (bridge.getName() == null || !bridge.getName().equals(bridgeIdentifier)) {
1099             return new Status(StatusCode.NOTFOUND);
1100         }
1101         return this.deleteRow(node, bridge.getSchema().getName(), bridge.getUuid().toString());
1102     }
1103
1104     @Override
1105     public List<String> getBridgeDomains(Node node) {
1106         if (connectionService == null) {
1107             logger.error("Couldn't refer to the ConnectionService");
1108             return null;
1109         }
1110
1111         Connection connection = connectionService.getConnection(node);
1112         Bridge bridge = connection.getClient().getTypedRowWrapper(Bridge.class, null);
1113         List<String> brlist = new ArrayList<String>();
1114         Map<String, Row> brTableCache = ovsdbInventoryService.getTableCache(node, OvsVswitchdSchemaConstants.DATABASE_NAME, bridge.getSchema().getName());
1115         if(brTableCache != null){
1116             for (String uuid : brTableCache.keySet()) {
1117                 bridge = connection.getClient().getTypedRowWrapper(Bridge.class, brTableCache.get(uuid));
1118                 brlist.add(bridge.getName());
1119             }
1120         }
1121         return brlist;
1122     }
1123
1124     @Override
1125     public NodeConnector getNodeConnector(Node arg0, String arg1, String arg2) {
1126         return null;
1127     }
1128
1129     @Override
1130     @Deprecated
1131     public Status addPortConfig(Node node, String bridgeIdentifier, String portIdentifier,
1132             Map<ConfigConstants, Object> configs) {
1133         // TODO Auto-generated method stub
1134         return null;
1135     }
1136
1137     @Override
1138     @Deprecated
1139     public Node getBridgeDomainNode(Node node, String bridgeIdentifier) {
1140         // TODO Auto-generated method stub
1141         return null;
1142     }
1143
1144     @Override
1145     @Deprecated
1146     public Map<ConfigConstants, Object> getPortConfigs(Node node, String bridgeIdentifier,
1147             String portIdentifier) {
1148         // TODO Auto-generated method stub
1149         return null;
1150     }
1151
1152     @Override
1153     @Deprecated
1154     public Status removeBridgeDomainConfig(Node node, String bridgeIdentifier,
1155             Map<ConfigConstants, Object> configs) {
1156         // TODO Auto-generated method stub
1157         return null;
1158     }
1159
1160     @Override
1161     @Deprecated
1162     public Status removePortConfig(Node node, String bridgeIdentifier, String portIdentifier,
1163             Map<ConfigConstants, Object> configs) {
1164         // TODO Auto-generated method stub
1165         return null;
1166     }
1167
1168     @Override
1169     @Deprecated
1170     public Map<ConfigConstants, Object> getBridgeDomainConfigs(Node node, String bridgeIdentifier) {
1171         // TODO Auto-generated method stub
1172         return null;
1173     }
1174
1175
1176     // SCHEMA-INDEPENDENT Configuration Service APIs
1177
1178     /*
1179      * A common Insert Transaction convenience method that populates the TransactionBuilder with insert operation
1180      * for a Child Row and also mutates the parent row with the UUID of the inserted Child.
1181      */
1182     private void processInsertTransaction(OvsdbClient client, String databaseName, String childTable,
1183                                     String parentTable, UUID parentUuid, String parentColumn, String namedUuid,
1184                                     Row<GenericTableSchema> row,
1185                                     TransactionBuilder transactionBuilder) {
1186         // Insert the row as the first transaction entry
1187         DatabaseSchema dbSchema = client.getDatabaseSchema(databaseName);
1188         TableSchema<GenericTableSchema> childTableSchema = dbSchema.table(childTable, GenericTableSchema.class);
1189         transactionBuilder.add(op.insert(childTableSchema, row)
1190                         .withId(namedUuid));
1191
1192         // Followed by the Mutation
1193         if (parentColumn != null) {
1194             TableSchema<GenericTableSchema> parentTableSchema = dbSchema.table(parentTable, GenericTableSchema.class);
1195             ColumnSchema<GenericTableSchema, UUID> parentColumnSchema = parentTableSchema.column(parentColumn, UUID.class);
1196             ColumnSchema<GenericTableSchema, UUID> _uuid = parentTableSchema.column("_uuid", UUID.class);
1197
1198             transactionBuilder
1199                 .add(op.mutate(parentTableSchema)
1200                         .addMutation(parentColumnSchema, Mutator.INSERT, new UUID(namedUuid))
1201                         .where(_uuid.opEqual(parentUuid))
1202                         .build());
1203         }
1204     }
1205
1206     /**
1207      * insert a Row in a Table of a specified Database Schema.
1208      *
1209      * This method can insert just a single Row specified in the row parameter.
1210      * But {@link #insertTree(Node, String, String, UUID, Row<GenericTableSchema>) insertTree}
1211      * can insert a hierarchy of rows with parent-child relationship.
1212      *
1213      * @param node OVSDB Node
1214      * @param databaseName Database Name that represents the Schema supported by the node.
1215      * @param tableName Table on which the row is inserted
1216      * @param parentTable Name of the Parent Table to which this operation will result in attaching/mutating.
1217      * @param parentUuid UUID of a Row in parent table to which this operation will result in attaching/mutating.
1218      * @param parentColumn Name of the Column in the Parent Table to be mutated with the UUID that results from the insert operation.
1219      * @param row Row of table Content to be inserted
1220      * @throws OvsdbPluginException Any failure during the insert transaction will result in a specific exception.
1221      * @return UUID of the inserted Row
1222      */
1223     @Override
1224     public UUID insertRow(Node node, String databaseName, String tableName, String parentTable, UUID parentUuid,
1225                           String parentColumn, Row<GenericTableSchema> row) throws OvsdbPluginException {
1226         Connection connection = connectionService.getConnection(node);
1227         OvsdbClient client = connection.getClient();
1228         DatabaseSchema dbSchema = client.getDatabaseSchema(databaseName);
1229         TableSchema<GenericTableSchema> tableSchema = dbSchema.table(tableName, GenericTableSchema.class);
1230
1231         Row<GenericTableSchema> processedRow = this.insertTree(node, databaseName, tableName, parentTable, parentUuid, parentColumn, row);
1232
1233         ColumnSchema<GenericTableSchema, UUID> _uuid = tableSchema.column("_uuid", UUID.class);
1234         Column<GenericTableSchema, UUID> uuid = processedRow.getColumn(_uuid);
1235         return uuid.getData();
1236     }
1237
1238     /**
1239      * insert a Row in a Table of a specified Database Schema. This is a convenience method on top of
1240      * {@link insertRow(Node, String, String, String, UUID, String, Row<GenericTableSchema>) insertRow}
1241      * which assumes that OVSDB schema implementation that corresponds to the databaseName will provide
1242      * the necessary service to populate the Parent Table Name and Parent Column Name.
1243      *
1244      * This method can insert just a single Row specified in the row parameter.
1245      * But {@link #insertTree(Node, String, String, UUID, Row<GenericTableSchema>) insertTree}
1246      * can insert a hierarchy of rows with parent-child relationship.
1247      *
1248      * @param node OVSDB Node
1249      * @param databaseName Database Name that represents the Schema supported by the node.
1250      * @param tableName Table on which the row is inserted
1251      * @param parentUuid UUID of the parent table to which this operation will result in attaching/mutating.
1252      * @param row Row of table Content to be inserted
1253      * @throws OvsdbPluginException Any failure during the insert transaction will result in a specific exception.
1254      * @return UUID of the inserted Row
1255      */
1256     @Override
1257     public UUID insertRow(Node node, String databaseName, String tableName,
1258             UUID parentRowUuid, Row<GenericTableSchema> row)
1259             throws OvsdbPluginException {
1260         return this.insertRow(node, databaseName, tableName, null, parentRowUuid, null, row);
1261     }
1262
1263     /**
1264      * inserts a Tree of Rows in multiple Tables that has parent-child relationships referenced through the OVSDB schema's refTable construct
1265      *
1266      * @param node OVSDB Node
1267      * @param databaseName Database Name that represents the Schema supported by the node.
1268      * @param tableName Table on which the row is inserted
1269      * @param parentTable Name of the Parent Table to which this operation will result in attaching/mutating.
1270      * @param parentUuid UUID of a Row in parent table to which this operation will result in attaching/mutating.
1271      * @param parentColumn Name of the Column in the Parent Table to be mutated with the UUID that results from the insert operation.
1272      * @param row Row Tree with parent-child relationships via column of type refTable.
1273      * @throws OvsdbPluginException Any failure during the insert transaction will result in a specific exception.
1274      * @return Returns the row tree with the UUID of every inserted Row populated in the _uuid column of every row in the tree
1275      */
1276     @Override
1277     public Row<GenericTableSchema> insertTree(Node node, String databaseName, String tableName, String parentTable, UUID parentUuid,
1278                                               String parentColumn, Row<GenericTableSchema> row) throws OvsdbPluginException {
1279         Connection connection = connectionService.getConnection(node);
1280         OvsdbClient client = connection.getClient();
1281
1282         if (databaseName == null || tableName == null) {
1283             throw new OvsdbPluginException("databaseName, tableName and parentUuid are Mandatory Parameters");
1284         }
1285         logger.debug("insertTree Connection : {} Table : {} ParentTable : {} Parent Column: {} Parent UUID : {} Row : {}",
1286                      client.getConnectionInfo(), tableName, parentTable, parentColumn, parentUuid, row);
1287
1288         Map<UUID, Map.Entry<String, Row<GenericTableSchema>>> referencedRows = Maps.newConcurrentMap();
1289         extractReferencedRows(node, databaseName, row, referencedRows, 0);
1290         DatabaseSchema dbSchema = client.getDatabaseSchema(OvsVswitchdSchemaConstants.DATABASE_NAME);
1291         TransactionBuilder transactionBuilder = client.transactBuilder(dbSchema);
1292
1293         String namedUuid = "Transaction_"+ tableName;
1294         this.processInsertTransaction(client, databaseName, tableName, parentTable, parentUuid,
1295                                       parentColumn, namedUuid, row, transactionBuilder);
1296
1297         int referencedRowsInsertIndex = transactionBuilder.getOperations().size();
1298         // Insert Referenced Rows
1299         if (referencedRows != null) {
1300             for (UUID refUuid : referencedRows.keySet()) {
1301                 Map.Entry<String, Row<GenericTableSchema>> referencedRow = referencedRows.get(refUuid);
1302                 TableSchema<GenericTableSchema> refTableSchema = dbSchema.table(referencedRow.getKey(), GenericTableSchema.class);
1303                 transactionBuilder.add(op.insert(refTableSchema, referencedRow.getValue())
1304                                 .withId(refUuid.toString()));
1305             }
1306         }
1307
1308         ListenableFuture<List<OperationResult>> results = transactionBuilder.execute();
1309         List<OperationResult> operationResults;
1310         try {
1311             operationResults = results.get();
1312             if (operationResults.isEmpty() || (transactionBuilder.getOperations().size() != operationResults.size())) {
1313                 throw new OvsdbPluginException("Insert Operation Failed");
1314             }
1315             for (OperationResult result : operationResults) {
1316                 if (result.getError() != null) {
1317                     throw new OvsdbPluginException("Insert Operation Failed with Error : "+result.getError().toString());
1318                 }
1319             }
1320             return getNormalizedRow(dbSchema, tableName, row, referencedRows, operationResults, referencedRowsInsertIndex);
1321         } catch (InterruptedException | ExecutionException e) {
1322             throw new OvsdbPluginException("Exception : "+e.getLocalizedMessage());
1323         }
1324     }
1325
1326     /**
1327      * inserts a Tree of Rows in multiple Tables that has parent-child relationships referenced through the OVSDB schema's refTable construct.
1328      * This is a convenience method on top of {@link #insertTree(Node, String, String, String, UUID, String, Row<GenericTableSchema>) insertTree}
1329      *
1330      * @param node OVSDB Node
1331      * @param databaseName Database Name that represents the Schema supported by the node.
1332      * @param tableName Table on which the row is inserted
1333      * @param parentUuid UUID of a Row in parent table to which this operation will result in attaching/mutating.
1334      * @param row Row Tree with parent-child relationships via column of type refTable.
1335      * @throws OvsdbPluginException Any failure during the insert transaction will result in a specific exception.
1336      * @return Returns the row tree with the UUID of every inserted Row populated in the _uuid column of every row in the tree
1337      */
1338     @Override
1339     public Row<GenericTableSchema> insertTree(Node node, String databaseName,
1340             String tableName, UUID parentRowUuid, Row<GenericTableSchema> row)
1341             throws OvsdbPluginException {
1342         return this.insertTree(node, databaseName, tableName, null, parentRowUuid, null, row);
1343     }
1344
1345     /**
1346      * Convenience method that helps insertTree to extract Rows that are referenced directly from within a primary row
1347      * to be inserted. These referenced rows are *NOT* defined in the OVSDB specification. But, we felt that from a northbound
1348      * application standpoint, having such an option is useful and our implementation supports it for applications to make use of.
1349      * In short, whichever ColumnSchema is based on an UUID (refered by RefTable in schema), applications can directly insert an
1350      * entire row and this method will help navigate it through and identify such cases.
1351      * After identifying these Referenced Rows, it will modify the primary row with Named UUIDs and fill out the referencedRows
1352      * Map structure so that insertTree can insert all the Rows defined in this Tree of rows in a single transaction with automatic
1353      * Mutation on the parent rows.
1354      *
1355      * @param node OVSDB Node
1356      * @param dbName Database Name that represents the Schema supported by the node.
1357      * @param row Row Tree with parent-child relationships via column of type refTable.
1358      * @param referencedRows Map of Named-UUID to the actual referenced row (with RefTable)
1359      * @param namedUuidSuffix Named UUID must be unique for every new Row insert within a given transaction.
1360      *        This index will help to retain the uniqueness.
1361      */
1362     private void extractReferencedRows(Node node, String dbName, Row<GenericTableSchema> row,
1363                                        Map<UUID, Map.Entry<String, Row<GenericTableSchema>>> referencedRows,
1364                                        int namedUuidSuffix) {
1365         OvsdbClient client = connectionService.getConnection(node).getClient();
1366         Collection<Column<GenericTableSchema, ?>> columns = row.getColumns();
1367         for (Column column : columns) {
1368             if (column.getData() != null) {
1369                 if (column.getData() instanceof ReferencedRow) {
1370                     ReferencedRow refRowObject = (ReferencedRow)column.getData();
1371                     UUID refUuid = new UUID("NamedUuid"+namedUuidSuffix++);
1372                     column.setData(refUuid);
1373                     try {
1374                         DatabaseSchema dbSchema = client.getSchema(dbName).get();
1375                         GenericTableSchema schema = dbSchema.table(refRowObject.getRefTable(), GenericTableSchema.class);
1376                         Row<GenericTableSchema> refRow = schema.createRow((ObjectNode)refRowObject.getJsonNode());
1377                         referencedRows.put(refUuid, new AbstractMap.SimpleEntry<String, Row<GenericTableSchema>>(refRowObject.getRefTable(), refRow));
1378                         extractReferencedRows(node, dbName, refRow, referencedRows, namedUuidSuffix);
1379                     } catch (InterruptedException | ExecutionException e) {
1380                         logger.error("Exception while extracting multi-level Row references " + e.getLocalizedMessage());
1381                     }
1382                 } else if (column.getData() instanceof OvsdbSet) {
1383                     OvsdbSet<Object> setObject = (OvsdbSet<Object>)column.getData();
1384                     OvsdbSet<Object> modifiedSet = new OvsdbSet<Object>();
1385                     for (Object obj : setObject) {
1386                         if (obj instanceof ReferencedRow) {
1387                             ReferencedRow refRowObject = (ReferencedRow)obj;
1388                             UUID refUuid = new UUID("NamedUuid"+namedUuidSuffix++);
1389                             modifiedSet.add(refUuid);
1390                             try {
1391                                 DatabaseSchema dbSchema = client.getSchema(dbName).get();
1392                                 GenericTableSchema schema = dbSchema.table(refRowObject.getRefTable(), GenericTableSchema.class);
1393                                 Row<GenericTableSchema> refRow = schema.createRow((ObjectNode)refRowObject.getJsonNode());
1394                                 referencedRows.put(refUuid, new AbstractMap.SimpleEntry<String, Row<GenericTableSchema>>(refRowObject.getRefTable(), refRow));
1395                                 extractReferencedRows(node, dbName, refRow, referencedRows, namedUuidSuffix);
1396                             } catch (InterruptedException | ExecutionException e) {
1397                                 logger.error("Exception while extracting multi-level Row references " + e.getLocalizedMessage());
1398                             }
1399                         } else {
1400                             modifiedSet.add(obj);
1401                         }
1402                     }
1403                     column.setData(modifiedSet);
1404                 }
1405             }
1406         }
1407     }
1408
1409     /**
1410      * getNormalizedRow normalizes the Row from a namedUuid Space as defined in extractReferencedRows to the actual Uuid as created
1411      * by the Ovsdb-server. In order to perform this normalization, it processes the operation results for a corresponding Transaction
1412      * where the referenced rows are inserted along with the Primary row. It changes the named-Uuid to the actual Uuid before returning
1413      * the Row to the application.
1414      *
1415      * @param dbSchema Database Schema supported by the node.
1416      * @param row Row Tree with parent-child relationships via column of type refTable.
1417      * @param tableName Table on which the row is inserted
1418      * @param referencedRows Map of Named-UUID to the actual referenced row (with RefTable)
1419      * @param operationResults Operation Results returned by ovsdb-server for the insertTree transaction
1420      * @param referencedRowsInsertIndex Starting index in OperationResults from which the ReferencedRow insert results begin.
1421      * @return
1422      */
1423     private Row<GenericTableSchema> getNormalizedRow(DatabaseSchema dbSchema, String tableName, Row<GenericTableSchema> row,
1424                                                      Map<UUID, Map.Entry<String, Row<GenericTableSchema>>> referencedRows,
1425                                                      List<OperationResult> operationResults, int referencedRowsInsertIndex) {
1426         UUID primaryRowUuid = operationResults.get(0).getUuid();
1427         TableSchema<GenericTableSchema> primaryRowTableSchema = dbSchema.table(tableName, GenericTableSchema.class);
1428         ColumnSchema<GenericTableSchema, UUID> _uuid = primaryRowTableSchema.column("_uuid", UUID.class);
1429         if (_uuid != null) {
1430             Column<GenericTableSchema, UUID> _uuidColumn = new Column<GenericTableSchema, UUID>(_uuid, primaryRowUuid);
1431             row.addColumn("_uuid", _uuidColumn);
1432         }
1433
1434         if (referencedRows != null) {
1435             Collection<Column<GenericTableSchema, ?>> columns = row.getColumns();
1436             if (referencedRows != null) {
1437                 for (int idx=0; idx < referencedRows.keySet().size(); idx++) {
1438                     UUID refUuid = (UUID) referencedRows.keySet().toArray()[idx];
1439                     for (Column column : columns) {
1440                         if (column.getData() != null) {
1441                             if ((column.getData() instanceof UUID) && column.getData().equals(refUuid)) {
1442                                 column.setData(operationResults.get(referencedRowsInsertIndex + idx).getUuid());
1443                             } else if ((column.getData() instanceof OvsdbSet) && ((OvsdbSet)column.getData()).contains(refUuid)) {
1444                                 OvsdbSet<UUID> refSet = (OvsdbSet<UUID>)column.getData();
1445                                 refSet.remove(refUuid);
1446                                 refSet.add(operationResults.get(referencedRowsInsertIndex + idx).getUuid());
1447                             }
1448                         }
1449                     }
1450                 }
1451             }
1452         }
1453         return row;
1454     }
1455
1456     @Override
1457     public Row<GenericTableSchema> updateRow(Node node, String databaseName,
1458             String tableName, UUID rowUuid, Row<GenericTableSchema> row,
1459             boolean overwrite) throws OvsdbPluginException {
1460         throw new OvsdbPluginException("Not implemented Yet");
1461     }
1462
1463     @Override
1464     public void deleteRow(Node node, String databaseName, String tableName, String parentTable, UUID parentRowUuid,
1465             String parentColumn, UUID rowUuid) throws OvsdbPluginException {
1466         throw new OvsdbPluginException("Not implemented Yet");
1467     }
1468
1469     @Override
1470     public void deleteRow(Node node, String databaseName, String tableName,
1471             UUID rowUuid) throws OvsdbPluginException {
1472         throw new OvsdbPluginException("Not implemented Yet");
1473     }
1474
1475     @Override
1476     public Row<GenericTableSchema> getRow(Node node, String databaseName,
1477             String tableName, UUID uuid) throws OvsdbPluginException {
1478         throw new OvsdbPluginException("Not implemented Yet");
1479     }
1480
1481     @Override
1482     public ConcurrentMap<UUID, Row<GenericTableSchema>> getRows(Node node,
1483             String databaseName, String tableName) throws OvsdbPluginException {
1484         throw new OvsdbPluginException("Not implemented Yet");
1485     }
1486
1487     @Override
1488     public ConcurrentMap<UUID, Row<GenericTableSchema>> getRows(Node node,
1489             String databaseName, String tableName, String fiqlQuery)
1490             throws OvsdbPluginException {
1491         throw new OvsdbPluginException("Not implemented Yet");
1492     }
1493
1494     @Override
1495     public List<String> getTables(Node node, String databaseName) throws OvsdbPluginException {
1496         throw new OvsdbPluginException("Not implemented Yet");
1497     }
1498 }
1499