'Static data model implementation in Worklet

Change-Id: Ic5eeb26eaea547523befd509f9f48281cb4c2031
diff --git a/apps/workflow/ofoverlay/app/src/main/java/org/onosproject/ofoverlay/impl/OfOverlayWorkflow.java b/apps/workflow/ofoverlay/app/src/main/java/org/onosproject/ofoverlay/impl/OfOverlayWorkflow.java
index cbddfc7..2267337 100644
--- a/apps/workflow/ofoverlay/app/src/main/java/org/onosproject/ofoverlay/impl/OfOverlayWorkflow.java
+++ b/apps/workflow/ofoverlay/app/src/main/java/org/onosproject/ofoverlay/impl/OfOverlayWorkflow.java
@@ -21,6 +21,8 @@
 import org.onosproject.workflow.api.WorkflowExecutionService;
 import org.onosproject.workflow.api.WorkflowStore;
 import org.onosproject.workflow.api.WorkplaceStore;
+import org.onosproject.workflow.api.DefaultWorkletDescription;
+import org.onosproject.workflow.api.WorkflowException;
 import org.osgi.service.component.annotations.Activate;
 import org.osgi.service.component.annotations.Component;
 import org.osgi.service.component.annotations.Deactivate;
@@ -57,6 +59,8 @@
 
     private ScheduledExecutorService eventMapTriggerExecutor;
 
+    private static final String BRIDGE_NAME = "/bridgeName";
+
     @Activate
     public void activate() {
         log.info("Activated");
@@ -77,108 +81,117 @@
      * Registers workflows.
      */
     private void registerWorkflows() {
-        // registering class-loader
-        workflowStore.registerLocal(this.getClass().getClassLoader());
+        try {
+            // registering class-loader
+            workflowStore.registerLocal(this.getClass().getClassLoader());
 
-        // registering new workflow definition
-        URI uri = URI.create("of-overlay.workflow-nova");
-        Workflow workflow = ImmutableListWorkflow.builder()
-                .id(uri)
-                //.attribute(WorkflowAttribute.REMOVE_AFTER_COMPLETE)
-                .chain(Ovs.CreateOvsdbDevice.class.getName())
-                .chain(Ovs.UpdateOvsVersion.class.getName())
-                .chain(Ovs.UpdateOverlayBridgeId.class.getName())
-                .chain(Ovs.CreateOverlayBridge.class.getName())
-                .chain(Ovs.UpdateUnderlayBridgeId.class.getName())
-                .chain(Ovs.CreateUnderlayBridge.class.getName())
-                .chain(Ovs.CreateOverlayBridgeVxlanPort.class.getName())
-                .chain(Ovs.AddPhysicalPortsOnUnderlayBridge.class.getName())
-                .chain(Ovs.ConfigureUnderlayBridgeLocalIp.class.getName())
-                .build();
-        workflowStore.register(workflow);
+            // registering new workflow definition
+            URI uri = URI.create("of-overlay.workflow-nova");
+            Workflow workflow = ImmutableListWorkflow.builder()
+                    .id(uri)
+                    //.attribute(WorkflowAttribute.REMOVE_AFTER_COMPLETE)
+                    .chain(Ovs.CreateOvsdbDevice.class.getName())
+                    .chain(Ovs.UpdateOvsVersion.class.getName())
+                    .chain(Ovs.UpdateOverlayBridgeId.class.getName())
+                    .chain(DefaultWorkletDescription.builder().name(Ovs.CreateBridge.class.getName())
+                            .staticDataModel(BRIDGE_NAME, "br-int")
+                            .build())
+                    .chain(Ovs.UpdateUnderlayBridgeId.class.getName())
+                    .chain(DefaultWorkletDescription.builder().name(Ovs.CreateBridge.class.getName())
+                            .staticDataModel(BRIDGE_NAME, "br-phy")
+                            .build())
+                    .chain(Ovs.CreateOverlayBridgeVxlanPort.class.getName())
+                    .chain(Ovs.AddPhysicalPortsOnUnderlayBridge.class.getName())
+                    .chain(Ovs.ConfigureUnderlayBridgeLocalIp.class.getName())
+                    .build();
 
-        // registering new workflow definition based on multi-event handling
-        uri = URI.create("of-overlay.workflow-nova-multiEvent-test");
-        workflow = ImmutableListWorkflow.builder()
-                .id(uri)
-                //.attribute(WorkflowAttribute.REMOVE_AFTER_COMPLETE)
-                .chain(Ovs.CreateOvsdbDevice.class.getName())
-                .chain(Ovs.UpdateOvsVersion.class.getName())
-                .chain(Ovs.UpdateOverlayBridgeId.class.getName())
-                .chain(Ovs.CreateOverlayBridgeMultiEvent.class.getName())
-                .chain(Ovs.UpdateUnderlayBridgeId.class.getName())
-                .chain(Ovs.CreateUnderlayBridge.class.getName())
-                .chain(Ovs.CreateOverlayBridgeVxlanPort.class.getName())
-                .chain(Ovs.AddPhysicalPortsOnUnderlayBridge.class.getName())
-                .chain(Ovs.ConfigureUnderlayBridgeLocalIp.class.getName())
-                .build();
-        workflowStore.register(workflow);
+            workflowStore.register(workflow);
 
-        uri = URI.create("of-overlay.clean-workflow-nova");
-        workflow = ImmutableListWorkflow.builder()
-                .id(uri)
-                //.attribute(WorkflowAttribute.REMOVE_AFTER_COMPLETE)
-                .chain(Ovs.DeleteOverlayBridgeConfig.class.getName())
-                .chain(Ovs.RemoveOverlayBridgeOfDevice.class.getName())
-                .chain(Ovs.DeleteUnderlayBridgeConfig.class.getName())
-                .chain(Ovs.RemoveUnderlayBridgeOfDevice.class.getName())
-                .chain(Ovs.RemoveOvsdbDevice.class.getName())
-                .build();
-        workflowStore.register(workflow);
+            // registering new workflow definition based on multi-event handling
+            uri = URI.create("of-overlay.workflow-nova-multiEvent-test");
+            workflow = ImmutableListWorkflow.builder()
+                    .id(uri)
+                    //.attribute(WorkflowAttribute.REMOVE_AFTER_COMPLETE)
+                    .chain(Ovs.CreateOvsdbDevice.class.getName())
+                    .chain(Ovs.UpdateOvsVersion.class.getName())
+                    .chain(Ovs.UpdateOverlayBridgeId.class.getName())
+                    .chain(Ovs.CreateOverlayBridgeMultiEvent.class.getName())
+                    .chain(Ovs.UpdateUnderlayBridgeId.class.getName())
+                    .chain(Ovs.CreateUnderlayBridge.class.getName())
+                    .chain(Ovs.CreateOverlayBridgeVxlanPort.class.getName())
+                    .chain(Ovs.AddPhysicalPortsOnUnderlayBridge.class.getName())
+                    .chain(Ovs.ConfigureUnderlayBridgeLocalIp.class.getName())
+                    .build();
+            workflowStore.register(workflow);
 
-        uri = URI.create("of-overlay.clean-workflow-nova-waitAll-Bridge-Del");
-        workflow = ImmutableListWorkflow.builder()
-                .id(uri)
-                //.attribute(WorkflowAttribute.REMOVE_AFTER_COMPLETE)
-                .chain(Ovs.DeleteOverlayBridgeConfig.class.getName())
-                .chain(Ovs.DeleteUnderlayBridgeConfig.class.getName())
-                .chain(Ovs.RemoveBridgeOfDevice.class.getName())
-                .chain(Ovs.RemoveOvsdbDevice.class.getName())
-                .build();
-        workflowStore.register(workflow);
+            uri = URI.create("of-overlay.clean-workflow-nova");
+            workflow = ImmutableListWorkflow.builder()
+                    .id(uri)
+                    //.attribute(WorkflowAttribute.REMOVE_AFTER_COMPLETE)
+                    .chain(Ovs.DeleteOverlayBridgeConfig.class.getName())
+                    .chain(Ovs.RemoveOverlayBridgeOfDevice.class.getName())
+                    .chain(Ovs.DeleteUnderlayBridgeConfig.class.getName())
+                    .chain(Ovs.RemoveUnderlayBridgeOfDevice.class.getName())
+                    .chain(Ovs.RemoveOvsdbDevice.class.getName())
+                    .build();
+            workflowStore.register(workflow);
 
-        uri = URI.create("of-overlay.workflow-ovs-leaf");
-        workflow = ImmutableListWorkflow.builder()
-                .id(uri)
-                .chain(Ovs.CreateOvsdbDevice.class.getName())
-                .chain(Ovs.UpdateOvsVersion.class.getName())
-                .chain(Ovs.UpdateUnderlayBridgeId.class.getName())
-                .chain(Ovs.CreateUnderlayBridge.class.getName())
-                .chain(Ovs.AddPhysicalPortsOnUnderlayBridge.class.getName())
-                .build();
-        workflowStore.register(workflow);
+            uri = URI.create("of-overlay.clean-workflow-nova-waitAll-Bridge-Del");
+            workflow = ImmutableListWorkflow.builder()
+                    .id(uri)
+                    //.attribute(WorkflowAttribute.REMOVE_AFTER_COMPLETE)
+                    .chain(Ovs.DeleteOverlayBridgeConfig.class.getName())
+                    .chain(Ovs.DeleteUnderlayBridgeConfig.class.getName())
+                    .chain(Ovs.RemoveBridgeOfDevice.class.getName())
+                    .chain(Ovs.RemoveOvsdbDevice.class.getName())
+                    .build();
+            workflowStore.register(workflow);
 
-        uri = URI.create("of-overlay.workflow-ovs-spine");
-        workflow = ImmutableListWorkflow.builder()
-                .id(uri)
-                .chain(Ovs.CreateOvsdbDevice.class.getName())
-                .chain(Ovs.UpdateOvsVersion.class.getName())
-                .chain(Ovs.UpdateUnderlayBridgeId.class.getName())
-                .chain(Ovs.CreateUnderlayBridge.class.getName())
-                .chain(Ovs.AddPhysicalPortsOnUnderlayBridge.class.getName())
-                .build();
-        workflowStore.register(workflow);
+            uri = URI.create("of-overlay.workflow-ovs-leaf");
+            workflow = ImmutableListWorkflow.builder()
+                    .id(uri)
+                    .chain(Ovs.CreateOvsdbDevice.class.getName())
+                    .chain(Ovs.UpdateOvsVersion.class.getName())
+                    .chain(Ovs.UpdateUnderlayBridgeId.class.getName())
+                    .chain(Ovs.CreateUnderlayBridge.class.getName())
+                    .chain(Ovs.AddPhysicalPortsOnUnderlayBridge.class.getName())
+                    .build();
+            workflowStore.register(workflow);
 
-        deviceService.addListener(
-                event -> {
-                    // trigger EventTask for DeviceEvent
-                    eventMapTriggerExecutor.submit(
-                            () -> workflowExecutionService.eventMapTrigger(
-                                    event,
-                                    // event hint supplier
-                                    (ev) -> {
-                                        if (ev == null || ev.subject() == null) {
-                                            return null;
+            uri = URI.create("of-overlay.workflow-ovs-spine");
+            workflow = ImmutableListWorkflow.builder()
+                    .id(uri)
+                    .chain(Ovs.CreateOvsdbDevice.class.getName())
+                    .chain(Ovs.UpdateOvsVersion.class.getName())
+                    .chain(Ovs.UpdateUnderlayBridgeId.class.getName())
+                    .chain(Ovs.CreateUnderlayBridge.class.getName())
+                    .chain(Ovs.AddPhysicalPortsOnUnderlayBridge.class.getName())
+                    .build();
+            workflowStore.register(workflow);
+
+            deviceService.addListener(
+                    event -> {
+                        // trigger EventTask for DeviceEvent
+                        eventMapTriggerExecutor.submit(
+                                () -> workflowExecutionService.eventMapTrigger(
+                                        event,
+                                        // event hint supplier
+                                        (ev) -> {
+                                            if (ev == null || ev.subject() == null) {
+                                                return null;
+                                            }
+                                            String hint = event.subject().id().toString();
+                                            log.debug("hint: {}", hint);
+                                            return hint;
                                         }
-                                        String hint = event.subject().id().toString();
-                                        log.debug("hint: {}", hint);
-                                        return hint;
-                                    }
-                            )
-                    );
-                }
-        );
+                                )
+                        );
+                    }
+            );
 
+        } catch (WorkflowException e) {
+            e.printStackTrace();
+        }
     }
 
 }
diff --git a/apps/workflow/ofoverlay/app/src/main/java/org/onosproject/ofoverlay/impl/Ovs.java b/apps/workflow/ofoverlay/app/src/main/java/org/onosproject/ofoverlay/impl/Ovs.java
index ad56d52..ccbc182 100644
--- a/apps/workflow/ofoverlay/app/src/main/java/org/onosproject/ofoverlay/impl/Ovs.java
+++ b/apps/workflow/ofoverlay/app/src/main/java/org/onosproject/ofoverlay/impl/Ovs.java
@@ -59,6 +59,7 @@
 import org.onosproject.workflow.api.JsonDataModel;
 import org.onosproject.workflow.api.WorkflowContext;
 import org.onosproject.workflow.api.WorkflowException;
+import org.onosproject.workflow.api.StaticDataModel;
 import org.onosproject.workflow.model.accessinfo.SshAccessInfo;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -83,6 +84,7 @@
     private static final Logger log = LoggerFactory.getLogger(Ovs.class);
 
     private static final String MODEL_MGMT_IP = "/mgmtIp";
+    private static final String BRIDGE_NAME = "/bridgeName";
     private static final String MODEL_OVSDB_PORT = "/ovsdbPort";
     private static final String MODEL_OVS_VERSION = "/ovsVersion";
     private static final String MODEL_OVS_DATAPATH_TYPE = "/ovsDatapathType";
@@ -535,6 +537,108 @@
         }
     }
 
+
+    public static class CreateBridge extends AbstractWorklet {
+
+        @StaticDataModel(path = BRIDGE_NAME)
+        String bridgeName;
+
+        @JsonDataModel(path = MODEL_MGMT_IP)
+        String strMgmtIp;
+
+        @JsonDataModel(path = MODEL_OVSDB_PORT)
+        Integer intOvsdbPort;
+
+        @JsonDataModel(path = MODEL_OVS_DATAPATH_TYPE)
+        String strOvsDatapath;
+
+        @JsonDataModel(path = MODEL_OF_DEVID_OVERLAY_BRIDGE, optional = true)
+        String strOfDevId;
+
+        @Override
+        public boolean isNext(WorkflowContext context) throws WorkflowException {
+
+            check(strOfDevId != null, "invalid strOfDevIdUnderlay");
+            return !OvsUtil.isAvailableBridge(context, DeviceId.deviceId(strOfDevId));
+        }
+
+        @Override
+        public void process(WorkflowContext context) throws WorkflowException {
+
+            check(strOfDevId != null, "invalid strOfDevIdOverlay");
+            BridgeConfig bridgeConfig = OvsUtil.getOvsdbBehaviour(context, strMgmtIp, BridgeConfig.class);
+            List<ControllerInfo> ofControllers = OvsUtil.getOpenflowControllerInfoList(context);
+            DeviceId ofDeviceId = DeviceId.deviceId(strOfDevId);
+
+            if (ofControllers == null || ofControllers.size() == 0) {
+                throw new WorkflowException("Invalid of controllers");
+            }
+
+            Optional<BridgeDescription> optBd = OvsUtil.getBridgeDescription(bridgeConfig, bridgeName);
+            if (!optBd.isPresent()) {
+
+                // If bridge does not exist, just creates a new bridge.
+                context.waitCompletion(DeviceEvent.class, ofDeviceId.toString(),
+                        () -> OvsUtil.createBridge(bridgeConfig,
+                                bridgeName,
+                                OvsUtil.bridgeDatapathId(ofDeviceId),
+                                ofControllers,
+                                OvsUtil.buildOvsDatapathType(strOvsDatapath)),
+                        TIMEOUT_DEVICE_CREATION_MS
+                );
+                return;
+
+            } else {
+                BridgeDescription bd = optBd.get();
+                if (OvsUtil.isEqual(ofControllers, bd.controllers())) {
+                    log.error("{} has valid controller setting({})", bridgeName, bd.controllers());
+                    context.completed();
+                    return;
+                }
+
+                OvsdbClientService ovsdbClient = OvsUtil.getOvsdbClient(context, strMgmtIp, intOvsdbPort);
+                if (ovsdbClient == null || !ovsdbClient.isConnected()) {
+                    throw new WorkflowException("Invalid ovsdb client for " + strMgmtIp);
+                }
+
+                // If controller settings are not matched, set controller with valid controller information.
+                context.waitCompletion(DeviceEvent.class, ofDeviceId.toString(),
+                        () -> ovsdbClient.setControllersWithDeviceId(bd.deviceId().get(), ofControllers),
+                        TIMEOUT_DEVICE_CREATION_MS
+                );
+                return;
+            }
+        }
+
+        @Override
+        public boolean isCompleted(WorkflowContext context, Event event)throws WorkflowException {
+            if (!(event instanceof DeviceEvent)) {
+                return false;
+            }
+            DeviceEvent deviceEvent = (DeviceEvent) event;
+            Device device = deviceEvent.subject();
+            switch (deviceEvent.type()) {
+                case DEVICE_ADDED:
+                case DEVICE_AVAILABILITY_CHANGED:
+                case DEVICE_UPDATED:
+                    return context.getService(DeviceService.class).isAvailable(device.id());
+                default:
+                    return false;
+            }
+        }
+
+        @Override
+        public void timeout(WorkflowContext context) throws WorkflowException {
+            if (!isNext(context)) {
+                context.completed(); //Complete the job of worklet by timeout
+            } else {
+                super.timeout(context);
+            }
+        }
+
+    }
+
+
     /**
      * Work-let class for creating overlay openflow bridge.
      */