Merge changes Id6b8ba01,Ic4081b36
authorTony Tkacik <ttkacik@cisco.com>
Fri, 28 Mar 2014 16:47:30 +0000 (16:47 +0000)
committerGerrit Code Review <gerrit@opendaylight.org>
Fri, 28 Mar 2014 16:47:30 +0000 (16:47 +0000)
* changes:
  Bug:553 - RPC providers are not cleaned up on bundle stop, causing bundle restart to fail
  Bug:441-closing listener on stop of md-topologymaneger bundle

47 files changed:
opendaylight/commons/opendaylight/pom.xml
opendaylight/distribution/opendaylight/src/main/resources/configuration/config.ini
opendaylight/md-sal/model/model-flow-statistics/src/main/yang/opendaylight-statistics-types.yang
opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/md/sal/binding/api/BindingDataBroker.java [new file with mode: 0644]
opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/md/sal/binding/api/BindingDataChangeListener.java [new file with mode: 0644]
opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/md/sal/binding/api/BindingDataReadTransaction.java [new file with mode: 0644]
opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/md/sal/binding/api/BindingDataReadWriteTransaction.java [new file with mode: 0644]
opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/md/sal/binding/api/BindingDataWriteTransaction.java [new file with mode: 0644]
opendaylight/md-sal/sal-binding-it/src/main/java/org/opendaylight/controller/test/sal/binding/it/TestHelper.java
opendaylight/md-sal/sal-binding-it/src/test/java/org/opendaylight/controller/test/sal/binding/it/AbstractTest.java
opendaylight/md-sal/sal-common-api/pom.xml
opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/AsyncDataBroker.java [new file with mode: 0644]
opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/AsyncDataChangeEvent.java [new file with mode: 0644]
opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/AsyncDataChangeListener.java [new file with mode: 0644]
opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/AsyncDataTransactionFactory.java [new file with mode: 0644]
opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/AsyncReadTransaction.java [new file with mode: 0644]
opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/AsyncReadWriteTransaction.java [new file with mode: 0644]
opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/AsyncTransaction.java [new file with mode: 0644]
opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/AsyncWriteTransaction.java [new file with mode: 0644]
opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/DataChangeListener.java
opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/LogicalDatastoreType.java [new file with mode: 0644]
opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/TransactionChain.java
opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/TransactionChainListener.java
opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/md/sal/dom/api/DOMDataBroker.java [new file with mode: 0644]
opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/md/sal/dom/api/DOMDataChangeListener.java [new file with mode: 0644]
opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/md/sal/dom/api/DOMDataReadTransaction.java [new file with mode: 0644]
opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/md/sal/dom/api/DOMDataReadWriteTransaction.java [new file with mode: 0644]
opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/md/sal/dom/api/DOMDataWriteTransaction.java [new file with mode: 0644]
opendaylight/md-sal/sal-dom-spi/src/main/java/org/opendaylight/controller/sal/core/spi/data/DOMStore.java [new file with mode: 0644]
opendaylight/md-sal/sal-dom-spi/src/main/java/org/opendaylight/controller/sal/core/spi/data/DOMStoreReadTransaction.java [new file with mode: 0644]
opendaylight/md-sal/sal-dom-spi/src/main/java/org/opendaylight/controller/sal/core/spi/data/DOMStoreReadWriteTransaction.java [new file with mode: 0644]
opendaylight/md-sal/sal-dom-spi/src/main/java/org/opendaylight/controller/sal/core/spi/data/DOMStoreThreePhaseCommitCohort.java [new file with mode: 0644]
opendaylight/md-sal/sal-dom-spi/src/main/java/org/opendaylight/controller/sal/core/spi/data/DOMStoreTransaction.java [new file with mode: 0644]
opendaylight/md-sal/sal-dom-spi/src/main/java/org/opendaylight/controller/sal/core/spi/data/DOMStoreWriteTransaction.java [new file with mode: 0644]
opendaylight/md-sal/sal-dom-spi/src/main/java/org/opendaylight/controller/sal/core/spi/data/package-info.java [new file with mode: 0644]
opendaylight/md-sal/samples/toaster-it/src/test/java/org/opendaylight/controller/sample/toaster/it/ToasterTest.java
opendaylight/md-sal/test/sal-rest-connector-it/pom.xml
opendaylight/netconf/netconf-it/src/test/java/org/opendaylight/controller/netconf/it/pax/IdentityRefNetconfTest.java
opendaylight/netconf/pom.xml
opendaylight/northbound/networkconfiguration/bridgedomain/src/main/java/org/opendaylight/controller/networkconfig/bridgedomain/northbound/BridgeDomainNorthbound.java
opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/core/internal/SecureMessageReadWriteService.java
opendaylight/sal/networkconfiguration/api/src/main/java/org/opendaylight/controller/sal/networkconfig/bridgedomain/BridgeDomainConfigServiceException.java [new file with mode: 0644]
opendaylight/sal/networkconfiguration/api/src/main/java/org/opendaylight/controller/sal/networkconfig/bridgedomain/IPluginInBridgeDomainConfigService.java
opendaylight/sal/networkconfiguration/implementation/src/main/java/org/opendaylight/controller/sal/networkconfig/bridgedomain/internal/BridgeDomainConfigService.java
opendaylight/web/devices/src/main/java/org/opendaylight/controller/devices/web/Devices.java
opendaylight/web/flows/src/main/java/org/opendaylight/controller/flows/web/Flows.java
opendaylight/web/flows/src/main/resources/js/page.js

index e05059b4aef212b3475845777356162b847025d5..e7c7bbe6370c1750d88d454c8faffdd4ac2eadae 100644 (file)
@@ -91,7 +91,7 @@
     <commons.httpclient.version>0.1.2-SNAPSHOT</commons.httpclient.version>
     <concepts.version>0.5.2-SNAPSHOT</concepts.version>
     <protocol-framework.version>0.5.0-SNAPSHOT</protocol-framework.version>
-    <netty.version>4.0.10.Final</netty.version>
+    <netty.version>4.0.17.Final</netty.version>
     <commons.io.version>2.4</commons.io.version>
     <bundlescanner.version>0.4.2-SNAPSHOT</bundlescanner.version>
     <usermanager.version>0.4.2-SNAPSHOT</usermanager.version>
index 0d223b8df2b3381cc26d248a6467da3efb68f1eb..4598bac593269d026bdcf32dd295ecaf5eb2af37 100644 (file)
@@ -49,7 +49,7 @@ netconf.config.persister.2.properties.numberOfBackups=1
 # Set Default start level for framework
 osgi.bundles.defaultStartLevel=4
 # Extra packages to import from the boot class loader
-org.osgi.framework.system.packages.extra=sun.reflect,sun.reflect.misc,sun.misc
+org.osgi.framework.system.packages.extra=sun.reflect,sun.reflect.misc,sun.misc,sun.nio.ch
 # This is not Eclipse App
 eclipse.ignoreApp=true
 # Don't shutdown equinox if the eclipse App has ended,
index c4cccc11023f33fd77ba0b27abf15e4d195b155d..19d6eafa789204b252caa2e8da233808dbce150e 100644 (file)
@@ -2,7 +2,7 @@ module opendaylight-statistics-types {
     namespace "urn:opendaylight:model:statistics:types";
     prefix stat-types;
 
-    import ietf-yang-types {prefix yang;}
+    import ietf-yang-types {prefix yang; revision-date "2010-09-24";}
     
     revision "2013-09-25" {
         description "Initial revision of flow service";
diff --git a/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/md/sal/binding/api/BindingDataBroker.java b/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/md/sal/binding/api/BindingDataBroker.java
new file mode 100644 (file)
index 0000000..c6a9efe
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.md.sal.binding.api;
+
+import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+public interface BindingDataBroker extends AsyncDataBroker<InstanceIdentifier<?>, DataObject, BindingDataChangeListener>{
+    @Override
+    BindingDataReadTransaction newReadOnlyTransaction();
+
+    @Override
+    BindingDataReadWriteTransaction newReadWriteTransaction();
+
+    @Override
+    BindingDataWriteTransaction newWriteOnlyTransaction();
+
+    @Override
+    ListenerRegistration<BindingDataChangeListener> registerDataChangeListener(LogicalDatastoreType store,
+            InstanceIdentifier<?> path, BindingDataChangeListener listener, DataChangeScope triggeringScope);
+}
diff --git a/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/md/sal/binding/api/BindingDataChangeListener.java b/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/md/sal/binding/api/BindingDataChangeListener.java
new file mode 100644 (file)
index 0000000..94ac2d2
--- /dev/null
@@ -0,0 +1,18 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.md.sal.binding.api;
+
+import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent;
+import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeListener;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+public interface BindingDataChangeListener extends AsyncDataChangeListener<InstanceIdentifier<?>, DataObject> {
+    @Override
+    void onDataChanged(AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> change);
+}
diff --git a/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/md/sal/binding/api/BindingDataReadTransaction.java b/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/md/sal/binding/api/BindingDataReadTransaction.java
new file mode 100644 (file)
index 0000000..93df3eb
--- /dev/null
@@ -0,0 +1,21 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.md.sal.binding.api;
+
+import org.opendaylight.controller.md.sal.common.api.data.AsyncReadTransaction;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+import com.google.common.base.Optional;
+import com.google.common.util.concurrent.ListenableFuture;
+
+public interface BindingDataReadTransaction extends AsyncReadTransaction<InstanceIdentifier<?>, DataObject> {
+    @Override
+    ListenableFuture<Optional<DataObject>> read(LogicalDatastoreType store, InstanceIdentifier<?> path);
+}
diff --git a/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/md/sal/binding/api/BindingDataReadWriteTransaction.java b/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/md/sal/binding/api/BindingDataReadWriteTransaction.java
new file mode 100644 (file)
index 0000000..0dcf020
--- /dev/null
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.md.sal.binding.api;
+
+import org.opendaylight.controller.md.sal.common.api.data.AsyncReadWriteTransaction;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+/**
+ * Logical capture of a combination of both {@link BindingDataReadTransaction} and
+ * {@link BindingDataWriteTransaction}.
+ */
+public interface BindingDataReadWriteTransaction extends BindingDataReadTransaction, BindingDataWriteTransaction, AsyncReadWriteTransaction<InstanceIdentifier<?>, DataObject> {
+
+}
diff --git a/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/md/sal/binding/api/BindingDataWriteTransaction.java b/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/md/sal/binding/api/BindingDataWriteTransaction.java
new file mode 100644 (file)
index 0000000..e989f73
--- /dev/null
@@ -0,0 +1,21 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.md.sal.binding.api;
+
+import org.opendaylight.controller.md.sal.common.api.data.AsyncWriteTransaction;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+public interface BindingDataWriteTransaction extends AsyncWriteTransaction<InstanceIdentifier<?>, DataObject> {
+    @Override
+    void put(LogicalDatastoreType store, InstanceIdentifier<?> path, DataObject data);
+
+    @Override
+    void delete(LogicalDatastoreType store, InstanceIdentifier<?> path);
+}
index 0a71ef5315ebde5338fbe32ab73f1934b2260f01..ba639ad7c24e4e704a15234949a13431a137f9fc 100644 (file)
@@ -45,6 +45,13 @@ public class TestHelper {
                 bindingAwareSalBundles(),
                 mavenBundle("commons-codec", "commons-codec").versionAsInProject(),
 
+                systemProperty("org.osgi.framework.system.packages.extra").value("sun.nio.ch"),
+                mavenBundle("io.netty", "netty-common").versionAsInProject(), //
+                mavenBundle("io.netty", "netty-buffer").versionAsInProject(), //
+                mavenBundle("io.netty", "netty-handler").versionAsInProject(), //
+                mavenBundle("io.netty", "netty-codec").versionAsInProject(), //
+                mavenBundle("io.netty", "netty-transport").versionAsInProject(), //
+
                 mavenBundle(CONTROLLER, "protocol-framework").versionAsInProject(), //
                 mavenBundle(CONTROLLER, "config-manager").versionAsInProject(), // //
                 mavenBundle("commons-io", "commons-io").versionAsInProject(), //
@@ -64,12 +71,6 @@ public class TestHelper {
 
                 mavenBundle(CONTROLLER, "config-persister-impl").versionAsInProject(), //
 
-                mavenBundle("io.netty", "netty-handler").versionAsInProject(), //
-                mavenBundle("io.netty", "netty-codec").versionAsInProject(), //
-                mavenBundle("io.netty", "netty-buffer").versionAsInProject(), //
-                mavenBundle("io.netty", "netty-transport").versionAsInProject(), //
-                mavenBundle("io.netty", "netty-common").versionAsInProject(), //
-
                 mavenBundle("org.apache.servicemix.bundles", "org.apache.servicemix.bundles.xerces", "2.11.0_1"),
                 mavenBundle("org.eclipse.birt.runtime.3_7_1", "org.apache.xml.resolver", "1.2.0"),
 
index 9ac94e7b8904a3148128ca0f01f6b7d6a72fa5d0..019fc0eb73949a55163c8ddd7b9dcc2bee065037 100644 (file)
@@ -25,6 +25,7 @@ import static org.opendaylight.controller.test.sal.binding.it.TestHelper.junitAn
 import static org.opendaylight.controller.test.sal.binding.it.TestHelper.mdSalCoreBundles;
 import static org.ops4j.pax.exam.CoreOptions.mavenBundle;
 import static org.ops4j.pax.exam.CoreOptions.options;
+import static org.ops4j.pax.exam.CoreOptions.systemPackages;
 import static org.ops4j.pax.exam.CoreOptions.systemProperty;
 
 @RunWith(PaxExam.class)
@@ -70,6 +71,7 @@ public abstract class AbstractTest {
                 mavenBundle("ch.qos.logback", "logback-core").versionAsInProject(), //
                 mavenBundle("ch.qos.logback", "logback-classic").versionAsInProject(), //
                 systemProperty("osgi.bundles.defaultStartLevel").value("4"),
+                systemPackages("sun.nio.ch"),
 
                 mdSalCoreBundles(),
 
index 126fe8d39eebb2c745ba1a85bf34a2dffca55df1..8798897a1def5063a5e9c7cb501c43c14f80566c 100644 (file)
@@ -1,17 +1,21 @@
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
     <modelVersion>4.0.0</modelVersion>
     <parent>
         <groupId>org.opendaylight.controller</groupId>
         <artifactId>sal-parent</artifactId>
         <version>1.1-SNAPSHOT</version>
     </parent>
+
     <artifactId>sal-common-api</artifactId>
+    <packaging>bundle</packaging>
+
     <scm>
-      <connection>scm:git:ssh://git.opendaylight.org:29418/controller.git</connection>
-      <developerConnection>scm:git:ssh://git.opendaylight.org:29418/controller.git</developerConnection>
-      <url>https://wiki.opendaylight.org/view/OpenDaylight_Controller:MD-SAL</url>
-      <tag>HEAD</tag>
-  </scm>
+        <connection>scm:git:ssh://git.opendaylight.org:29418/controller.git</connection>
+        <developerConnection>scm:git:ssh://git.opendaylight.org:29418/controller.git</developerConnection>
+        <url>https://wiki.opendaylight.org/view/OpenDaylight_Controller:MD-SAL</url>
+        <tag>HEAD</tag>
+    </scm>
 
     <dependencies>
         <dependency>
@@ -22,6 +26,9 @@
             <groupId>org.opendaylight.yangtools</groupId>
             <artifactId>concepts</artifactId>
         </dependency>
+        <dependency>
+            <groupId>com.google.guava</groupId>
+            <artifactId>guava</artifactId>
+        </dependency>
     </dependencies>
-    <packaging>bundle</packaging>
 </project>
diff --git a/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/AsyncDataBroker.java b/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/AsyncDataBroker.java
new file mode 100644 (file)
index 0000000..87bbfd3
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.md.sal.common.api.data;
+
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.concepts.Path;
+
+public interface AsyncDataBroker<P extends Path<P>, D, L extends AsyncDataChangeListener<P, D>> extends //
+        AsyncDataTransactionFactory<P, D> {
+
+    /**
+     *
+     * Scope of Data Change
+     *
+     * Represents scope of data change (addition, replacement, deletion).
+     *
+     * The terminology for types is reused from LDAP
+     *
+     * @see http://www.idevelopment.info/data/LDAP/LDAP_Resources/SEARCH_Setting_the_SCOPE_Parameter.shtml
+     */
+    public enum DataChangeScope {
+
+       /**
+        * Represents only a direct change of the node, such as replacement of node,
+        * addition or deletion.
+        *
+        */
+       BASE,
+       /**
+        * Represent a change (addition,replacement,deletion)
+        * of the node or one of it's direct childs.
+        *
+        */
+       ONE,
+       /**
+        * Represents a change of the node or any of it's child nodes.
+        *
+        */
+       SUBTREE
+    }
+
+    @Override
+    public AsyncReadTransaction<P, D> newReadOnlyTransaction();
+
+    @Override
+    public AsyncReadWriteTransaction<P,D> newReadWriteTransaction();
+
+    @Override
+    public AsyncWriteTransaction<P, D> newWriteOnlyTransaction();
+
+    /**
+     * Registers {@link DataChangeListener} for Data Change callbacks
+     * which will be triggered on which will be triggered on the store
+     *
+     * @param store Logical store in which listener is registered.
+     * @param path Path (subtree identifier) on which client listener will be invoked.
+     * @param listener Instance of listener which should be invoked on
+     * @param triggeringScope Scope of change which triggers callback.
+     * @return Listener registration of the listener, call {@link ListenerRegistration#close()}
+     *         to stop delivery of change events.
+     */
+    ListenerRegistration<L> registerDataChangeListener(LogicalDatastoreType store, P path, L listener, DataChangeScope triggeringScope);
+}
diff --git a/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/AsyncDataChangeEvent.java b/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/AsyncDataChangeEvent.java
new file mode 100644 (file)
index 0000000..f612e51
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.md.sal.common.api.data;
+
+import java.util.Map;
+import java.util.Set;
+
+import org.opendaylight.yangtools.concepts.Immutable;
+import org.opendaylight.yangtools.concepts.Path;
+
+public interface AsyncDataChangeEvent<P extends Path<P>,D> extends Immutable {
+    /**
+     * Returns a immutable map of paths and newly created objects
+     *
+     * @return map of paths and newly created objects
+     */
+    Map<P, D> getCreatedData();
+
+    /**
+     * Returns a immutable map of paths and respective updated objects after update.
+     *
+     * Original state of the object is in
+     * {@link #getOriginalData()}
+     *
+     * @return map of paths and newly created objects
+     */
+    Map<P, D> getUpdatedData();
+
+    /**
+     * Returns a immutable set of removed paths.
+     *
+     * Original state of the object is in
+     * {@link #getOriginalData()}
+     *
+     * @return set of removed paths
+     */
+    Set<P> getRemovedPaths();
+
+    /**
+     * Return a immutable map of paths and original state of updated and removed objects.
+     *
+     * This map is populated if at changed path was previous object, and captures
+     * state of previous object.
+     *
+     * @return map of paths and original state of updated and removed objects.
+     */
+    Map<P, ? extends D> getOriginalData();
+
+    /**
+     * Returns a  immutable stable view of data state, which
+     * captures state of data store before the reported change.
+     *
+     *
+     * The view is rooted at the point where the listener, to which the event is being delivered, was registered.
+     *
+     * @return Stable view of data before the change happened, rooted at the listener registration path.
+     *
+     */
+    D getOriginalSubtree();
+
+    /**
+     * Returns a immutable stable view of data, which captures state of data store
+     * after the reported change.
+     *
+     * The view is rooted at the point where the listener, to which the event is being delivered, was registered.
+     *
+     * @return Stable view of data after the change happened, rooted at the listener registration path.
+     */
+    D getUpdatedSubtree();
+}
diff --git a/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/AsyncDataChangeListener.java b/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/AsyncDataChangeListener.java
new file mode 100644 (file)
index 0000000..49f07bc
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.md.sal.common.api.data;
+
+import java.util.EventListener;
+
+import org.opendaylight.yangtools.concepts.Path;
+
+public interface AsyncDataChangeListener<P extends Path<P>, D> extends EventListener {
+    /**
+     * Note that this method may be invoked from a shared thread pool, so
+     * implementations SHOULD NOT perform CPU-intensive operations and they
+     * definitely MUST NOT invoke any potentially blocking operations.
+     *
+     * @param change Data Change Event being delivered.
+     */
+    void onDataChanged(AsyncDataChangeEvent<P, D> change);
+}
diff --git a/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/AsyncDataTransactionFactory.java b/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/AsyncDataTransactionFactory.java
new file mode 100644 (file)
index 0000000..732fed0
--- /dev/null
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.md.sal.common.api.data;
+
+import org.opendaylight.yangtools.concepts.Path;
+
+public interface AsyncDataTransactionFactory<P extends Path<P>, D> {
+
+    AsyncReadTransaction<P, D> newReadOnlyTransaction();
+
+    AsyncReadWriteTransaction<P, D> newReadWriteTransaction();
+
+    AsyncWriteTransaction<P,D> newWriteOnlyTransaction();
+
+}
diff --git a/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/AsyncReadTransaction.java b/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/AsyncReadTransaction.java
new file mode 100644 (file)
index 0000000..1d1d910
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.md.sal.common.api.data;
+
+import java.util.concurrent.Future;
+
+import org.opendaylight.yangtools.concepts.Path;
+
+import com.google.common.base.Optional;
+import com.google.common.util.concurrent.ListenableFuture;
+
+public interface AsyncReadTransaction<P extends Path<P>, D> extends AsyncTransaction<P, D> {
+
+    /**
+     *
+     * Reads data from provided logical data store located at provided path
+     *
+     *
+     * @param store
+     *            Logical data store from which read should occur.
+     * @param path
+     *            Path which uniquely identifies subtree which client want to
+     *            read
+     * @return Listenable Future which contains read result
+     *         <ul>
+     *         <li>If data at supplied path exists the {@link Future#get()}
+     *         returns Optional object containing data
+     *         <li>If data at supplied path does not exists the
+     *         {@link Future#get()} returns {@link Optional#absent()}.
+     *         </ul>
+     */
+    ListenableFuture<Optional<D>> read(LogicalDatastoreType store, P path);
+
+}
diff --git a/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/AsyncReadWriteTransaction.java b/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/AsyncReadWriteTransaction.java
new file mode 100644 (file)
index 0000000..ce740bf
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.md.sal.common.api.data;
+
+import org.opendaylight.yangtools.concepts.Path;
+
+/**
+ * Transaction enabling client to have combined transaction,
+ * which provides read and write capabilities.
+ *
+ *
+ * @param <P> Path Type
+ * @param <D> Data Type
+ */
+public interface AsyncReadWriteTransaction<P extends Path<P>, D> extends AsyncReadTransaction<P, D>,
+        AsyncWriteTransaction<P, D> {
+
+}
diff --git a/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/AsyncTransaction.java b/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/AsyncTransaction.java
new file mode 100644 (file)
index 0000000..23ca275
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.md.sal.common.api.data;
+
+import org.opendaylight.yangtools.concepts.Identifiable;
+import org.opendaylight.yangtools.concepts.Path;
+
+
+/**
+ *
+ * @author
+ *
+ * @param <P> Type of path (subtree identifier), which represents location in tree
+ * @param <D> Type of data (payload), which represents data payload
+ */
+public interface AsyncTransaction<P extends Path<P>,D> extends //
+    Identifiable<Object>,
+    AutoCloseable {
+
+    @Override
+    public Object getIdentifier();
+
+    /**
+     * Closes transaction and releases all resources associated with it.
+     */
+    @Override
+    public void close();
+}
diff --git a/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/AsyncWriteTransaction.java b/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/AsyncWriteTransaction.java
new file mode 100644 (file)
index 0000000..35b9914
--- /dev/null
@@ -0,0 +1,119 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.md.sal.common.api.data;
+
+import java.util.concurrent.Future;
+
+import org.opendaylight.controller.md.sal.common.api.TransactionStatus;
+import org.opendaylight.yangtools.concepts.Path;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+
+public interface AsyncWriteTransaction<P extends Path<P>, D>  extends AsyncTransaction<P, D> {
+    /**
+     * Cancels transaction.
+     *
+     * Transaction could be only cancelled if it's status
+     * is {@link TransactionStatus#NEW} or {@link TransactionStatus#SUBMITED}
+     *
+     * Invoking cancel() on {@link TransactionStatus#FAILED} or {@link TransactionStatus#CANCELED}
+     * will have no effect.
+     *
+     * @throws IllegalStateException If transaction status is {@link TransactionStatus#COMMITED}
+     *
+     */
+    public void cancel();
+
+    /**
+     * Store a piece of data at specified path. This acts as a add / replace operation,
+     * which is to say that whole subtree will be replaced by specified path.
+     *
+     * If you need add or merge of current object with specified use {@link #merge(LogicalDatastoreType, Path, Object)}
+     *
+     * @param store Logical data store which should be modified
+     * @param path Data object path
+     * @param data Data object to be written to specified path
+     * @throws IllegalStateException if the transaction is no longer {@link TransactionStatus#NEW}
+     */
+    public void put(LogicalDatastoreType store, P path, D data);
+
+    /**
+     * Store a piece of data at specified path. This acts as a merge operation,
+     * which is to say that any pre-existing data which is not explicitly
+     * overwritten will be preserved. This means that if you store a container,
+     * its child lists will be merged. Performing the following put operations:
+     *
+     * 1) container { list [ a ] }
+     * 2) container { list [ b ] }
+     *
+     * will result in the following data being present:
+     *
+     * container { list [ a, b ] }
+     *
+     * This also means that storing the container will preserve any augmentations
+     * which have been attached to it.
+     *
+     * If you require an explicit replace operation, use {@link #put(LogicalDatastoreType, Path, Object)} instead.
+     *
+     * @param store Logical data store which should be modified
+     * @param path Data object path
+     * @param data Data object to be written to specified path
+     * @throws IllegalStateException if the transaction is no longer {@link TransactionStatus#NEW}
+     */
+    public void merge(LogicalDatastoreType store, P path, D data);
+
+    /**
+     * Remove a piece of data from specified path. This operation does not fail
+     * if the specified path does not exist.
+     *
+     * @param store Logical data store which should be modified
+     * @param path Data object path
+     * @throws IllegalStateException if the transaction is no longer {@link TransactionStatus#NEW}
+     */
+    public void delete(LogicalDatastoreType store, P path);
+
+    /**
+     *
+     * Closes transaction and resources allocated to the transaction.
+     *
+     * This call does not change Transaction status. Client SHOULD
+     * explicitly {@link #commit()} or {@link #cancel()} transaction.
+     *
+     * @throws IllegalStateException if the transaction has not been
+     *         updated by invoking {@link #commit()} or {@link #cancel()}.
+     */
+    @Override
+    public void close();
+
+    /**
+     * Initiates a commit of modification. This call logically seals the
+     * transaction, preventing any the client from interacting with the
+     * data stores. The transaction is marked as {@link TransactionStatus#SUBMITED}
+     * and enqueued into the data store backed for processing.
+     *
+     * <p>
+     * The successful commit changes the state of the system and may affect
+     * several components.
+     *
+     * <p>
+     * The effects of successful commit of data are described in the
+     * specifications and YANG models describing the Provider components of
+     * controller. It is assumed that Consumer has an understanding of this
+     * changes.
+     *
+     * @see DataCommitHandler for further information how two-phase commit is
+     *      processed.
+     * @param store Identifier of the store, where commit should occur.
+     * @return Result of the Commit, containing success information or list of
+     *         encountered errors, if commit was not successful. The Future
+     *         blocks until {@link TransactionStatus#COMMITED} or
+     *         {@link TransactionStatus#FAILED} is reached.
+     * @throws IllegalStateException if the transaction is not {@link TransactionStatus#NEW}
+     */
+    public Future<RpcResult<TransactionStatus>> commit();
+
+}
index 8787a3fe8d82de85bc7e064177501e017d041cca..669baa8d9e96a6601bfe7cbe49cb99d2ffb00233 100644 (file)
@@ -12,6 +12,12 @@ import java.util.EventListener;
 import org.opendaylight.yangtools.concepts.Path;
 
 public interface DataChangeListener<P extends Path<P>, D> extends EventListener {
-
+    /**
+     * Note that this method may be invoked from a shared thread pool, so
+     * implementations SHOULD NOT perform CPU-intensive operations and they
+     * definitely MUST NOT invoke any potentially blocking operations.
+     *
+     * @param change Data Change Event being delivered.
+     **/
     void onDataChanged(DataChangeEvent<P, D> change);
 }
diff --git a/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/LogicalDatastoreType.java b/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/LogicalDatastoreType.java
new file mode 100644 (file)
index 0000000..d2e41f1
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.md.sal.common.api.data;
+
+public enum LogicalDatastoreType {
+
+    /**
+     * Logical atastore representing operational state of the system
+     * and it's components
+     *
+     * This datastore is used to describe operational state of
+     * the system and it's operation related data.
+     *
+     */
+    OPERATIONAL,
+    /**
+     * Logical Datastore representing configuration state of the system
+     * and it's components.
+     *
+     * This datastore is used to describe intended state of
+     * the system and intended operation mode.
+     *
+     */
+    CONFIGURATION
+
+}
index d542935dd6dbf0fdb91ce72b273d6bc9c87b2668..e7e0eb0ff87e424973de4b9c9d6fdf9111ccae4c 100644 (file)
@@ -13,17 +13,34 @@ import org.opendaylight.yangtools.concepts.Path;
  * A chain of transactions. Transactions in a chain need to be committed in sequence and each
  * transaction should see the effects of previous transactions as if they happened. A chain
  * makes no guarantees of atomicity, in fact transactions are committed as soon as possible.
+ *
  */
-public interface TransactionChain<P extends Path<P>, D> extends AutoCloseable {
+public interface TransactionChain<P extends Path<P>, D> extends AutoCloseable, AsyncDataTransactionFactory<P, D> {
+
     /**
-     * Create a new transaction which will continue the chain. The previous transaction
-     * has to be either COMMITTED or CANCELLED.
+     * Create a new read only transaction which will continue the chain.
+     * The previous read-write transaction has to be either COMMITED or CANCELLED.
      *
      * @return New transaction in the chain.
-     * @throws IllegalStateException if the previous transaction was not COMMITTED or CANCELLED.
+     * @throws IllegalStateException if the previous transaction was not COMMITED
+     *    or CANCELLED.
      * @throws TransactionChainClosedException if the chain has been closed.
      */
-    DataModification<P, D> newTransaction();
+    @Override
+    public AsyncReadTransaction<P, D> newReadOnlyTransaction();
+
+
+    /**
+     * Create a new read write transaction which will continue the chain.
+     * The previous read-write transaction has to be either COMMITED or CANCELLED.
+     *
+     * @return New transaction in the chain.
+     * @throws IllegalStateException if the previous transaction was not COMMITTED
+     *    or CANCELLED.
+     * @throws TransactionChainClosedException if the chain has been closed.
+     */
+    @Override
+    public AsyncReadWriteTransaction<P, D> newReadWriteTransaction();
 
     @Override
     void close();
index 4dac6f557ebda436b29d2e1aaea9df86682fb90a..52b0812736af1f236c292b28eefe9fe51db1245c 100644 (file)
@@ -21,7 +21,7 @@ public interface TransactionChainListener extends EventListener {
      * @param transaction Transaction which caused the chain to fail
      * @param cause The cause of transaction failure
      */
-    void onTransactionChainFailed(TransactionChain<?, ?> chain, DataModification<?, ?> transaction, Throwable cause);
+    void onTransactionChainFailed(TransactionChain<?, ?> chain, AsyncTransaction<?, ?> transaction, Throwable cause);
 
     /**
      * Invoked when a transaction chain is completed. A transaction chain is considered completed when it has been
diff --git a/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/md/sal/dom/api/DOMDataBroker.java b/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/md/sal/dom/api/DOMDataBroker.java
new file mode 100644 (file)
index 0000000..5328b79
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.md.sal.dom.api;
+
+import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+
+public interface DOMDataBroker extends AsyncDataBroker<InstanceIdentifier, NormalizedNode<?, ?>, DOMDataChangeListener>{
+    @Override
+    DOMDataReadTransaction newReadOnlyTransaction();
+
+    @Override
+    DOMDataReadWriteTransaction newReadWriteTransaction();
+
+    @Override
+    DOMDataWriteTransaction newWriteOnlyTransaction();
+}
diff --git a/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/md/sal/dom/api/DOMDataChangeListener.java b/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/md/sal/dom/api/DOMDataChangeListener.java
new file mode 100644 (file)
index 0000000..d1f0176
--- /dev/null
@@ -0,0 +1,16 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.md.sal.dom.api;
+
+import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeListener;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+
+public interface DOMDataChangeListener extends AsyncDataChangeListener<InstanceIdentifier, NormalizedNode<?, ?>> {
+
+}
diff --git a/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/md/sal/dom/api/DOMDataReadTransaction.java b/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/md/sal/dom/api/DOMDataReadTransaction.java
new file mode 100644 (file)
index 0000000..5baa5e7
--- /dev/null
@@ -0,0 +1,16 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.md.sal.dom.api;
+
+import org.opendaylight.controller.md.sal.common.api.data.AsyncReadTransaction;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+
+public interface DOMDataReadTransaction extends AsyncReadTransaction<InstanceIdentifier, NormalizedNode<?, ?>> {
+
+}
diff --git a/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/md/sal/dom/api/DOMDataReadWriteTransaction.java b/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/md/sal/dom/api/DOMDataReadWriteTransaction.java
new file mode 100644 (file)
index 0000000..55600b0
--- /dev/null
@@ -0,0 +1,16 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.md.sal.dom.api;
+
+import org.opendaylight.controller.md.sal.common.api.data.AsyncReadWriteTransaction;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+
+public interface DOMDataReadWriteTransaction extends DOMDataReadTransaction, DOMDataWriteTransaction, AsyncReadWriteTransaction<InstanceIdentifier, NormalizedNode<?, ?>> {
+
+}
diff --git a/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/md/sal/dom/api/DOMDataWriteTransaction.java b/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/md/sal/dom/api/DOMDataWriteTransaction.java
new file mode 100644 (file)
index 0000000..9415973
--- /dev/null
@@ -0,0 +1,16 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.md.sal.dom.api;
+
+import org.opendaylight.controller.md.sal.common.api.data.AsyncWriteTransaction;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+
+public interface DOMDataWriteTransaction extends AsyncWriteTransaction<InstanceIdentifier, NormalizedNode<?, ?>> {
+
+}
diff --git a/opendaylight/md-sal/sal-dom-spi/src/main/java/org/opendaylight/controller/sal/core/spi/data/DOMStore.java b/opendaylight/md-sal/sal-dom-spi/src/main/java/org/opendaylight/controller/sal/core/spi/data/DOMStore.java
new file mode 100644 (file)
index 0000000..c82a2b8
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.core.spi.data;
+
+import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope;
+import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeListener;
+import org.opendaylight.controller.md.sal.common.api.data.DataChangeListener;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+
+public interface DOMStore {
+
+    /**
+     *
+     * Creates a read only transaction
+     *
+     * @return
+     */
+    DOMStoreReadTransaction newReadOnlyTransaction();
+
+    /**
+     * Creates write only transaction
+     *
+     * @return
+     */
+    DOMStoreWriteTransaction newWriteOnlyTransaction();
+
+    /**
+     * Creates Read-Write transaction
+     *
+     * @return
+     */
+    DOMStoreReadWriteTransaction newReadWriteTransaction();
+
+    /**
+     * Registers {@link DataChangeListener} for Data Change callbacks
+     * which will be triggered on the change of provided subpath. What
+     * constitutes a change depends on the @scope parameter.
+     *
+     * Listener upon registration receives an initial callback
+     * {@link AsyncDataChangeListener#onDataChanged(org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent)}
+     * which contains stable view of data tree at the time of registration.
+     *
+     * @param path Path (subtree identifier) on which client listener will be invoked.
+     * @param listener Instance of listener which should be invoked on
+     * @param scope Scope of change which triggers callback.
+     * @return Listener Registration object, which client may use to close registration
+     *         / interest on receiving data changes.
+     *
+     */
+    <L extends AsyncDataChangeListener<InstanceIdentifier, NormalizedNode<?, ?>>> ListenerRegistration<L> registerChangeListener(
+            InstanceIdentifier path, L listener, DataChangeScope scope);
+
+}
diff --git a/opendaylight/md-sal/sal-dom-spi/src/main/java/org/opendaylight/controller/sal/core/spi/data/DOMStoreReadTransaction.java b/opendaylight/md-sal/sal-dom-spi/src/main/java/org/opendaylight/controller/sal/core/spi/data/DOMStoreReadTransaction.java
new file mode 100644 (file)
index 0000000..733c109
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.core.spi.data;
+
+import java.util.concurrent.Future;
+
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+
+import com.google.common.base.Optional;
+import com.google.common.util.concurrent.ListenableFuture;
+
+public interface DOMStoreReadTransaction extends DOMStoreTransaction {
+
+    /**
+     *
+     * Reads data from provided logical data store located at provided path
+     *
+     *
+     * @param path
+     *            Path which uniquely identifies subtree which client want to
+     *            read
+     * @return Listenable Future which contains read result
+     *         <ul>
+     *         <li>If data at supplied path exists the {@link Future#get()}
+     *         returns Optional object containing data
+     *         <li>If data at supplied path does not exists the
+     *         {@link Future#get()} returns {@link Optional#absent()}.
+     *         </ul>
+     */
+    ListenableFuture<Optional<NormalizedNode<?,?>>> read(InstanceIdentifier path);
+}
diff --git a/opendaylight/md-sal/sal-dom-spi/src/main/java/org/opendaylight/controller/sal/core/spi/data/DOMStoreReadWriteTransaction.java b/opendaylight/md-sal/sal-dom-spi/src/main/java/org/opendaylight/controller/sal/core/spi/data/DOMStoreReadWriteTransaction.java
new file mode 100644 (file)
index 0000000..7277406
--- /dev/null
@@ -0,0 +1,15 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.core.spi.data;
+
+/**
+ * Combination of a {@link DOMStoreReadTransaction} and {@link DOMStoreWriteTransaction}.
+ */
+public interface DOMStoreReadWriteTransaction extends DOMStoreReadTransaction, DOMStoreWriteTransaction {
+
+}
diff --git a/opendaylight/md-sal/sal-dom-spi/src/main/java/org/opendaylight/controller/sal/core/spi/data/DOMStoreThreePhaseCommitCohort.java b/opendaylight/md-sal/sal-dom-spi/src/main/java/org/opendaylight/controller/sal/core/spi/data/DOMStoreThreePhaseCommitCohort.java
new file mode 100644 (file)
index 0000000..986a153
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.core.spi.data;
+
+import com.google.common.util.concurrent.ListenableFuture;
+
+/**
+ * Interface implemented by the {@link DOMStore} and exposed for each {@link DOMStoreWriteTransaction}
+ * upon its transition to Ready state. The frontend (DOMStore user) uses this interface to drive the
+ * commit procedure across potentially multiple DOMStores using the Three-Phase-Commit (3PC) Protocol,
+ * as described in {@link https://en.wikipedia.org/wiki/Three-phase_commit}.
+ */
+public interface DOMStoreThreePhaseCommitCohort {
+
+    /**
+     * Sends transaction associated with this three phase commit instance to the
+     * participant, participant votes on the transaction, if the transaction
+     * should be committed or aborted.
+     *
+     * @return ListenableFuture with vote of the participant. Vote
+     *         {@link ListenableFuture#get()} is following:
+     *         <ul>
+     *         <li>
+     *         true if transaction is approved by data store.
+     *         <li>false if the transaction is not approved by data store and
+     *         should be aborted.
+     */
+    ListenableFuture<Boolean> canCommit();
+
+    /**
+     * Initiates a pre-commit phase of associated transaction on datastore.
+     *
+     * This message is valid only and only if and only if the participant responded
+     * on {@link #canCommit()} call with positive response.
+     *
+     * @return ListenableFuture representing acknowledgment for participant
+     *        that pre-commit message was received and processed.
+     */
+    ListenableFuture<Void> preCommit();
+
+    /**
+     * Initiates a abort phase of associated transaction on data store.
+     *
+     * @return ListenableFuture representing acknowledgment for participant
+     *        that abort message was received.
+     */
+    ListenableFuture<Void> abort();
+
+    /**
+     * Initiates a commit phase on of associated transaction on data store.
+     *
+     * @return ListenableFuture representing acknowledgment for participant
+     *        that commit message was received and commit of transaction was
+     *        processed.
+     */
+    ListenableFuture<Void> commit();
+}
diff --git a/opendaylight/md-sal/sal-dom-spi/src/main/java/org/opendaylight/controller/sal/core/spi/data/DOMStoreTransaction.java b/opendaylight/md-sal/sal-dom-spi/src/main/java/org/opendaylight/controller/sal/core/spi/data/DOMStoreTransaction.java
new file mode 100644 (file)
index 0000000..76ea78b
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.core.spi.data;
+
+import org.opendaylight.yangtools.concepts.Identifiable;
+
+/**
+ * DOM Data Store transaction
+ *
+ * See {@link DOMStoreReadTransaction}, {@link DOMStoreWriteTransaction} and {@link DOMStoreReadWriteTransaction}
+ * for specific transaction types.
+ *
+ */
+public interface DOMStoreTransaction extends AutoCloseable, Identifiable<Object> {
+    /**
+     * Unique identifier of the transaction
+     */
+    @Override
+    public Object getIdentifier();
+
+    @Override
+    void close();
+}
diff --git a/opendaylight/md-sal/sal-dom-spi/src/main/java/org/opendaylight/controller/sal/core/spi/data/DOMStoreWriteTransaction.java b/opendaylight/md-sal/sal-dom-spi/src/main/java/org/opendaylight/controller/sal/core/spi/data/DOMStoreWriteTransaction.java
new file mode 100644 (file)
index 0000000..6761bc1
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.core.spi.data;
+
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.yangtools.concepts.Path;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+
+public interface DOMStoreWriteTransaction extends DOMStoreTransaction {
+
+    /**
+     * Store a provided data at specified path. This acts as a add / replace
+     * operation, which is to say that whole subtree will be replaced by
+     * specified path.
+     *
+     * If you need add or merge of current object with specified use
+     * {@link #merge(LogicalDatastoreType, Path, Object)}
+     *
+     *
+     * @param path
+     * @param data
+     *            Data object to be written
+     *
+     * @throws IllegalStateException
+     *             if the client code already sealed transaction and invoked
+     *             {@link #ready()}
+     */
+    void write(InstanceIdentifier path, NormalizedNode<?, ?> data);
+
+    /**
+     *
+     * Deletes data and whole subtree located at provided path.
+     *
+     * @param path
+     *            Path to delete
+     * @throws IllegalStateException
+     *             if the client code already sealed transaction and invoked
+     *             {@link #ready()}
+     */
+    void delete(InstanceIdentifier path);
+
+    /**
+     *
+     * Seals transaction, and returns three-phase commit cohort associated
+     * with this transaction and DOM Store to be coordinated by coordinator.
+     *
+     * @return Three Phase Commit Cohort instance for this transaction.
+     */
+    DOMStoreThreePhaseCommitCohort ready();
+
+}
diff --git a/opendaylight/md-sal/sal-dom-spi/src/main/java/org/opendaylight/controller/sal/core/spi/data/package-info.java b/opendaylight/md-sal/sal-dom-spi/src/main/java/org/opendaylight/controller/sal/core/spi/data/package-info.java
new file mode 100644 (file)
index 0000000..ec3b698
--- /dev/null
@@ -0,0 +1,8 @@
+/*\r
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.\r
+ *\r
+ * This program and the accompanying materials are made available under the\r
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,\r
+ * and is available at http://www.eclipse.org/legal/epl-v10.html\r
+ */\r
+package org.opendaylight.controller.sal.core.spi.data;
\ No newline at end of file
index 38a4dd46617405c148022d4622a3b200b9182b80..000783bd07e545ee16ae5e306c20c8d72f4d6e35 100644 (file)
@@ -52,6 +52,7 @@ public class ToasterTest {
                 mavenBundle("ch.qos.logback", "logback-core").versionAsInProject(), //
                 mavenBundle("ch.qos.logback", "logback-classic").versionAsInProject(), //
                 systemProperty("osgi.bundles.defaultStartLevel").value("4"),
+                systemPackages("sun.nio.ch"),
 
                 toasterBundles(),
                 mdSalCoreBundles(),
index 15fee781ef77275a0213e4a842b85ed953ae8eaa..a9fc739456b95740c3ab9c00313c31711e7ebba9 100644 (file)
         <dependency>
             <groupId>io.netty</groupId>
             <artifactId>netty-all</artifactId>
-            <version>4.0.10.Final</version>
+           <version>${netty.version}</version>
             <scope>test</scope>
         </dependency>
         <dependency>
index 5fd9f2fcd1ba6f1152c9ca7ef317b574ca47f706..ee971a65ddc882bd11e7c0593f1b3f0168bcce99 100644 (file)
@@ -44,6 +44,7 @@ import static org.opendaylight.controller.test.sal.binding.it.TestHelper.junitAn
 import static org.opendaylight.controller.test.sal.binding.it.TestHelper.mdSalCoreBundles;
 import static org.ops4j.pax.exam.CoreOptions.mavenBundle;
 import static org.ops4j.pax.exam.CoreOptions.options;
+import static org.ops4j.pax.exam.CoreOptions.systemPackages;
 import static org.ops4j.pax.exam.CoreOptions.systemProperty;
 
 @RunWith(PaxExam.class)
@@ -62,6 +63,7 @@ public class IdentityRefNetconfTest {
                 systemProperty("osgi.console").value("2401"),
                 systemProperty("osgi.bundles.defaultStartLevel").value("4"),
                 systemProperty("pax.exam.osgi.unresolved.fail").value("true"),
+                systemPackages("sun.nio.ch"),
 
                 testingModules(),
                 loggingModules(),
index e7b9a025520f3d5ab64fa03b2852a9dc1ce61172..586366f41a63659bc8b75fd8ccbf12df97ae34bd 100644 (file)
@@ -47,7 +47,6 @@
         <osgi.version>5.0.0</osgi.version>
         <maven.bundle.version>2.4.0</maven.bundle.version>
         <slf4j.version>1.7.2</slf4j.version>
-        <netconf.netty.version>4.0.10.Final</netconf.netty.version>
         <salGeneratorPath>${project.build.directory}/generated-sources/sal</salGeneratorPath>
     </properties>
 
index 9ef56e5dc440b612f5f70e0ec823fca3172aad2c..9ddba67e251360996d6c72e50ad81e271c1c0f65 100644 (file)
@@ -29,6 +29,7 @@ import org.opendaylight.controller.northbound.commons.exception.NotAcceptableExc
 import org.opendaylight.controller.northbound.commons.exception.ResourceNotFoundException;
 import org.opendaylight.controller.northbound.commons.exception.ServiceUnavailableException;
 import org.opendaylight.controller.sal.core.Node;
+import org.opendaylight.controller.sal.networkconfig.bridgedomain.BridgeDomainConfigServiceException;
 import org.opendaylight.controller.sal.networkconfig.bridgedomain.ConfigConstants;
 import org.opendaylight.controller.sal.networkconfig.bridgedomain.IBridgeDomainConfigService;
 import org.opendaylight.controller.sal.utils.ServiceHelper;
@@ -114,9 +115,7 @@ public class BridgeDomainNorthbound {
            if (status.getCode().equals(StatusCode.SUCCESS)) {
                return Response.status(Response.Status.CREATED).build();
            }
-       } catch (Error e) {
-           throw e;
-       } catch (Throwable t) {
+       } catch (BridgeDomainConfigServiceException e) {
            return Response.status(Response.Status.PRECONDITION_FAILED).build();
        }
        throw new ResourceNotFoundException(status.getDescription());
index aa60f9117405270725514dc740f564ad8e2ccd03..f27d30eaae620312a75a7da2d47fa878936f5ccd 100644 (file)
@@ -54,6 +54,12 @@ public class SecureMessageReadWriteService implements IMessageReadWrite {
                                     // switch
     private ByteBuffer peerNetData; // encrypted message from the switch
     private FileInputStream kfd = null, tfd = null;
+    private final String keyStoreFileDefault = "./configuration/tlsKeyStore";
+    private final String trustStoreFileDefault = "./configuration/tlsTrustStore";
+    private final String keyStorePasswordPropName = "controllerKeyStorePassword";
+    private final String trustStorePasswordPropName = "controllerTrustStorePassword";
+    private static String keyStorePassword = null;
+    private static String trustStorePassword = null;
 
     public SecureMessageReadWriteService(SocketChannel socket, Selector selector)
             throws Exception {
@@ -80,32 +86,44 @@ public class SecureMessageReadWriteService implements IMessageReadWrite {
      */
     private void createSecureChannel(SocketChannel socket) throws Exception {
         String keyStoreFile = System.getProperty("controllerKeyStore");
-        String keyStorePassword = System
-                .getProperty("controllerKeyStorePassword");
         String trustStoreFile = System.getProperty("controllerTrustStore");
-        String trustStorePassword = System
-                .getProperty("controllerTrustStorePassword");
+        String keyStorePasswordProp = System.getProperty(keyStorePasswordPropName);
+        String trustStorePasswordProp = System.getProperty(trustStorePasswordPropName);
 
         if (keyStoreFile != null) {
             keyStoreFile = keyStoreFile.trim();
+        } else {
+            keyStoreFile = keyStoreFileDefault;
         }
         if ((keyStoreFile == null) || keyStoreFile.isEmpty()) {
             throw new FileNotFoundException("TLS KeyStore file not found.");
         }
+
+        if ((keyStorePassword == null) || ((keyStorePasswordProp != null) && !keyStorePasswordProp.isEmpty())) {
+            keyStorePassword = keyStorePasswordProp;
+        }
         if (keyStorePassword != null) {
             keyStorePassword = keyStorePassword.trim();
+            System.setProperty(keyStorePasswordPropName, "");
         }
         if ((keyStorePassword == null) || keyStorePassword.isEmpty()) {
             throw new FileNotFoundException("TLS KeyStore Password not provided.");
         }
         if (trustStoreFile != null) {
             trustStoreFile = trustStoreFile.trim();
+        } else {
+            trustStoreFile = trustStoreFileDefault;
         }
         if ((trustStoreFile == null) || trustStoreFile.isEmpty()) {
             throw new FileNotFoundException("TLS TrustStore file not found");
         }
+
+        if ((trustStorePassword == null) || ((trustStorePasswordProp != null) && !trustStorePasswordProp.isEmpty())) {
+            trustStorePassword = trustStorePasswordProp;
+        }
         if (trustStorePassword != null) {
             trustStorePassword = trustStorePassword.trim();
+            System.setProperty(trustStorePasswordPropName, "");
         }
         if ((trustStorePassword == null) || trustStorePassword.isEmpty()) {
             throw new FileNotFoundException("TLS TrustStore Password not provided.");
diff --git a/opendaylight/sal/networkconfiguration/api/src/main/java/org/opendaylight/controller/sal/networkconfig/bridgedomain/BridgeDomainConfigServiceException.java b/opendaylight/sal/networkconfiguration/api/src/main/java/org/opendaylight/controller/sal/networkconfig/bridgedomain/BridgeDomainConfigServiceException.java
new file mode 100644 (file)
index 0000000..19f467e
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.networkconfig.bridgedomain;
+
+/**
+ * Exception thrown by IPluginInBridgeDomainConfigService implementations.
+ */
+public class BridgeDomainConfigServiceException extends Exception {
+    private static final long serialVersionUID = 1L;
+
+    public BridgeDomainConfigServiceException(String message) {
+        super(message);
+    }
+
+    public BridgeDomainConfigServiceException(String message, Throwable cause) {
+        super(message, cause);
+    }
+}
+
index f8696b1cec347372d7cb27b8b28d43ee22eb38cb..c84136115c434c0a26367afcf1a438670e37f119 100644 (file)
@@ -29,7 +29,7 @@ public interface IPluginInBridgeDomainConfigService {
      * @note This method will return false if one or more of the supplied params is not supported by the
      * protocol plugin that serves the Node.
      */
-    public Status createBridgeDomain(Node node, String bridgeIdentifier, Map<ConfigConstants, Object> params) throws Throwable;
+    public Status createBridgeDomain(Node node, String bridgeIdentifier, Map<ConfigConstants, Object> params) throws BridgeDomainConfigServiceException;
 
     /**
      * Delete a Bridge Domain
index 64c72115f61519895ea3d8e3e44121b646319b77..14c5e0d9e72ada56a7d8d4c2f55e477e2a5f95f1 100644 (file)
@@ -14,6 +14,7 @@ import java.util.concurrent.ConcurrentMap;
 
 import org.opendaylight.controller.sal.core.Node;
 import org.opendaylight.controller.sal.core.NodeConnector;
+import org.opendaylight.controller.sal.networkconfig.bridgedomain.BridgeDomainConfigServiceException;
 import org.opendaylight.controller.sal.networkconfig.bridgedomain.ConfigConstants;
 import org.opendaylight.controller.sal.networkconfig.bridgedomain.IBridgeDomainConfigService;
 import org.opendaylight.controller.sal.networkconfig.bridgedomain.IPluginInBridgeDomainConfigService;
@@ -26,7 +27,7 @@ import org.slf4j.LoggerFactory;
 public class BridgeDomainConfigService implements IBridgeDomainConfigService {
     protected static final Logger logger = LoggerFactory
             .getLogger(BridgeDomainConfigService.class);
-    private ConcurrentMap<String, IPluginInBridgeDomainConfigService> pluginService =
+    private final ConcurrentMap<String, IPluginInBridgeDomainConfigService> pluginService =
             new ConcurrentHashMap<String, IPluginInBridgeDomainConfigService>();
 
     void setPluginInService (Map props, IPluginInBridgeDomainConfigService s) {
@@ -80,7 +81,7 @@ public class BridgeDomainConfigService implements IBridgeDomainConfigService {
 
     @Override
     public Status createBridgeDomain(Node node, String bridgeIdentifier, Map<ConfigConstants, Object> params)
-            throws Throwable {
+            throws BridgeDomainConfigServiceException {
         if (pluginService != null) {
             IPluginInBridgeDomainConfigService plugin = this.pluginService.get(node.getType());
             if (plugin != null) {
index e4bb790676379bfb508ea6b6eec4051a38286636..a9f11fafb5c2ae2e9434dc24f232f21b1a3b59d1 100644 (file)
@@ -774,7 +774,7 @@ public class Devices implements IDaylightWeb {
         return result;
     }
 
-    @RequestMapping(value = "/connect/{nodeId}", method = RequestMethod.POST)
+    @RequestMapping(value = "/connect/{nodeId:.+}", method = RequestMethod.POST)
     @ResponseBody
     public Status addNode(HttpServletRequest request, @PathVariable("nodeId") String nodeId,
             @RequestParam(required = true) String ipAddress, @RequestParam(required = true) String port,
@@ -811,7 +811,7 @@ public class Devices implements IDaylightWeb {
         return new Status(StatusCode.SUCCESS);
     }
 
-    @RequestMapping(value = "/disconnect/{nodeId}", method = RequestMethod.POST)
+    @RequestMapping(value = "/disconnect/{nodeId:.+}", method = RequestMethod.POST)
     @ResponseBody
     public Status removeNode(HttpServletRequest request, @PathVariable("nodeId") String nodeId,
             @RequestParam(required = true) String nodeType) {
index 259ffde4b447e1d5d8c916ff96a26ee38198b3bf..9c3c895916b03f88c579996d91d27c15b842776c 100644 (file)
@@ -14,11 +14,15 @@ import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import java.util.TreeMap;
 
 import javax.servlet.http.HttpServletRequest;
 
 import org.opendaylight.controller.forwardingrulesmanager.FlowConfig;
 import org.opendaylight.controller.forwardingrulesmanager.IForwardingRulesManager;
+import org.opendaylight.controller.sal.action.Action;
+import org.opendaylight.controller.sal.action.ActionType;
+import org.opendaylight.controller.sal.action.SupportedFlowActions;
 import org.opendaylight.controller.sal.authorization.Privilege;
 import org.opendaylight.controller.sal.authorization.UserLevel;
 import org.opendaylight.controller.sal.core.Description;
@@ -212,7 +216,6 @@ public class Flows implements IDaylightWeb {
         return nodes;
     }
 
-
     @RequestMapping(value = "/flow", method = RequestMethod.POST)
     @ResponseBody
     public String actionFlow(@RequestParam(required = true) String action, @RequestParam(required = false) String body,
@@ -337,6 +340,83 @@ public class Flows implements IDaylightWeb {
         }
     }
 
+    @RequestMapping(value = "/valid-flows/{nodeId}")
+    @ResponseBody
+    public Object getValidActions(HttpServletRequest request, @RequestParam(required = false) String container,
+            @PathVariable("nodeId") String nodeId) {
+        String containerName = (container == null) ? GlobalConstants.DEFAULT.toString() : container;
+
+        // Authorization check
+        String userName = request.getUserPrincipal().getName();
+        if (DaylightWebUtil.getContainerPrivilege(userName, containerName, this) != Privilege.WRITE) {
+            return "Operation not authorized";
+        }
+
+        ISwitchManager switchManager = (ISwitchManager) ServiceHelper.getInstance(ISwitchManager.class, containerName, this);
+        if (switchManager == null) {
+            return null;
+        }
+
+        Map<String, String> result = new TreeMap<String, String>();
+
+        Node node = Node.fromString(nodeId);
+        SupportedFlowActions supportedFlows = (SupportedFlowActions) switchManager.getNodeProp(node, "supportedFlowActions");
+        List<Class<? extends Action>> actions = supportedFlows.getActions();
+        for (Class<? extends Action> action : actions) {
+            if (action.isAssignableFrom(org.opendaylight.controller.sal.action.Drop.class)) {
+                result.put(ActionType.DROP.toString(), "Drop");
+            } else if (action.isAssignableFrom(org.opendaylight.controller.sal.action.Loopback.class)) {
+                result.put(ActionType.LOOPBACK.toString(), "Loopback");
+            } else if (action.isAssignableFrom(org.opendaylight.controller.sal.action.Flood.class)) {
+                result.put(ActionType.FLOOD.toString(), "Flood");
+            } else if (action.isAssignableFrom(org.opendaylight.controller.sal.action.FloodAll.class)) {
+                result.put(ActionType.FLOOD_ALL.toString(), "Flood All");
+            } else if (action.isAssignableFrom(org.opendaylight.controller.sal.action.Controller.class)) {
+                result.put(ActionType.CONTROLLER.toString(), "Controller");
+            } else if (action.isAssignableFrom(org.opendaylight.controller.sal.action.SwPath.class)) {
+                result.put(ActionType.SW_PATH.toString(), "Software Path");
+            } else if (action.isAssignableFrom(org.opendaylight.controller.sal.action.HwPath.class)) {
+                result.put(ActionType.HW_PATH.toString(), "Hardware Path");
+            } else if (action.isAssignableFrom(org.opendaylight.controller.sal.action.Output.class)) {
+                result.put(ActionType.OUTPUT.toString(), "Output");
+            } else if (action.isAssignableFrom(org.opendaylight.controller.sal.action.Enqueue.class)) {
+                result.put(ActionType.ENQUEUE.toString(), "Enqueue");
+            } else if (action.isAssignableFrom(org.opendaylight.controller.sal.action.SetDlSrc.class)) {
+                result.put(ActionType.SET_DL_SRC.toString(), "Set Datalayer Source Address");
+            } else if (action.isAssignableFrom(org.opendaylight.controller.sal.action.SetDlDst.class)) {
+                result.put(ActionType.SET_DL_DST.toString(), "Set Datalayer Destination Address");
+            } else if (action.isAssignableFrom(org.opendaylight.controller.sal.action.SetVlanId.class)) {
+                result.put(ActionType.SET_VLAN_ID.toString(), "Set VLAN ID");
+            } else if (action.isAssignableFrom(org.opendaylight.controller.sal.action.SetVlanPcp.class)) {
+                result.put(ActionType.SET_VLAN_PCP.toString(), "Set VLAN Priority");
+            } else if (action.isAssignableFrom(org.opendaylight.controller.sal.action.SetVlanCfi.class)) {
+                result.put(ActionType.SET_VLAN_CFI.toString(), "Set VLAN CFI");
+            } else if (action.isAssignableFrom(org.opendaylight.controller.sal.action.PopVlan.class)) {
+                result.put(ActionType.POP_VLAN.toString(), "Pop VLAN");
+            } else if (action.isAssignableFrom(org.opendaylight.controller.sal.action.PushVlan.class)) {
+                result.put(ActionType.PUSH_VLAN.toString(), "Push VLAN");
+            } else if (action.isAssignableFrom(org.opendaylight.controller.sal.action.SetDlType.class)) {
+                result.put(ActionType.SET_DL_TYPE.toString(), "Set EtherType");
+            } else if (action.isAssignableFrom(org.opendaylight.controller.sal.action.SetNwSrc.class)) {
+                result.put(ActionType.SET_NW_SRC.toString(), "Set Network Source Address");
+            } else if (action.isAssignableFrom(org.opendaylight.controller.sal.action.SetNwDst.class)) {
+                result.put(ActionType.SET_NW_DST.toString(), "Set Network Destination Address");
+            } else if (action.isAssignableFrom(org.opendaylight.controller.sal.action.SetNwTos.class)) {
+                result.put(ActionType.SET_NW_TOS.toString(), "Modify ToS Bits");
+            } else if (action.isAssignableFrom(org.opendaylight.controller.sal.action.SetTpSrc.class)) {
+                result.put(ActionType.SET_TP_SRC.toString(), "Modify Transport Source Port");
+            } else if (action.isAssignableFrom(org.opendaylight.controller.sal.action.SetTpDst.class)) {
+                result.put(ActionType.SET_TP_DST.toString(), "Modify Transport Destination Port");
+            }
+        }
+
+        return result;
+    }
+
+    private boolean actionCompare(String name, ActionType type) {
+        return name.equals(type.getId().toLowerCase());
+    }
+
     private String getNodeDesc(Node node, ISwitchManager switchManager) {
         Description desc = (Description) switchManager.getNodeProp(node, Description.propertyName);
         String description = (desc == null) ? "" : desc.getValue();
index ab8301bf73dd21fb842aeee16b3a80dc647039a2..6e7fd25e049a17fc997b30c5d2003227e1b9a61f 100644 (file)
@@ -11,1593 +11,1723 @@ one.f = {};
 
 // specify dashlets and layouts
 one.f.dashlet = {
-    flows : {
-        id : 'flows',
-        name : 'Flow Entries'
-    },
-    nodes : {
-        id : 'nodes',
-        name : 'Nodes'
-    },
-    detail : {
-        id : 'detail',
-        name : 'Flow Detail'
-    }
+  flows : {
+    id : 'flows',
+    name : 'Flow Entries'
+  },
+  nodes : {
+    id : 'nodes',
+    name : 'Nodes'
+  },
+  detail : {
+    id : 'detail',
+    name : 'Flow Detail'
+  }
 };
 
 one.f.menu = {
-    left : {
-        top : [
-            one.f.dashlet.flows
-        ],
-        bottom : [
-            one.f.dashlet.nodes
-        ]
-    },
-    right : {
-        top : [],
-        bottom : [
-            one.f.dashlet.detail
-        ]
-    }
+  left : {
+    top : [
+      one.f.dashlet.flows
+      ],
+    bottom : [
+      one.f.dashlet.nodes
+      ]
+  },
+  right : {
+    top : [],
+    bottom : [
+      one.f.dashlet.detail
+      ]
+  }
 };
 
 one.f.address = {
-    root : "/controller/web/flows",
-    flows : {
-        main : "/main",
-        flows : "/node-flows",
-        nodes : "/node-ports",
-        flow : "/flow",
-        modifyFlow : "/modifyFlow",
-        deleteFlows:"/flow/deleteFlows"
-    }
+  root : "/controller/web/flows",
+  flows : {
+    main : "/main",
+    flows : "/node-flows",
+    nodes : "/node-ports",
+    flow : "/flow",
+    modifyFlow : "/modifyFlow",
+    deleteFlows:"/flow/deleteFlows"
+  }
 }
 
 /** NODES **/
 one.f.nodes = {
-    id : {
-        dashlet: {
-            datagrid: "one_f_nodes_id_dashlet_datagrid"
-        }
-    },
-    registry : {},
-    dashlet : function($dashlet) {
-        var $h4 = one.lib.dashlet.header("Nodes");
-        $dashlet.append($h4);
-
-        one.f.nodes.ajax.dashlet(function(data) {
-            var $gridHTML = one.lib.dashlet.datagrid.init(one.f.nodes.id.dashlet.datagrid, {
-                searchable: true,
-                filterable: false,
-                pagination: true,
-                flexibleRowsPerPage: true
-                }, "table-striped table-condensed");
-            $dashlet.append($gridHTML);
-            var dataSource = one.f.nodes.data.nodesDataGrid(data);
-            $("#" + one.f.nodes.id.dashlet.datagrid).datagrid({dataSource: dataSource});
-        });
-    },
-    ajax : {
-        dashlet : function(callback) {
-            $.getJSON(one.f.address.root+one.f.address.flows.flows, function(data) {
-                callback(data);
-            });
-        }
-    },
-    data : {
-        nodesDataGrid: function(data) {
-            var gridData = [];
-            $.each(data, function(nodeName, flow) {
-                var nodeFlowObject = {};
-                nodeFlowObject["nodeName"] = nodeName;
-                nodeFlowObject["flows"] = flow;
-                nodeFlowObject["rowData"] = nodeName + flow + "-foobar";
-                gridData.push(nodeFlowObject);
-            });
+  id : {
+    dashlet: {
+      datagrid: "one_f_nodes_id_dashlet_datagrid"
+    }
+  },
+  registry : {},
+  dashlet : function($dashlet) {
+    var $h4 = one.lib.dashlet.header("Nodes");
+    $dashlet.append($h4);
 
-            var source = new StaticDataSource({
-                    columns: [
-                        {
-                            property: 'nodeName',
-                            label: 'Node',
-                            sortable: true
-                        },
-                        {
-                            property: 'flows',
-                            label: 'Flows',
-                            sortable: true
-                        }
-                    ],
-                    data: gridData,
-                    delay: 0
-                });
-            return source;
-        }
-    },
-    body : {
-        dashlet : function(body, callback) {
-            var attributes = ['table-striped', 'table-bordered', 'table-hover', 'table-condensed'];
-            var $table = one.lib.dashlet.table.table(attributes);
+    one.f.nodes.ajax.dashlet(function(data) {
+      var $gridHTML = one.lib.dashlet.datagrid.init(one.f.nodes.id.dashlet.datagrid, {
+        searchable: true,
+          filterable: false,
+          pagination: true,
+          flexibleRowsPerPage: true
+      }, "table-striped table-condensed");
+      $dashlet.append($gridHTML);
+      var dataSource = one.f.nodes.data.nodesDataGrid(data);
+      $("#" + one.f.nodes.id.dashlet.datagrid).datagrid({dataSource: dataSource});
+    });
+  },
+  ajax : {
+    dashlet : function(callback) {
+      $.getJSON(one.f.address.root+one.f.address.flows.flows, function(data) {
+        callback(data);
+      });
+    }
+  },
+  data : {
+    nodesDataGrid: function(data) {
+      var gridData = [];
+      $.each(data, function(nodeName, flow) {
+        var nodeFlowObject = {};
+        nodeFlowObject["nodeName"] = nodeName;
+        nodeFlowObject["flows"] = flow;
+        nodeFlowObject["rowData"] = nodeName + flow + "-foobar";
+        gridData.push(nodeFlowObject);
+      });
+
+      var source = new StaticDataSource({
+        columns: [
+      {
+        property: 'nodeName',
+          label: 'Node',
+          sortable: true
+      },
+          {
+            property: 'flows',
+          label: 'Flows',
+          sortable: true
+          }
+      ],
+          data: gridData,
+          delay: 0
+      });
+      return source;
+    }
+  },
+  body : {
+    dashlet : function(body, callback) {
+      var attributes = ['table-striped', 'table-bordered', 'table-hover', 'table-condensed'];
+      var $table = one.lib.dashlet.table.table(attributes);
 
-            var headers = ['Node', 'Flows'];
-            var $thead = one.lib.dashlet.table.header(headers);
-            $table.append($thead);
+      var headers = ['Node', 'Flows'];
+      var $thead = one.lib.dashlet.table.header(headers);
+      $table.append($thead);
 
-            var $tbody = one.lib.dashlet.table.body(body);
-            $table.append($tbody);
+      var $tbody = one.lib.dashlet.table.body(body);
+      $table.append($tbody);
 
-            return $table;
-        }
+      return $table;
     }
+  }
 }
 
 /** FLOW DETAIL **/
 one.f.detail = {
-    id : {},
-    registry : {},
-    dashlet : function($dashlet, details) {
-        var $h4 = one.lib.dashlet.header("Flow Details");
-        $dashlet.append($h4);
-
-        // details
-        if (details == undefined) {
-            var $none = $(document.createElement('div'));
-            $none.addClass('none');
-            var $p = $(document.createElement('p'));
-            $p.text('Please select a flow');
-            $p.addClass('text-center').addClass('text-info');
+  id : {},
+  registry : {},
+  dashlet : function($dashlet, details) {
+    var $h4 = one.lib.dashlet.header("Flow Details");
+    $dashlet.append($h4);
 
-            $dashlet.append($none)
-                .append($p);
-        }
-    },
-    data : {
-        dashlet : function(data) {
-            var body = [];
-            var tr = {};
-            var entry = [];
-
-            entry.push(data['name']);
-            entry.push(data['node']);
-            entry.push(data['flow']['priority']);
-            entry.push(data['flow']['hardTimeout']);
-            entry.push(data['flow']['idleTimeout']);
-
-            tr.entry = entry;
-            body.push(tr);
-            return body;
-        },
-        description : function(data) {
-            var body = [];
-            var tr = {};
-            var entry = [];
-            entry.push(data['flow']['ingressPort']);
-            entry.push(data['flow']['etherType']);
-            entry.push(data['flow']['vlanId']);
-            entry.push(data['flow']['vlanPriority']);
-            entry.push(data['flow']['srcMac']);
-            entry.push(data['flow']['dstMac']);
-            entry.push(data['flow']['srcIp']);
-            entry.push(data['flow']['dstIp']);
-            entry.push(data['flow']['tosBits']);
-            entry.push(data['flow']['srcPort']);
-            entry.push(data['flow']['dstPort']);
-            entry.push(data['flow']['protocol']);
-            entry.push(data['flow']['cookie']);
-
-            tr.entry = entry;
-            body.push(tr);
-            return body;
-        },
-        actions : function(data) {
-            var body = [];
-            var tr = {};
-            var entry = [];
-            var actions = '';
-
-            $(data['flow']['actions']).each(function(index, value) {
-                var locEqualTo = value.indexOf("=");
-                if ( locEqualTo == -1 ) {
-                    actions += value + ', ';
-                } else {
-                    var action = value.substr(0,locEqualTo);
-                    if( action == "OUTPUT") {
-                        var portIds = value.substr(locEqualTo+1).split(",");
-                        actions += action + "=";
-                        var allPorts = one.f.flows.registry.nodeports[one.f.flows.registry.selectedNode]['ports'];
-                        for(var i =0; i < portIds.length ; i++) {
-                            var portName = allPorts[portIds[i]];
-                            actions += portName + ", ";
-                        }
-                    } else {
-                        actions += value + ', ';
-                    }
-                }
-            });
-            actions = actions.slice(0,-2);
-            entry.push(actions);
+    // details
+    if (details == undefined) {
+      var $none = $(document.createElement('div'));
+      $none.addClass('none');
+      var $p = $(document.createElement('p'));
+      $p.text('Please select a flow');
+      $p.addClass('text-center').addClass('text-info');
 
-            tr.entry = entry;
-            body.push(tr);
-            return body;
+      $dashlet.append($none)
+        .append($p);
+    }
+  },
+  data : {
+    dashlet : function(data) {
+      var body = [];
+      var tr = {};
+      var entry = [];
+
+      entry.push(data['name']);
+      entry.push(data['node']);
+      entry.push(data['flow']['priority']);
+      entry.push(data['flow']['hardTimeout']);
+      entry.push(data['flow']['idleTimeout']);
+
+      tr.entry = entry;
+      body.push(tr);
+      return body;
+    },
+    description : function(data) {
+      var body = [];
+      var tr = {};
+      var entry = [];
+      entry.push(data['flow']['ingressPort']);
+      entry.push(data['flow']['etherType']);
+      entry.push(data['flow']['vlanId']);
+      entry.push(data['flow']['vlanPriority']);
+      entry.push(data['flow']['srcMac']);
+      entry.push(data['flow']['dstMac']);
+      entry.push(data['flow']['srcIp']);
+      entry.push(data['flow']['dstIp']);
+      entry.push(data['flow']['tosBits']);
+      entry.push(data['flow']['srcPort']);
+      entry.push(data['flow']['dstPort']);
+      entry.push(data['flow']['protocol']);
+      entry.push(data['flow']['cookie']);
+
+      tr.entry = entry;
+      body.push(tr);
+      return body;
+    },
+    actions : function(data) {
+      var body = [];
+      var tr = {};
+      var entry = [];
+      var actions = '';
+
+      $(data['flow']['actions']).each(function(index, value) {
+        var locEqualTo = value.indexOf("=");
+        if ( locEqualTo == -1 ) {
+          actions += value + ', ';
+        } else {
+          var action = value.substr(0,locEqualTo);
+          if( action == "OUTPUT") {
+            var portIds = value.substr(locEqualTo+1).split(",");
+            actions += action + "=";
+            var allPorts = one.f.flows.registry.nodeports[one.f.flows.registry.selectedNode]['ports'];
+            for(var i =0; i < portIds.length ; i++) {
+              var portName = allPorts[portIds[i]];
+              actions += portName + ", ";
+            }
+          } else {
+            actions += value + ', ';
+          }
         }
+      });
+      actions = actions.slice(0,-2);
+      entry.push(actions);
+
+      tr.entry = entry;
+      body.push(tr);
+      return body;
+    }
+  },
+  body : {
+    dashlet : function(body) {
+      // create table
+      var header = ['Flow Name', 'Node', 'Priority', 'Hard Timeout', 'Idle Timeout'];
+      var $thead = one.lib.dashlet.table.header(header);
+      var attributes = ['table-striped', 'table-bordered', 'table-condensed'];
+      var $table = one.lib.dashlet.table.table(attributes);
+      $table.append($thead);
+
+      var $tbody = one.lib.dashlet.table.body(body);
+      $table.append($tbody);
+
+      return $table;
     },
-    body : {
-        dashlet : function(body) {
-            // create table
-            var header = ['Flow Name', 'Node', 'Priority', 'Hard Timeout', 'Idle Timeout'];
-            var $thead = one.lib.dashlet.table.header(header);
-            var attributes = ['table-striped', 'table-bordered', 'table-condensed'];
-            var $table = one.lib.dashlet.table.table(attributes);
-            $table.append($thead);
-
-            var $tbody = one.lib.dashlet.table.body(body);
-            $table.append($tbody);
-
-            return $table;
-        },
-        description : function(body) {
-            var header = ['Input Port', 'Ethernet Type', 'VLAN ID', 'VLAN Priority', 'Source MAC', 'Dest MAC', 'Source IP', 'Dest IP', 'ToS', 'Source Port', 'Dest Port', 'Protocol', 'Cookie'];
-            var $thead = one.lib.dashlet.table.header(header);
-            var attributes = ['table-striped', 'table-bordered', 'table-condensed'];
-            var $table = one.lib.dashlet.table.table(attributes);
-            $table.append($thead);
+    description : function(body) {
+      var header = ['Input Port', 'Ethernet Type', 'VLAN ID', 'VLAN Priority', 'Source MAC', 'Dest MAC', 'Source IP', 'Dest IP', 'ToS', 'Source Port', 'Dest Port', 'Protocol', 'Cookie'];
+      var $thead = one.lib.dashlet.table.header(header);
+      var attributes = ['table-striped', 'table-bordered', 'table-condensed'];
+      var $table = one.lib.dashlet.table.table(attributes);
+      $table.append($thead);
 
-            var $tbody = one.lib.dashlet.table.body(body);
-            $table.append($tbody);
+      var $tbody = one.lib.dashlet.table.body(body);
+      $table.append($tbody);
 
-            return $table;
-        },
-        actions : function(body) {
-            var header = ['Actions'];
-            var $thead = one.lib.dashlet.table.header(header);
-            var attributes = ['table-striped', 'table-bordered', 'table-condensed'];
-            var $table = one.lib.dashlet.table.table(attributes);
-            $table.append($thead);
+      return $table;
+    },
+    actions : function(body) {
+      var header = ['Actions'];
+      var $thead = one.lib.dashlet.table.header(header);
+      var attributes = ['table-striped', 'table-bordered', 'table-condensed'];
+      var $table = one.lib.dashlet.table.table(attributes);
+      $table.append($thead);
 
-            var $tbody = one.lib.dashlet.table.body(body);
-            $table.append($tbody);
+      var $tbody = one.lib.dashlet.table.body(body);
+      $table.append($tbody);
 
-            return $table;
-        }
+      return $table;
     }
+  }
 }
 
 /** FLOW ENTRIES **/
 one.f.flows = {
-    id : {
-        dashlet : {
-            add : "one_f_flows_id_dashlet_add",
-            removeMultiple : "one_f_flows_id_dashlet_removeMultiple",
-            remove : "one_f_flows_id_dashlet_remove",
-            toggle : "one_f_flows_id_dashlet_toggle",
-            edit : "one_f_flows_id_dashlet_edit",
-            datagrid : "one_f_flows_id_dashlet_datagrid",
-            selectAllFlows : "one_f_flows_id_dashlet_selectAllFlows"
-        },
+  id : {
+    dashlet : {
+      add : "one_f_flows_id_dashlet_add",
+      removeMultiple : "one_f_flows_id_dashlet_removeMultiple",
+      remove : "one_f_flows_id_dashlet_remove",
+      toggle : "one_f_flows_id_dashlet_toggle",
+      edit : "one_f_flows_id_dashlet_edit",
+      datagrid : "one_f_flows_id_dashlet_datagrid",
+      selectAllFlows : "one_f_flows_id_dashlet_selectAllFlows"
+    },
+    modal : {
+      install : "one_f_flows_id_modal_install",
+      edit : "one_f_flows_id_modal_edit",
+      add : "one_f_flows_id_modal_add",
+      close : "one_f_flows_id_modal_close",
+      modal : "one_f_flows_id_modal_modal",
+      dialog : {
+        modal : "one_f_flows_id_modal_dialog_modal",
+        remove : "one_f_flows_id_modal_dialog_remove",
+        close : "one_f_flows_id_modal_dialog_close"
+      },
+      action : {
+        button : "one_f_flows_id_modal_action_button",
+        modal : "one_f_flows_id_modal_action_modal",
+        add : "one_f_flows_id_modal_action_add",
+        close : "one_f_flows_id_modal_action_close",
+        table : "one_f_flows_id_modal_action_table",
+        addOutputPorts : "one_f_flows_id_modal_action_addOutputPorts",
+        setVlanId : "one_f_flows_id_modal_action_setVlanId",
+        setVlanPriority : "one_f_flows_id_modal_action_setVlanPriority",
+        modifyDatalayerSourceAddress : "one_f_flows_id_modal_action_modifyDatalayerSourceAddress",
+        modifyDatalayerDestinationAddress : "one_f_flows_id_modal_action_modifyDatalayerDestinationAddress",
+        modifyNetworkSourceAddress : "one_f_flows_modal_action_modifyNetworkSourceAddress",
+        modifyNetworkDestinationAddress : "one_f_flows_modal_action_modifyNetworkDestinationAddress",
+        modifyTosBits : "one_f_flows_modal_action_modifyTosBits",
+        modifyTransportSourcePort : "one_f_flows_modal_action_modifyTransportSourcePort",
+        modifyTransportDestinationPort : "one_f_flows_modal_action_modifyTransportDestinationPort",
+        enqueue : 'one-f-flows-modal-action-enqueue',
+        queue : 'one-f-flows-modal-action-queue',
+        setEthertype : 'one-f-flows-modal-action-setEthertype',
+        pushVlan : 'one-f-flows-modal-action-pushVlan',
+        setVlanCfi : 'one-f-flows-modal-action-setVlanCfi',
         modal : {
-            install : "one_f_flows_id_modal_install",
-            edit : "one_f_flows_id_modal_edit",
-            add : "one_f_flows_id_modal_add",
-            close : "one_f_flows_id_modal_close",
-            modal : "one_f_flows_id_modal_modal",
-            dialog : {
-                modal : "one_f_flows_id_modal_dialog_modal",
-                remove : "one_f_flows_id_modal_dialog_remove",
-                close : "one_f_flows_id_modal_dialog_close"
-            },
-            action : {
-                button : "one_f_flows_id_modal_action_button",
-                modal : "one_f_flows_id_modal_action_modal",
-                add : "one_f_flows_id_modal_action_add",
-                close : "one_f_flows_id_modal_action_close",
-                table : "one_f_flows_id_modal_action_table",
-                addOutputPorts : "one_f_flows_id_modal_action_addOutputPorts",
-                setVlanId : "one_f_flows_id_modal_action_setVlanId",
-                setVlanPriority : "one_f_flows_id_modal_action_setVlanPriority",
-                modifyDatalayerSourceAddress : "one_f_flows_id_modal_action_modifyDatalayerSourceAddress",
-                modifyDatalayerDestinationAddress : "one_f_flows_id_modal_action_modifyDatalayerDestinationAddress",
-                modifyNetworkSourceAddress : "one_f_flows_modal_action_modifyNetworkSourceAddress",
-                modifyNetworkDestinationAddress : "one_f_flows_modal_action_modifyNetworkDestinationAddress",
-                modifyTosBits : "one_f_flows_modal_action_modifyTosBits",
-                modifyTransportSourcePort : "one_f_flows_modal_action_modifyTransportSourcePort",
-                modifyTransportDestinationPort : "one_f_flows_modal_action_modifyTransportDestinationPort",
-                modal : {
-                    modal : "one_f_flows_modal_action_modal_modal",
-                    remove : "one_f_flows_modal_action_modal_remove",
-                    cancel : "one_f_flows_modal_action_modal_cancel"
-                }
-            },
-            form : {
-                name : "one_f_flows_id_modal_form_name",
-                nodes : "one_f_flows_id_modal_form_nodes",
-                port : "one_f_flows_id_modal_form_port",
-                priority : "one_f_flows_id_modal_form_priority",
-                hardTimeout : "one_f_flows_id_modal_form_hardTimeout",
-                idleTimeout : "one_f_flows_id_modal_form_idleTimeout",
-                cookie : "one_f_flows_id_modal_form_cookie",
-                etherType : "one_f_flows_id_modal_form_etherType",
-                vlanId : "one_f_flows_id_modal_form_vlanId",
-                vlanPriority : "one_f_flows_id_modal_form_vlanPriority",
-                srcMac : "one_f_flows_id_modal_form_srcMac",
-                dstMac : "one_f_flows_id_modal_form_dstMac",
-                srcIp : "one_f_flows_id_modal_form_srcIp",
-                dstIp : "one_f_flows_id_modal_form_dstIp",
-                tosBits : "one_f_flows_id_modal_form_tosBits",
-                srcPort : "one_f_flows_id_modal_form_srcPort",
-                dstPort : "one_f_flows_id_modal_form_dstPort",
-                protocol : "one_f_flows_id_modal_form_protocol"
-            }
+          modal : "one_f_flows_modal_action_modal_modal",
+          remove : "one_f_flows_modal_action_modal_remove",
+          cancel : "one_f_flows_modal_action_modal_cancel"
         }
-    },
-    registry : {},
-    dashlet : function($dashlet, callback) {
-
-        // load body
-        one.f.flows.ajax.dashlet(function(data) {
-
-            var $h4 = one.lib.dashlet.header("Flow Entries");
-
-            $dashlet.append($h4);
-            if (one.f.flows.registry.privilege === 'WRITE') {
-                var button = one.lib.dashlet.button.single("Add Flow Entry", one.f.flows.id.dashlet.add, "btn-primary", "btn-mini");
-                var $button = one.lib.dashlet.button.button(button);
-
-                $button.click(function() {
-                    var $modal = one.f.flows.modal.initialize();
-                    $modal.modal();
-                });
-                $dashlet.append($button);
-                var button = one.lib.dashlet.button.single("Remove Flow Entry", one.f.flows.id.dashlet.removeMultiple, "btn-danger", "btn-mini");
-                var $button = one.lib.dashlet.button.button(button);
-
-                $button.click(function() {
-                    var checkedCheckBoxes = $('.flowEntry[type=checkbox]:checked');
-                    if (checkedCheckBoxes.size() === 0) {
-                        return false;
-                    }
-                    
-                    var requestData = [];
-                    
-                    checkedCheckBoxes.each(function(index, value) {
-                        var flowEntry = {};
-                        flowEntry['name'] = checkedCheckBoxes[index].name;
-                        flowEntry['node'] = checkedCheckBoxes[index].getAttribute("node");
-                        requestData.push(flowEntry);  
-                    });
-                    one.f.flows.modal.removeMultiple.dialog(requestData);
-                });
-                $dashlet.append($button);
+      },
+      form : {
+        name : "one_f_flows_id_modal_form_name",
+        nodes : "one_f_flows_id_modal_form_nodes",
+        port : "one_f_flows_id_modal_form_port",
+        priority : "one_f_flows_id_modal_form_priority",
+        hardTimeout : "one_f_flows_id_modal_form_hardTimeout",
+        idleTimeout : "one_f_flows_id_modal_form_idleTimeout",
+        cookie : "one_f_flows_id_modal_form_cookie",
+        etherType : "one_f_flows_id_modal_form_etherType",
+        vlanId : "one_f_flows_id_modal_form_vlanId",
+        vlanPriority : "one_f_flows_id_modal_form_vlanPriority",
+        srcMac : "one_f_flows_id_modal_form_srcMac",
+        dstMac : "one_f_flows_id_modal_form_dstMac",
+        srcIp : "one_f_flows_id_modal_form_srcIp",
+        dstIp : "one_f_flows_id_modal_form_dstIp",
+        tosBits : "one_f_flows_id_modal_form_tosBits",
+        srcPort : "one_f_flows_id_modal_form_srcPort",
+        dstPort : "one_f_flows_id_modal_form_dstPort",
+        protocol : "one_f_flows_id_modal_form_protocol",
+        action : 'one-f-flows-id-modal-form-action'
+      }
+    }
+  },
+  registry : {},
+  dashlet : function($dashlet, callback) {
+    // load body
+    one.f.flows.ajax.dashlet(function(data) {
+      var $h4 = one.lib.dashlet.header("Flow Entries");
+      $dashlet.append($h4);
+      if (one.f.flows.registry.privilege === 'WRITE') {
+        var button = one.lib.dashlet.button.single("Add Flow Entry", one.f.flows.id.dashlet.add, "btn-primary", "btn-mini");
+        var $button = one.lib.dashlet.button.button(button);
+
+        $button.click(function() {
+          var $modal = one.f.flows.modal.initialize();
+          $modal.modal();
+        });
+        $dashlet.append($button);
+        var button = one.lib.dashlet.button.single("Remove Flow Entry", one.f.flows.id.dashlet.removeMultiple, "btn-danger", "btn-mini");
+        var $button = one.lib.dashlet.button.button(button);
+
+        $button.click(function() {
+          var checkedCheckBoxes = $('.flowEntry[type=checkbox]:checked');
+          if (checkedCheckBoxes.size() === 0) {
+            return false;
+          }
 
-            }
+          var requestData = [];
 
-            var $gridHTML = one.lib.dashlet.datagrid.init(one.f.flows.id.dashlet.datagrid, {
-                searchable: true,
-                filterable: false,
-                pagination: true,
-                flexibleRowsPerPage: true
-                }, "table-striped table-condensed");
-            $dashlet.append($gridHTML);
-            var dataSource = one.f.flows.data.flowsDataGrid(data);
-            $("#" + one.f.flows.id.dashlet.datagrid).datagrid({dataSource: dataSource}).on("loaded", function() {
-                    $("#"+one.f.flows.id.dashlet.datagrid.selectAllFlows).click(function() {
-                                $("#" + one.f.flows.id.dashlet.datagrid).find(':checkbox').prop('checked',
-                                        $("#"+one.f.flows.id.dashlet.datagrid.selectAllFlows).is(':checked'));
-                    });
-                    
-                    $("#" + one.f.flows.id.dashlet.datagrid).find("tbody tr").each(function(index, tr) {
-                    $tr = $(tr);
-                    $span = $("td span", $tr);
-                    var flowstatus = $span.data("flowstatus");
-                    if($span.data("installinhw") != null) {
-                        var installInHw = $span.data("installinhw").toString();
-                        if(installInHw == "true" && flowstatus == "Success") {
-                            $tr.addClass("success");
-                        } else {
-                            $tr.addClass("warning");
-                        }
-                    }
-                    // attach mouseover to show pointer cursor
-                    $tr.mouseover(function() {
-                        $(this).css("cursor", "pointer");
-                    });
-                    // attach click event
-                    $tr.click(function() {
-                        var $td = $($(this).find("td")[1]);
-                        var id = $td.text();
-                        var node = $td.find("span").data("nodeid");
-                        one.f.flows.detail(id, node);
-                    });
-                    $(".flowEntry").click(function(e){
-                                if (!$('.flowEntry[type=checkbox]:not(:checked)').length) {
-                            $("#"+one.f.flows.id.dashlet.datagrid.selectAllFlows)
-                                .prop("checked",
-                              true);
-                        } else {
-                            $("#"+one.f.flows.id.dashlet.datagrid.selectAllFlows)
-                                .prop("checked",
-                             false);
-                        }
-                        e.stopPropagation();
-                    });
-                });
-            });
-            
-            // details callback
-            if(callback != undefined) callback();
+          checkedCheckBoxes.each(function(index, value) {
+            var flowEntry = {};
+            flowEntry['name'] = checkedCheckBoxes[index].name;
+            flowEntry['node'] = checkedCheckBoxes[index].getAttribute("node");
+            requestData.push(flowEntry);  
+          });
+          one.f.flows.modal.removeMultiple.dialog(requestData);
         });
-    },
-    detail : function(id, node) {
-        // clear flow details
-        var $detailDashlet = one.main.dashlet.right.bottom;
-        $detailDashlet.empty();
-        var $h4 = one.lib.dashlet.header("Flow Overview");
-        $detailDashlet.append($h4);
-
-        // details
-        var flows = one.f.flows.registry.flows;
-        one.f.flows.registry['selectedId'] = id;
-        one.f.flows.registry['selectedNode'] = node;
-        var flow;
-        $(flows).each(function(index, value) {
-          if (value.name == id && value.nodeId == node) {
-            flow = value;
-          }
+        $dashlet.append($button);
+
+      }
+      var $gridHTML = one.lib.dashlet.datagrid.init(one.f.flows.id.dashlet.datagrid, {
+        searchable: true,
+          filterable: false,
+          pagination: true,
+          flexibleRowsPerPage: true
+      }, "table-striped table-condensed");
+      $dashlet.append($gridHTML);
+      var dataSource = one.f.flows.data.flowsDataGrid(data);
+      $("#" + one.f.flows.id.dashlet.datagrid).datagrid({dataSource: dataSource}).on("loaded", function() {
+        $("#"+one.f.flows.id.dashlet.datagrid.selectAllFlows).click(function() {
+          $("#" + one.f.flows.id.dashlet.datagrid).find(':checkbox').prop('checked',
+            $("#"+one.f.flows.id.dashlet.datagrid.selectAllFlows).is(':checked'));
         });
-        if (one.f.flows.registry.privilege === 'WRITE') {
-            // remove button
-            var button = one.lib.dashlet.button.single("Remove Flow", one.f.flows.id.dashlet.remove, "btn-danger", "btn-mini");
-            var $button = one.lib.dashlet.button.button(button);
-            $button.click(function() {
-                var $modal = one.f.flows.modal.dialog.initialize(id, node);
-                $modal.modal();
-            });
-            // edit button
-            var editButton = one.lib.dashlet.button.single("Edit Flow", one.f.flows.id.dashlet.edit, "btn-primary", "btn-mini");
-            var $editButton = one.lib.dashlet.button.button(editButton);
-            $editButton.click(function() {
-               var install = flow['flow']['installInHw'];
-                var $modal = one.f.flows.modal.initialize(true,install);
-                $modal.modal().on('shown',function(){
-                    var $port = $('#'+one.f.flows.id.modal.form.port);
-                    $('#'+one.f.flows.id.modal.form.nodes).trigger("change");
-                });
-            });
-            // toggle button
-            var toggle;
-            if (flow['flow']['installInHw'] == 'true' && flow['flow']['status'] == 'Success') {
-                toggle = one.lib.dashlet.button.single("Uninstall Flow", one.f.flows.id.dashlet.toggle, "btn-warning", "btn-mini");
-            } else {
-                toggle = one.lib.dashlet.button.single("Install Flow", one.f.flows.id.dashlet.toggle, "btn-success", "btn-mini");
-            }
-            var $toggle = one.lib.dashlet.button.button(toggle);
-            $toggle.click(function() {
-                one.f.flows.modal.ajax.toggleflow(id, node, function(data) {
-                    if(data == "Success") {
-                        one.main.dashlet.right.bottom.empty();
-                        one.f.detail.dashlet(one.main.dashlet.right.bottom);
-                        one.main.dashlet.left.top.empty();
-                        one.f.flows.dashlet(one.main.dashlet.left.top, function() {
-                           // checks are backwards due to stale registry
-                           if(flow['flow']['installInHw'] == 'true') {
-                               one.lib.alert('Uninstalled Flow');
-                           } else {
-                               one.lib.alert('Installed Flow');
-                           }
-                           one.f.flows.detail(id, node)
-                        });
-                    } else {
-                        one.lib.alert('Cannot toggle flow: '+data);
-                    }
-                });
-            });
 
-            $detailDashlet.append($button).append($editButton).append($toggle);
-        }
-        // append details
-        var body = one.f.detail.data.dashlet(flow);
-        var $body = one.f.detail.body.dashlet(body);
-        $detailDashlet.append($body);
-        var body = one.f.detail.data.description(flow);
-        var $body = one.f.detail.body.description(body);
-        $detailDashlet.append($body);
-        var body = one.f.detail.data.actions(flow);
-        var $body = one.f.detail.body.actions(body);
-        $detailDashlet.append($body);
-    },
-    modal : {
-        dialog : {
-            initialize : function(id, node) {
-                var h3 = "Remove Flow";
-                var $p = one.f.flows.modal.dialog.body(id);
-                var footer = one.f.flows.modal.dialog.footer();
-                var $modal = one.lib.modal.spawn(one.f.flows.id.modal.dialog.modal, h3, $p, footer);
-                $('#'+one.f.flows.id.modal.dialog.close, $modal).click(function() {
-                    $modal.modal('hide');
-                });
-                $('#'+one.f.flows.id.modal.dialog.remove, $modal).click(function() {
-                    one.f.flows.modal.ajax.removeflow(id, node, function(data) {
-                        if (data == "Success") {
-                            $modal.modal('hide');
-                            one.main.dashlet.right.bottom.empty();
-                            one.f.detail.dashlet(one.main.dashlet.right.bottom);
-                            one.main.dashlet.left.top.empty();
-                            one.f.flows.dashlet(one.main.dashlet.left.top);
-                            one.lib.alert('Flow removed');
-                        } else {
-                            one.lib.alert('Cannot remove flow: '+data);
-                        }
-                    });
-                });
-                return $modal;
-            },
-            footer : function() {
-                var footer = [];
-
-                var removeButton = one.lib.dashlet.button.single("Remove Flow", one.f.flows.id.modal.dialog.remove, "btn-danger", "");
-                var $removeButton = one.lib.dashlet.button.button(removeButton);
-                footer.push($removeButton);
-
-                var closeButton = one.lib.dashlet.button.single("Cancel", one.f.flows.id.modal.dialog.close, "", "");
-                var $closeButton = one.lib.dashlet.button.button(closeButton);
-                footer.push($closeButton);
-
-                return footer;
-            },
-            body : function(id) {
-                var $p = $(document.createElement('p'));
-                $p.append('Remove flow '+id+'?');
-                return $p;
+        $("#" + one.f.flows.id.dashlet.datagrid).find("tbody tr").each(function(index, tr) {
+          $tr = $(tr);
+          $span = $("td span", $tr);
+          var flowstatus = $span.data("flowstatus");
+          if($span.data("installinhw") != null) {
+            var installInHw = $span.data("installinhw").toString();
+            if(installInHw == "true" && flowstatus == "Success") {
+              $tr.addClass("success");
+            } else {
+              $tr.addClass("warning");
             }
-        },
-        initialize : function(edit,install) {
-            var h3;
-            if(edit) {
-                h3 = "Edit Flow Entry";
-                var footer = one.f.flows.modal.footerEdit();
-
+          }
+          // attach mouseover to show pointer cursor
+          $tr.mouseover(function() {
+            $(this).css("cursor", "pointer");
+          });
+          // attach click event
+          $tr.click(function() {
+            var $td = $($(this).find("td")[1]);
+            var id = $td.text();
+            var node = $td.find("span").data("nodeid");
+            one.f.flows.detail(id, node);
+          });
+          $(".flowEntry").click(function(e){
+            if (!$('.flowEntry[type=checkbox]:not(:checked)').length) {
+              $("#"+one.f.flows.id.dashlet.datagrid.selectAllFlows)
+            .prop("checked",
+              true);
             } else {
-                h3 = "Add Flow Entry";
-                var footer = one.f.flows.modal.footer();
+              $("#"+one.f.flows.id.dashlet.datagrid.selectAllFlows)
+            .prop("checked",
+              false);
             }
-
-            var $modal = one.lib.modal.spawn(one.f.flows.id.modal.modal, h3, "", footer);
-
-            // bind close button
-            $('#'+one.f.flows.id.modal.close, $modal).click(function() {
-                $modal.modal('hide');
+            e.stopPropagation();
+          });
+        });
+      });
+
+      // details callback
+      if(callback != undefined) callback();
+    });
+  },
+  detail : function(id, node) {
+    // clear flow details
+    var $detailDashlet = one.main.dashlet.right.bottom;
+    $detailDashlet.empty();
+    var $h4 = one.lib.dashlet.header("Flow Overview");
+    $detailDashlet.append($h4);
+
+    // details
+    var flows = one.f.flows.registry.flows;
+    one.f.flows.registry['selectedId'] = id;
+    one.f.flows.registry['selectedNode'] = node;
+    var flow;
+    $(flows).each(function(index, value) {
+      if (value.name == id && value.nodeId == node) {
+        flow = value;
+      }
+    });
+    if (one.f.flows.registry.privilege === 'WRITE') {
+      // remove button
+      var button = one.lib.dashlet.button.single("Remove Flow", one.f.flows.id.dashlet.remove, "btn-danger", "btn-mini");
+      var $button = one.lib.dashlet.button.button(button);
+      $button.click(function() {
+        var $modal = one.f.flows.modal.dialog.initialize(id, node);
+        $modal.modal();
+      });
+      // edit button
+      var editButton = one.lib.dashlet.button.single("Edit Flow", one.f.flows.id.dashlet.edit, "btn-primary", "btn-mini");
+      var $editButton = one.lib.dashlet.button.button(editButton);
+      $editButton.click(function() {
+        var install = flow['flow']['installInHw'];
+        var $modal = one.f.flows.modal.initialize(true,install);
+        $modal.modal().on('shown',function(){
+          var $port = $('#'+one.f.flows.id.modal.form.port);
+          $('#'+one.f.flows.id.modal.form.nodes).trigger("change");
+        });
+      });
+      // toggle button
+      var toggle;
+      if (flow['flow']['installInHw'] == 'true' && flow['flow']['status'] == 'Success') {
+        toggle = one.lib.dashlet.button.single("Uninstall Flow", one.f.flows.id.dashlet.toggle, "btn-warning", "btn-mini");
+      } else {
+        toggle = one.lib.dashlet.button.single("Install Flow", one.f.flows.id.dashlet.toggle, "btn-success", "btn-mini");
+      }
+      var $toggle = one.lib.dashlet.button.button(toggle);
+      $toggle.click(function() {
+        one.f.flows.modal.ajax.toggleflow(id, node, function(data) {
+          if(data == "Success") {
+            one.main.dashlet.right.bottom.empty();
+            one.f.detail.dashlet(one.main.dashlet.right.bottom);
+            one.main.dashlet.left.top.empty();
+            one.f.flows.dashlet(one.main.dashlet.left.top, function() {
+              // checks are backwards due to stale registry
+              if(flow['flow']['installInHw'] == 'true') {
+                one.lib.alert('Uninstalled Flow');
+              } else {
+                one.lib.alert('Installed Flow');
+              }
+              one.f.flows.detail(id, node)
             });
+          } else {
+            one.lib.alert('Cannot toggle flow: '+data);
+          }
+        });
+      });
 
-            if (edit) {
-                // bind edit flow button
-                $('#'+one.f.flows.id.modal.edit, $modal).click(function() {
-                    one.f.flows.modal.save($modal, install, true);
-                });
+      $detailDashlet.append($button).append($editButton).append($toggle);
+    }
+    // append details
+    var body = one.f.detail.data.dashlet(flow);
+    var $body = one.f.detail.body.dashlet(body);
+    $detailDashlet.append($body);
+    var body = one.f.detail.data.description(flow);
+    var $body = one.f.detail.body.description(body);
+    $detailDashlet.append($body);
+    var body = one.f.detail.data.actions(flow);
+    var $body = one.f.detail.body.actions(body);
+    $detailDashlet.append($body);
+  },
+  modal : {
+    dialog : {
+      initialize : function(id, node) {
+        var h3 = "Remove Flow";
+        var $p = one.f.flows.modal.dialog.body(id);
+        var footer = one.f.flows.modal.dialog.footer();
+        var $modal = one.lib.modal.spawn(one.f.flows.id.modal.dialog.modal, h3, $p, footer);
+        $('#'+one.f.flows.id.modal.dialog.close, $modal).click(function() {
+          $modal.modal('hide');
+        });
+        $('#'+one.f.flows.id.modal.dialog.remove, $modal).click(function() {
+          one.f.flows.modal.ajax.removeflow(id, node, function(data) {
+            if (data == "Success") {
+              $modal.modal('hide');
+              one.main.dashlet.right.bottom.empty();
+              one.f.detail.dashlet(one.main.dashlet.right.bottom);
+              one.main.dashlet.left.top.empty();
+              one.f.flows.dashlet(one.main.dashlet.left.top);
+              one.lib.alert('Flow removed');
             } else {
-                // bind add flow button
-                $('#'+one.f.flows.id.modal.add, $modal).click(function() {
-                    one.f.flows.modal.save($modal, 'false');
-                });
-
-                // bind install flow button
-                $('#'+one.f.flows.id.modal.install, $modal).click(function() {
-                    one.f.flows.modal.save($modal, 'true');
-                });
+              one.lib.alert('Cannot remove flow: '+data);
             }
+          });
+        });
+        return $modal;
+      },
+      footer : function() {
+        var footer = [];
+
+        var removeButton = one.lib.dashlet.button.single("Remove Flow", one.f.flows.id.modal.dialog.remove, "btn-danger", "");
+        var $removeButton = one.lib.dashlet.button.button(removeButton);
+        footer.push($removeButton);
+
+        var closeButton = one.lib.dashlet.button.single("Cancel", one.f.flows.id.modal.dialog.close, "", "");
+        var $closeButton = one.lib.dashlet.button.button(closeButton);
+        footer.push($closeButton);
+
+        return footer;
+      },
+      body : function(id) {
+        var $p = $(document.createElement('p'));
+        $p.append('Remove flow '+id+'?');
+        return $p;
+      }
+    },
+    initialize : function(edit,install) {
+      var h3;
+      if(edit) {
+        h3 = "Edit Flow Entry";
+        var footer = one.f.flows.modal.footerEdit();
+
+      } else {
+        h3 = "Add Flow Entry";
+        var footer = one.f.flows.modal.footer();
+      }
+
+      var $modal = one.lib.modal.spawn(one.f.flows.id.modal.modal, h3, "", footer);
+
+      // bind close button
+      $('#'+one.f.flows.id.modal.close, $modal).click(function() {
+        $modal.modal('hide');
+      });
+
+      if (edit) {
+        // bind edit flow button
+        $('#'+one.f.flows.id.modal.edit, $modal).click(function() {
+          one.f.flows.modal.save($modal, install, true);
+        });
+      } else {
+        // bind add flow button
+        $('#'+one.f.flows.id.modal.add, $modal).click(function() {
+          one.f.flows.modal.save($modal, 'false');
+        });
 
+        // bind install flow button
+        $('#'+one.f.flows.id.modal.install, $modal).click(function() {
+          one.f.flows.modal.save($modal, 'true');
+        });
+      }
 
-            var nodes = one.f.flows.registry.nodes;
-            var nodeports = one.f.flows.registry.nodeports;
-            var $body = one.f.flows.modal.body(nodes, nodeports, edit);
-            one.lib.modal.inject.body($modal, $body,edit);
-
-            return $modal;
-        },
-        save : function($modal, install, edit) {
-            var result = {};
-
-            result['name'] = $('#'+one.f.flows.id.modal.form.name, $modal).val();
-            result['ingressPort'] = $('#'+one.f.flows.id.modal.form.port, $modal).val();
-            result['priority'] = $('#'+one.f.flows.id.modal.form.priority, $modal).val();
-            result['hardTimeout'] = $('#'+one.f.flows.id.modal.form.hardTimeout, $modal).val();
-            result['idleTimeout'] = $('#'+one.f.flows.id.modal.form.idleTimeout, $modal).val();
-            result['cookie'] = $('#'+one.f.flows.id.modal.form.cookie, $modal).val();
-            result['etherType'] = $('#'+one.f.flows.id.modal.form.etherType, $modal).val();
-            result['vlanId'] = $('#'+one.f.flows.id.modal.form.vlanId, $modal).val();
-            result['vlanPriority'] = $('#'+one.f.flows.id.modal.form.vlanPriority, $modal).val();
-            result['dlSrc'] = $('#'+one.f.flows.id.modal.form.srcMac, $modal).val();
-            result['dlDst'] = $('#'+one.f.flows.id.modal.form.dstMac, $modal).val();
-            result['nwSrc'] = $('#'+one.f.flows.id.modal.form.srcIp, $modal).val();
-            result['nwDst'] = $('#'+one.f.flows.id.modal.form.dstIp, $modal).val();
-            result['tosBits'] = $('#'+one.f.flows.id.modal.form.tosBits, $modal).val();
-            result['tpSrc'] = $('#'+one.f.flows.id.modal.form.srcPort, $modal).val();
-            result['tpDst'] = $('#'+one.f.flows.id.modal.form.dstPort, $modal).val();
-            result['protocol'] = $('#'+one.f.flows.id.modal.form.protocol, $modal).val();
-            result['installInHw'] = install;
-
-            var nodeId = $('#'+one.f.flows.id.modal.form.nodes, $modal).val();
-
-            $.each(result, function(key, value) {
-                if (value == "") delete result[key];
-            });
+      var nodes = one.f.flows.registry.nodes;
+      var nodeports = one.f.flows.registry.nodeports;
+      var $body = one.f.flows.modal.body(nodes, nodeports, edit);
+      one.lib.modal.inject.body($modal, $body,edit);
 
-            var action = [];
-            var $table = $('#'+one.f.flows.id.modal.action.table, $modal);
-            $($table.find('tbody').find('tr')).each(function(index, value) {
-                if (!$(this).find('td').hasClass('empty')) {
-                    action.push($(value).data('action'));
-                }
+      return $modal;
+    },
+    save : function($modal, install, edit) {
+      var result = {};
+
+      result['name'] = $('#'+one.f.flows.id.modal.form.name, $modal).val();
+      result['ingressPort'] = $('#'+one.f.flows.id.modal.form.port, $modal).val();
+      result['priority'] = $('#'+one.f.flows.id.modal.form.priority, $modal).val();
+      result['hardTimeout'] = $('#'+one.f.flows.id.modal.form.hardTimeout, $modal).val();
+      result['idleTimeout'] = $('#'+one.f.flows.id.modal.form.idleTimeout, $modal).val();
+      result['cookie'] = $('#'+one.f.flows.id.modal.form.cookie, $modal).val();
+      result['etherType'] = $('#'+one.f.flows.id.modal.form.etherType, $modal).val();
+      result['vlanId'] = $('#'+one.f.flows.id.modal.form.vlanId, $modal).val();
+      result['vlanPriority'] = $('#'+one.f.flows.id.modal.form.vlanPriority, $modal).val();
+      result['dlSrc'] = $('#'+one.f.flows.id.modal.form.srcMac, $modal).val();
+      result['dlDst'] = $('#'+one.f.flows.id.modal.form.dstMac, $modal).val();
+      result['nwSrc'] = $('#'+one.f.flows.id.modal.form.srcIp, $modal).val();
+      result['nwDst'] = $('#'+one.f.flows.id.modal.form.dstIp, $modal).val();
+      result['tosBits'] = $('#'+one.f.flows.id.modal.form.tosBits, $modal).val();
+      result['tpSrc'] = $('#'+one.f.flows.id.modal.form.srcPort, $modal).val();
+      result['tpDst'] = $('#'+one.f.flows.id.modal.form.dstPort, $modal).val();
+      result['protocol'] = $('#'+one.f.flows.id.modal.form.protocol, $modal).val();
+      result['installInHw'] = install;
+
+      var nodeId = $('#'+one.f.flows.id.modal.form.nodes, $modal).val();
+
+      $.each(result, function(key, value) {
+        if (value == "") delete result[key];
+      });
+
+      var action = [];
+      var $table = $('#'+one.f.flows.id.modal.action.table, $modal);
+      $($table.find('tbody').find('tr')).each(function(index, value) {
+        if (!$(this).find('td').hasClass('empty')) {
+          action.push($(value).data('action'));
+        }
+      });
+      result['actions'] = action;
+
+      // frontend validation
+      if (result['name'] == undefined) {
+        alert('Need flow name');
+        return;
+      }
+      if (nodeId == '') {
+        alert('Select node');
+        return;
+      }
+      if (action.length == 0) {
+        alert('Please specify an action');
+        return;
+      }
+
+      // package for ajax call
+      var resource = {};
+      resource['body'] = JSON.stringify(result);
+      if(edit){
+        resource['action'] = 'edit';
+      } else {
+        resource['action'] = 'add';
+      }
+
+      resource['nodeId'] = nodeId;
+
+      if (edit) {
+        one.f.flows.modal.ajax.saveflow(resource, function(data) {
+          if (data == "Success") {
+            $modal.modal('hide').on('hidden', function () {
+              one.f.flows.detail(result['name'], nodeId);
             });
-            result['actions'] = action;
-
-            // frontend validation
-            if (result['name'] == undefined) {
-                alert('Need flow name');
-                return;
-            }
-            if (nodeId == '') {
-                alert('Select node');
-                return;
-            }
-            if (action.length == 0) {
-                alert('Please specify an action');
-                return;
-            }
-
-            // package for ajax call
-            var resource = {};
-            resource['body'] = JSON.stringify(result);
-            if(edit){
-                resource['action'] = 'edit';
+            one.lib.alert('Flow Entry edited');
+            one.main.dashlet.left.top.empty();
+            one.f.flows.dashlet(one.main.dashlet.left.top);
+          } else {
+            alert('Could not edit flow: '+data);
+          }
+        });
+      } else {
+        one.f.flows.modal.ajax.saveflow(resource, function(data) {
+          if (data == "Success") {
+            $modal.modal('hide');
+            one.lib.alert('Flow Entry added');
+            one.main.dashlet.left.top.empty();
+            one.f.flows.dashlet(one.main.dashlet.left.top);
+          } else {
+            alert('Could not add flow: '+data);
+          }
+        });
+      }
+    },
+    ajax : {
+      nodes : function(successCallback) {
+        $.getJSON(one.f.address.root+one.f.address.flows.nodes, function(data) {
+          var nodes = one.f.flows.modal.data.nodes(data);
+          var nodeports = data;
+          one.f.flows.registry['nodes'] = nodes;
+          one.f.flows.registry['nodeports'] = nodeports;
+
+          successCallback(nodes, nodeports);
+        });
+      },
+      saveflow : function(resource, callback) {
+        $.post(one.f.address.root+one.f.address.flows.flow, resource, function(data) {
+          callback(data);
+        });
+      },
+      removeflow : function(id, node, callback) {
+        resource = {};
+        resource['action'] = 'remove';
+        $.post(one.f.address.root+one.f.address.flows.flow+'/'+node+'/'+id, resource, function(data) {
+          callback(data);
+        });
+      },
+      toggleflow : function(id, node, callback) {
+        resource = {};
+        resource['action'] = 'toggle';
+        $.post(one.f.address.root+one.f.address.flows.flow+'/'+node+'/'+id, resource, function(data) {
+          callback(data);
+        });
+      }
+    },
+    data : {
+      nodes : function(data) {
+        result = {};
+        $.each(data, function(key, value) {
+          result[key] = value['name'];
+        });
+        return result;
+      }
+    },
+    body : function(nodes, nodeports, edit) {
+      var $form = $(document.createElement('form'));
+      var $fieldset = $(document.createElement('fieldset'));
+      var existingFlow;
+      // flow description
+      var $legend = one.lib.form.legend("");
+      $legend.css('visibility', 'hidden');
+      $fieldset.append($legend);
+      // name
+      var $label = one.lib.form.label("Name");
+      var $input = one.lib.form.input("Flow Name");
+      $input.attr('id', one.f.flows.id.modal.form.name);
+      if(edit) {
+        $input.attr('disabled', 'disabled');
+        var flows = one.f.flows.registry.flows;
+        $(flows).each(function(index, value) {
+          if (value.name == one.f.flows.registry.selectedId && value.nodeId == one.f.flows.registry.selectedNode) {
+            existingFlow = value.flow;
+          }
+        });
+        $input.val(existingFlow.name);
+      }
+
+      $fieldset.append($label).append($input);
+      // node
+      var $label = one.lib.form.label("Node");
+      var $select = one.lib.form.select.create(nodes);
+      one.lib.form.select.prepend($select, { '' : 'Please Select a Node' });
+      $select.val($select.find("option:first").val());
+      $select.attr('id', one.f.flows.id.modal.form.nodes);
+      if(edit) {
+        $select.attr('disabled', 'disabled');
+        $select.val(existingFlow.node.type + "|"+ existingFlow.node.nodeIDString);
+      }
+
+      // bind onchange
+      $select.change(function() {
+        // retrieve port value
+        var node = $(this).find('option:selected').attr('value');
+        var $ports = $('#'+one.f.flows.id.modal.form.port);
+        if (node == '') {
+          one.lib.form.select.inject($ports, {});
+          return;
+        }
+        one.f.flows.registry['currentNode'] = node;
+        var ports = nodeports[node]['ports'];
+        one.lib.form.select.inject($ports, ports);
+        one.lib.form.select.prepend($ports, { '' : 'Please Select a Port' });
+        $ports.val($ports.find("option:first").val());
+        if(edit) {
+          $ports.val( existingFlow.ingressPort );
+        }
+        $.getJSON(one.f.address.root+'/valid-flows/'+node, function(response) {
+          var $select = $('#'+one.f.flows.id.modal.form.action, $fieldset);
+          one.lib.form.select.inject($select, response);
+          one.lib.form.select.prepend($select, {'' : 'Please Select an Action'});
+          // when selecting an action
+          $select.change(function() {
+            var action = $(this).find('option:selected');
+            one.f.flows.modal.action.parse(action.attr('value'));
+            $select[0].selectedIndex = 0;
+          });
+        });
+      });
+
+      $fieldset.append($label).append($select);
+      // input port
+      var $label = one.lib.form.label("Input Port");
+      var $select = one.lib.form.select.create();
+
+      $select.attr('id', one.f.flows.id.modal.form.port);
+      $fieldset.append($label).append($select);
+      // priority
+      var $label = one.lib.form.label("Priority");
+      var $input = one.lib.form.input("Priority");
+      $input.attr('id', one.f.flows.id.modal.form.priority);
+      $input.val('500');
+      $fieldset.append($label).append($input);
+      if(edit) {
+        $input.val(existingFlow.priority);
+      }
+      // hardTimeout
+      var $label = one.lib.form.label("Hard Timeout");
+      var $input = one.lib.form.input("Hard Timeout");
+      $input.attr('id', one.f.flows.id.modal.form.hardTimeout);
+      if(edit) {
+        $input.val(existingFlow.hardTimeout);
+      }
+      $fieldset.append($label).append($input);
+
+      // idleTimeout
+      var $label = one.lib.form.label("Idle Timeout");
+      var $input = one.lib.form.input("Idle Timeout");
+      $input.attr('id', one.f.flows.id.modal.form.idleTimeout);
+      $fieldset.append($label).append($input);
+      if(edit) {
+        $input.val(existingFlow.idleTimeout);
+      }
+      // cookie
+      var $label = one.lib.form.label("Cookie");
+      var $input = one.lib.form.input("Cookie");
+      $input.attr('id', one.f.flows.id.modal.form.cookie);
+      $fieldset.append($label).append($input);
+      if(edit) {
+        $input.val(existingFlow.cookie);
+      }
+
+      // layer 2
+      var $legend = one.lib.form.legend("Layer 2");
+      $fieldset.append($legend);
+      // etherType
+      var $label = one.lib.form.label("Ethernet Type");
+      var $input = one.lib.form.input("Ethernet Type");
+      $input.attr('id', one.f.flows.id.modal.form.etherType);
+      $input.val('0x800');
+      $fieldset.append($label).append($input);
+      if(edit) {
+        $input.val(existingFlow.etherType);
+      }
+      // vlanId
+      var $label = one.lib.form.label("VLAN Identification Number");
+      var $input = one.lib.form.input("VLAN Identification Number");
+      $input.attr('id', one.f.flows.id.modal.form.vlanId);
+      var $help = one.lib.form.help("Range: 0 - 4095");
+      $fieldset.append($label).append($input).append($help);
+      if(edit) {
+        $input.val(existingFlow.vlanId);
+      }
+
+      // vlanPriority
+      var $label = one.lib.form.label("VLAN Priority");
+      var $input = one.lib.form.input("VLAN Priority");
+      $input.attr('id', one.f.flows.id.modal.form.vlanPriority);
+      var $help = one.lib.form.help("Range: 0 - 7");
+      $fieldset.append($label).append($input).append($help);
+      if(edit) {
+        $input.val(existingFlow.vlanPriority);
+      }
+
+      // srcMac
+      var $label = one.lib.form.label("Source MAC Address");
+      var $input = one.lib.form.input("3c:97:0e:75:c3:f7");
+      $input.attr('id', one.f.flows.id.modal.form.srcMac);
+      $fieldset.append($label).append($input);
+      if(edit) {
+        $input.val(existingFlow.srcMac);
+      }
+      // dstMac
+      var $label = one.lib.form.label("Destination MAC Address");
+      var $input = one.lib.form.input("7c:d1:c3:e8:e6:99");
+      $input.attr('id', one.f.flows.id.modal.form.dstMac);
+      $fieldset.append($label).append($input);
+      if(edit) {
+        $input.val(existingFlow.dstMac);
+      }
+      // layer 3
+      var $legend = one.lib.form.legend("Layer 3");
+      $fieldset.append($legend);
+
+      // srcIp
+      var $label = one.lib.form.label("Source IP Address");
+      var $input = one.lib.form.input("192.168.3.128");
+      $input.attr('id', one.f.flows.id.modal.form.srcIp);
+      $fieldset.append($label).append($input);
+      if(edit) {
+        $input.val(existingFlow.srcIp);
+      }
+      // dstIp
+      var $label = one.lib.form.label("Destination IP Address");
+      var $input = one.lib.form.input("2001:2334::0/32");
+      $input.attr('id', one.f.flows.id.modal.form.dstIp);
+      $fieldset.append($label).append($input);
+      if(edit) {
+        $input.val(existingFlow.dstIp);
+      }
+      // tosBits
+      var $label = one.lib.form.label("ToS Bits");
+      var $input = one.lib.form.input("ToS Bits");
+      $input.attr('id', one.f.flows.id.modal.form.tosBits);
+      var $help = one.lib.form.help("Range: 0 - 63");
+      $fieldset.append($label).append($input).append($help);
+      if(edit) {
+        $input.val(existingFlow.tosBits);
+      }
+
+      // layer 4
+      var $legend = one.lib.form.legend("Layer 4");
+      $fieldset.append($legend);
+      // srcPort
+      var $label = one.lib.form.label("Source Port");
+      var $input = one.lib.form.input("Source Port");
+      $input.attr('id', one.f.flows.id.modal.form.srcPort);
+      var $help = one.lib.form.help("Range: 0 - 65535");
+      $fieldset.append($label).append($input).append($help);
+      if(edit) {
+        $input.val(existingFlow.srcPort);
+      }
+      // dstPort
+      var $label = one.lib.form.label("Destination Port");
+      var $input = one.lib.form.input("Destination Port");
+      $input.attr('id', one.f.flows.id.modal.form.dstPort);
+      var $help = one.lib.form.help("Range: 0 - 65535");
+      $fieldset.append($label).append($input).append($help);
+      if(edit) {
+        $input.val(existingFlow.dstPort);
+      }
+      // protocol
+      var $label = one.lib.form.label("Protocol");
+      var $input = one.lib.form.input("Protocol");
+      $input.attr('id', one.f.flows.id.modal.form.protocol);
+      $fieldset.append($label).append($input);
+      if(edit) {
+        $input.val(existingFlow.protocol);
+      }
+      // actions
+      var $legend = one.lib.form.label("Actions");
+      $fieldset.append($legend);
+      // actions table
+      var tableAttributes = ["table-striped", "table-bordered", "table-condensed", "table-hover", "table-cursor"];
+      var $table = one.lib.dashlet.table.table(tableAttributes);
+      $table.attr('id', one.f.flows.id.modal.action.table);
+      var tableHeaders = ["Action", "Data"];
+      var $thead = one.lib.dashlet.table.header(tableHeaders);
+      var $tbody = one.lib.dashlet.table.body("", tableHeaders);
+      $table.append($thead).append($tbody);
+      // actions
+      var actions = {
+        "" : "Please Select an Action",
+        "DROP" : "Drop",
+        "LOOPBACK" : "Loopback",
+        "FLOOD" : "Flood",
+        "FLOOD_ALL" : "Flood All",
+        "CONTROLLER" : "Controller",
+        "SW_PATH" : "Software Path",
+        "HW_PATH" : "Hardware Path",
+        "OUTPUT" : "Add Output Ports",
+        "ENQUEUE" : "Enqueue",
+        "SET_VLAN_ID" : "Set VLAN ID",
+        "SET_VLAN_PCP" : "Set VLAN Priority",
+        "SET_VLAN_CFI" : "Set VLAN CFI",
+        "POP_VLAN" : "Strip VLAN Header",
+        "PUSH_VLAN" : "Push VLAN",
+        "SET_DL_SRC" : "Modify Datalayer Source Address",
+        "SET_DL_DST" : "Modify Datalayer Destination Address",
+        "SET_DL_TYPE" : "Set Ethertype",
+        "SET_NW_SRC" : "Modify Network Source Address",
+        "SET_NW_DST" :"Modify Network Destination Address",
+        "SET_NW_TOS" : "Modify ToS Bits",
+        "SET_TP_SRC" : "Modify Transport Source Port",
+        "SET_TP_DST" : "Modify Transport Destination Port"
+      };
+      var $select = one.lib.form.select.create(actions);
+      $select.attr('id', one.f.flows.id.modal.form.action);
+      // when selecting an action
+      $select.change(function() {
+        var action = $(this).find('option:selected');
+        one.f.flows.modal.action.parse(action.attr('value'));
+        $select[0].selectedIndex = 0;
+      });
+
+      if(edit) {
+        $(existingFlow.actions).each(function(index, value){
+          setTimeout(function(){
+            var locEqualTo = value.indexOf("=");
+            if ( locEqualTo == -1 ) {
+              one.f.flows.modal.action.add.add(actions[value], value);
             } else {
-                resource['action'] = 'add';
+              var action = value.substr(0,locEqualTo);
+              if( action == "OUTPUT") {
+                var portIds = value.substr(locEqualTo+1).split(",");
+                var ports = [];
+                var allPorts = one.f.flows.registry.nodeports[one.f.flows.registry.currentNode]['ports'];
+                for(var i =0; i < portIds.length ; i++) {
+                  var portName = allPorts[portIds[i]];
+                  ports.push(portName);
+                }
+                one.f.flows.modal.action.add.addPortsToTable(ports.join(", "), portIds.join(","));
+              } else {
+                var val = value.substr(locEqualTo+1);
+                one.f.flows.modal.action.add.addDataToTable(actions[action], val, action)
+              }
             }
+          }, 1000)
+        });
+      }
+      $fieldset.append($select).append($table);
 
-            resource['nodeId'] = nodeId;
-
-            if (edit) {
-                    one.f.flows.modal.ajax.saveflow(resource, function(data) {
-                    if (data == "Success") {
-                        $modal.modal('hide').on('hidden', function () {
-                            one.f.flows.detail(result['name'], nodeId);
-                        });
-                        one.lib.alert('Flow Entry edited');
-                        one.main.dashlet.left.top.empty();
-                        one.f.flows.dashlet(one.main.dashlet.left.top);
-                    } else {
-                        alert('Could not edit flow: '+data);
-                    }
-                });
-            } else {
-                    one.f.flows.modal.ajax.saveflow(resource, function(data) {
-                    if (data == "Success") {
-                        $modal.modal('hide');
-                        one.lib.alert('Flow Entry added');
-                        one.main.dashlet.left.top.empty();
-                        one.f.flows.dashlet(one.main.dashlet.left.top);
-                    } else {
-                        alert('Could not add flow: '+data);
-                    }
-                });
-            }
+      // return
+      $form.append($fieldset);
+      return $form;
+    },
+    action : {
+      parse : function(option) {
+        switch (option) {
+          case "OUTPUT" :
+            var h3 = "Add Output Port";
+            var $modal = one.f.flows.modal.action.initialize(h3, one.f.flows.modal.action.body.addOutputPorts, one.f.flows.modal.action.add.addOutputPorts);
+            $modal.modal();
+            break;
+          case "SET_VLAN_ID" :
+            var h3 = "Set VLAN ID";
+            var placeholder = "VLAN Identification Number";
+            var id = one.f.flows.id.modal.action.setVlanId;
+            var help = "Range: 0 - 4095";
+            var action = 'SET_VLAN_ID';
+            var name = "VLAN ID";
+            var body = function() {
+              return one.f.flows.modal.action.body.set(h3, placeholder, id, help);
+            };
+            var add = function($modal) {
+              one.f.flows.modal.action.add.set(name, id, action, $modal);
+            };
+            var $modal = one.f.flows.modal.action.initialize(h3, body, add);
+            $modal.modal();
+            break;
+          case "SET_VLAN_PCP" :
+            var h3 = "Set VLAN Priority";
+            var placeholder = "VLAN Priority";
+            var id = one.f.flows.id.modal.action.setVlanPriority;
+            var help = "Range: 0 - 7";
+            var action = 'SET_VLAN_PCP';
+            var name = "VLAN Priority";
+            var body = function() {
+              return one.f.flows.modal.action.body.set(h3, placeholder, id, help);
+            };
+            var add = function($modal) {
+              one.f.flows.modal.action.add.set(name, id, action, $modal);
+            };
+            var $modal = one.f.flows.modal.action.initialize(h3, body, add);
+            $modal.modal();
+            break;
+          case "SET_VLAN_CFI" :
+            var h3 = "Set VLAN CFI";
+            var placeholder = "VLAN CFI";
+            var id = one.f.flows.id.modal.action.setVlanCfi;
+            var help = "Range: 0 - 1";
+            var action = 'SET_VLAN_CFI';
+            var name = "VLAN CFI";
+            var body = function() {
+              return one.f.flows.modal.action.body.set(h3, placeholder, id, help);
+            };
+            var add = function($modal) {
+              one.f.flows.modal.action.add.set(name, id, action, $modal);
+            };
+            var $modal = one.f.flows.modal.action.initialize(h3, body, add);
+            $modal.modal();
+            break;
+          case "POP_VLAN" :
+            var name = "Strip VLAN Header";
+            var action = 'POP_VLAN';
+            one.f.flows.modal.action.add.add(name, action);
+            break;
+          case "PUSH_VLAN" :
+            var h3 = "Push VLAN";
+            var placeholder = "VLAN";
+            var id = one.f.flows.id.modal.action.pushVlan;
+            var help = "Range: 0 - 4095";
+            var action = 'PUSH_VLAN';
+            var name = "VLAN";
+            var body = function() {
+              return one.f.flows.modal.action.body.set(h3, placeholder, id, help);
+            };
+            var add = function($modal) {
+              one.f.flows.modal.action.add.set(name, id, action, $modal);
+            };
+            var $modal = one.f.flows.modal.action.initialize(h3, body, add);
+            $modal.modal();
+            break;
+          case "SET_DL_SRC" :
+            var h3 = "Set Source MAC Address";
+            var placeholder = "Source MAC Address";
+            var id = one.f.flows.id.modal.action.modifyDatalayerSourceAddress;
+            var help = "Example: 00:11:22:aa:bb:cc";
+            var action = 'SET_DL_SRC';
+            var name = "Source MAC";
+            var body = function() {
+              return one.f.flows.modal.action.body.set(h3, placeholder, id, help);
+            };
+            var add = function($modal) {
+              one.f.flows.modal.action.add.set(name, id, action, $modal);
+            };
+            var $modal = one.f.flows.modal.action.initialize(h3, body, add);
+            $modal.modal();
+            break;
+          case "SET_DL_DST" :
+            var h3 = "Set Destination MAC Address";
+            var placeholder = "Destination MAC Address";
+            var id = one.f.flows.id.modal.action.modifyDatalayerDestinationAddress;
+            var help = "Example: 00:11:22:aa:bb:cc";
+            var action = 'SET_DL_DST';
+            var name = "Destination MAC";
+            var body = function() {
+              return one.f.flows.modal.action.body.set(h3, placeholder, id, help);
+            };
+            var add = function($modal) {
+              one.f.flows.modal.action.add.set(name, id, action, $modal);
+            };
+            var $modal = one.f.flows.modal.action.initialize(h3, body, add);
+            $modal.modal();
+            break;
+          case "SET_DL_TYPE" :
+            var h3 = "Set Ethertype";
+            var placeholder = "Ethertype";
+            var id = one.f.flows.id.modal.action.setEthertype;
+            var help = "Range: 0 - 65535";
+            var action = 'SET_DL_TYPE';
+            var name = "Ethertype";
+            var body = function() {
+              return one.f.flows.modal.action.body.set(h3, placeholder, id, help);
+            };
+            var add = function($modal) {
+              one.f.flows.modal.action.add.set(name, id, action, $modal);
+            };
+            var $modal = one.f.flows.modal.action.initialize(h3, body, add);
+            $modal.modal();
+            break;
+          case "SET_NW_SRC" :
+            var h3 = "Set IP Source Address";
+            var placeholder = "Source IP Address";
+            var id = one.f.flows.id.modal.action.modifyNetworkSourceAddress;
+            var help = "Example: 127.0.0.1";
+            var action = 'SET_NW_SRC';
+            var name = "Source IP";
+            var body = function() {
+              return one.f.flows.modal.action.body.set(h3, placeholder, id, help);
+            };
+            var add = function($modal) {
+              one.f.flows.modal.action.add.set(name, id, action, $modal);
+            };
+            var $modal = one.f.flows.modal.action.initialize(h3, body, add);
+            $modal.modal();
+            break;
+          case "SET_NW_DST" :
+            var h3 = "Set IP Destination Address";
+            var placeholder = "Destination IP Address";
+            var id = one.f.flows.id.modal.action.modifyNetworkDestinationAddress;
+            var help = "Example: 127.0.0.1";
+            var action = 'SET_NW_DST';
+            var name = "Destination IP";
+            var body = function() {
+              return one.f.flows.modal.action.body.set(h3, placeholder, id, help);
+            };
+            var add = function($modal) {
+              one.f.flows.modal.action.add.set(name, id, action, $modal);
+            };
+            var $modal = one.f.flows.modal.action.initialize(h3, body, add);
+            $modal.modal();
+            break;
+          case "SET_NW_TOS" :
+            var h3 = "Set IPv4 ToS";
+            var placeholder = "IPv4 ToS";
+            var id = one.f.flows.id.modal.action.modifyTosBits;
+            var help = "Range: 0 - 63";
+            var action = 'SET_NW_TOS';
+            var name = "ToS Bits";
+            var body = function() {
+              return one.f.flows.modal.action.body.set(h3, placeholder, id, help);
+            };
+            var add = function($modal) {
+              one.f.flows.modal.action.add.set(name, id, action, $modal);
+            };
+            var $modal = one.f.flows.modal.action.initialize(h3, body, add);
+            $modal.modal();
+            break;
+          case "SET_TP_SRC" :
+            var h3 = "Set Transport Source Port";
+            var placeholder = "Transport Source Port";
+            var id = one.f.flows.id.modal.action.modifyTransportSourcePort;
+            var help = "Range: 1 - 65535";
+            var action = 'SET_TP_SRC';
+            var name = "Source Port";
+            var body = function() {
+              return one.f.flows.modal.action.body.set(h3, placeholder, id, help);
+            };
+            var add = function($modal) {
+              one.f.flows.modal.action.add.set(name, id, action, $modal);
+            };
+            var $modal = one.f.flows.modal.action.initialize(h3, body, add);
+            $modal.modal();
+            break;
+          case "SET_TP_DST" :
+            var h3 = "Set Transport Destination Port";
+            var placeholder = "Transport Destination Port";
+            var id = one.f.flows.id.modal.action.modifyTransportDestinationPort;
+            var help = "Range: 1 - 65535";
+            var action = 'SET_TP_DST';
+            var name = "Destination Port";
+            var body = function() {
+              return one.f.flows.modal.action.body.set(h3, placeholder, id, help);
+            };
+            var add = function($modal) {
+              one.f.flows.modal.action.add.set(name, id, action, $modal);
+            };
+            var $modal = one.f.flows.modal.action.initialize(h3, body, add);
+            $modal.modal();
+            break;
+          case "ENQUEUE" :
+            var h3 = "Enqueue";
+            var placeholder = "Enqueue";
+            var id = one.f.flows.id.modal.action.enqueue;
+            var $modal = one.f.flows.modal.action.initialize(h3, one.f.flows.modal.action.body.addEnqueue, one.f.flows.modal.action.add.addEnqueue);
+            $modal.modal();
+            break;
+          case "DROP" :
+            var name = "Drop";
+            var action = 'DROP';
+            one.f.flows.modal.action.add.add(name, action);
+            break;
+          case "LOOPBACK" :
+            var name = "Loopback";
+            var action = 'LOOPBACK';
+            one.f.flows.modal.action.add.add(name, action);
+            break;
+          case "FLOOD" :
+            var name = "Flood";
+            var action = 'FLOOD';
+            one.f.flows.modal.action.add.add(name, action);
+            break;
+          case "FLOOD_ALL" :
+            var name = "Flood All";
+            var action = 'FLOOD_ALL';
+            one.f.flows.modal.action.add.add(name, action);
+            break;
+          case "SW_PATH" :
+            var name = "Software Path";
+            var action = 'SW_PATH';
+            one.f.flows.modal.action.add.add(name, action);
+            break;
+          case "HW_PATH" :
+            var name = "Hardware Path";
+            var action = 'HW_PATH';
+            one.f.flows.modal.action.add.add(name, action);
+            break;
+          case "CONTROLLER" :
+            var name = "Controller";
+            var action = 'CONTROLLER';
+            one.f.flows.modal.action.add.add(name, action);
+            break;
+        }
+      },
+      initialize : function(h3, bodyCallback, addCallback) {
+        var footer = one.f.flows.modal.action.footer();
+        var $body = bodyCallback();
+        var $modal = one.lib.modal.spawn(one.f.flows.id.modal.action.modal, h3, $body, footer);
+        // bind close button
+        $('#'+one.f.flows.id.modal.action.close, $modal).click(function() {
+          $modal.modal('hide');
+        });
+        // bind add flow button
+        $('#'+one.f.flows.id.modal.action.add, $modal).click(function() {
+          addCallback($modal);
+        });
+        return $modal;
+      },
+      add : {
+        addOutputPorts : function($modal) {
+          var $options = $('#'+one.f.flows.id.modal.action.addOutputPorts).find('option:selected');
+          var ports = '';
+          var pid = '';
+          $options.each(function(index, value) {
+            ports = ports+$(value).text()+", ";
+            pid = pid+$(value).attr('value')+",";
+          });
+          ports = ports.slice(0,-2);
+          pid = pid.slice(0,-1);
+          one.f.flows.modal.action.add.addPortsToTable(ports, pid);
+          $modal.modal('hide');
         },
-        ajax : {
-            nodes : function(successCallback) {
-                $.getJSON(one.f.address.root+one.f.address.flows.nodes, function(data) {
-                    var nodes = one.f.flows.modal.data.nodes(data);
-                    var nodeports = data;
-                    one.f.flows.registry['nodes'] = nodes;
-                    one.f.flows.registry['nodeports'] = nodeports;
-
-                    successCallback(nodes, nodeports);
-                });
-            },
-            saveflow : function(resource, callback) {
-                $.post(one.f.address.root+one.f.address.flows.flow, resource, function(data) {
-                    callback(data);
-                });
-            },
-            removeflow : function(id, node, callback) {
-                resource = {};
-                resource['action'] = 'remove';
-                $.post(one.f.address.root+one.f.address.flows.flow+'/'+node+'/'+id, resource, function(data) {
-                    callback(data);
-                });
-            },
-            toggleflow : function(id, node, callback) {
-                resource = {};
-                resource['action'] = 'toggle';
-                $.post(one.f.address.root+one.f.address.flows.flow+'/'+node+'/'+id, resource, function(data) {
-                    callback(data);
-                });
-            }
+        addEnqueue : function($modal) {
+          var $options = $('#'+one.f.flows.id.modal.action.addOutputPorts).find('option:selected');
+          var ports = '';
+          var pid = '';
+          $options.each(function(index, value) {
+            ports = ports+$(value).text()+", ";
+            pid = pid+$(value).attr('value')+",";
+          });
+          var $input = $('#'+one.f.flows.id.modal.action.queue);
+          var queue = $input.val();
+          ports = ports.slice(0,-2);
+          pid = pid.slice(0,-1);
+          one.f.flows.modal.action.add.addEnqueueToTable(ports, pid, queue);
+          $modal.modal('hide');
         },
-        data : {
-            nodes : function(data) {
-                result = {};
-                $.each(data, function(key, value) {
-                    result[key] = value['name'];
-                });
-                return result;
-            }
+        addEnqueueToTable : function(ports, pid, queue) {
+          if (queue !== '' && queue >= 0) {
+            ports += ':'+queue;
+          }
+          var $tr = one.f.flows.modal.action.table.add("Enqueue", ports);
+          $tr.attr('id', 'ENQUEUE');
+          if (queue !== '' && queue >= 0) {
+            $tr.data('action', 'ENQUEUE='+pid+':'+queue);
+          } else {
+            $tr.data('action', 'ENQUEUE='+pid+':0'); // default queue to 0
+          }
+          $tr.click(function() {
+            one.f.flows.modal.action.add.modal.initialize(this);
+          });
+          one.f.flows.modal.action.table.append($tr);
         },
-        body : function(nodes, nodeports, edit) {
-            var $form = $(document.createElement('form'));
-            var $fieldset = $(document.createElement('fieldset'));
-            var existingFlow;
-            // flow description
-            var $legend = one.lib.form.legend("");
-            $legend.css('visibility', 'hidden');
-            $fieldset.append($legend);
-            // name
-            var $label = one.lib.form.label("Name");
-            var $input = one.lib.form.input("Flow Name");
-            $input.attr('id', one.f.flows.id.modal.form.name);
-            if(edit) {
-                $input.attr('disabled', 'disabled');
-                var flows = one.f.flows.registry.flows;
-                $(flows).each(function(index, value) {
-                  if (value.name == one.f.flows.registry.selectedId && value.nodeId == one.f.flows.registry.selectedNode) {
-                    existingFlow = value.flow;
-                  }
-                });
-                $input.val(existingFlow.name);
-            }
-
-            $fieldset.append($label).append($input);
-            // node
-            var $label = one.lib.form.label("Node");
-            var $select = one.lib.form.select.create(nodes);
-            one.lib.form.select.prepend($select, { '' : 'Please Select a Node' });
-            $select.val($select.find("option:first").val());
-            $select.attr('id', one.f.flows.id.modal.form.nodes);
-            if(edit) {
-                $select.attr('disabled', 'disabled');
-                $select.val(existingFlow.node.type + "|"+ existingFlow.node.nodeIDString);
-            }
+        addPortsToTable : function(ports, pid){
+          var $tr = one.f.flows.modal.action.table.add("Add Output Ports", ports);
+          $tr.attr('id', 'OUTPUT');
+          $tr.data('action', 'OUTPUT='+pid);
+          $tr.click(function() {
+            one.f.flows.modal.action.add.modal.initialize(this);
+          });
+          one.f.flows.modal.action.table.append($tr);
+        },
+        add : function(name, action) {
+          var $tr = one.f.flows.modal.action.table.add(name);
+          $tr.attr('id', action);
+          $tr.data('action', action);
+          $tr.click(function() {
+            one.f.flows.modal.action.add.modal.initialize(this);
+          });
+          one.f.flows.modal.action.table.append($tr);
+        },
+        set : function(name, id, action, $modal) {
+          var $input = $('#'+id);
+          var value = $input.val();
+          one.f.flows.modal.action.add.addDataToTable(name,value,action)
+            $modal.modal('hide');
+        },
+        addDataToTable : function(name,value,action) {
+          var $tr = one.f.flows.modal.action.table.add(name, value);
+          $tr.attr('id', action);
+          $tr.data('action', action+'='+value);
+          $tr.click(function() {
+            one.f.flows.modal.action.add.modal.initialize(this);
+          });
+          one.f.flows.modal.action.table.append($tr);
+        },
+        remove : function(that) {
+          $(that).remove();
+          var $table = $('#'+one.f.flows.id.modal.action.table);
+          if ($table.find('tbody').find('tr').size() == 0) {
+            var $tr = $(document.createElement('tr'));
+            var $td = $(document.createElement('td'));
+            $td.attr('colspan', '3');
+            $tr.addClass('empty');
+            $td.text('No data available');
+            $tr.append($td);
+            $table.find('tbody').append($tr);
+          }
+        },
+        modal : {
+          initialize : function(that) {
+            var h3 = "Remove Action";
+            var footer = one.f.flows.modal.action.add.modal.footer();
+            var $body = one.f.flows.modal.action.add.modal.body();
+            var $modal = one.lib.modal.spawn(one.f.flows.id.modal.action.modal.modal, h3, $body, footer);
+
+            // bind cancel button
+            $('#'+one.f.flows.id.modal.action.modal.cancel, $modal).click(function() {
+              $modal.modal('hide');
+            });
 
-            // bind onchange
-            $select.change(function() {
-                // retrieve port value
-                var node = $(this).find('option:selected').attr('value');
-                var $ports = $('#'+one.f.flows.id.modal.form.port);
-                if (node == '') {
-                    one.lib.form.select.inject($ports, {});
-                    return;
-                }
-                one.f.flows.registry['currentNode'] = node;
-                var ports = nodeports[node]['ports'];
-                one.lib.form.select.inject($ports, ports);
-                one.lib.form.select.prepend($ports, { '' : 'Please Select a Port' });
-                $ports.val($ports.find("option:first").val());
-                if(edit) {
-                    $ports.val( existingFlow.ingressPort );
-                }
+            // bind remove button
+            $('#'+one.f.flows.id.modal.action.modal.remove, $modal).click(function() {
+              one.f.flows.modal.action.add.remove(that);
+              $modal.modal('hide');
             });
 
-            $fieldset.append($label).append($select);
-            // input port
-            var $label = one.lib.form.label("Input Port");
-            var $select = one.lib.form.select.create();
-
-            $select.attr('id', one.f.flows.id.modal.form.port);
-            $fieldset.append($label).append($select);
-            // priority
-            var $label = one.lib.form.label("Priority");
-            var $input = one.lib.form.input("Priority");
-            $input.attr('id', one.f.flows.id.modal.form.priority);
-            $input.val('500');
-            $fieldset.append($label).append($input);
-            if(edit) {
-                $input.val(existingFlow.priority);
-            }
-            // hardTimeout
-            var $label = one.lib.form.label("Hard Timeout");
-            var $input = one.lib.form.input("Hard Timeout");
-            $input.attr('id', one.f.flows.id.modal.form.hardTimeout);
-            if(edit) {
-                $input.val(existingFlow.hardTimeout);
-            }
-            $fieldset.append($label).append($input);
-
-            // idleTimeout
-            var $label = one.lib.form.label("Idle Timeout");
-            var $input = one.lib.form.input("Idle Timeout");
-            $input.attr('id', one.f.flows.id.modal.form.idleTimeout);
-            $fieldset.append($label).append($input);
-            if(edit) {
-                $input.val(existingFlow.idleTimeout);
-            }
-            // cookie
-            var $label = one.lib.form.label("Cookie");
-            var $input = one.lib.form.input("Cookie");
-            $input.attr('id', one.f.flows.id.modal.form.cookie);
-            $fieldset.append($label).append($input);
-            if(edit) {
-                $input.val(existingFlow.cookie);
-            }
+            $modal.modal();
+          },
+          body : function() {
+            var $p = $(document.createElement('p'));
+            $p.append("Remove this action?");
+            return $p;
+          },
+          footer : function() {
+            var footer = [];
 
-            // layer 2
-            var $legend = one.lib.form.legend("Layer 2");
-            $fieldset.append($legend);
-            // etherType
-            var $label = one.lib.form.label("Ethernet Type");
-            var $input = one.lib.form.input("Ethernet Type");
-            $input.attr('id', one.f.flows.id.modal.form.etherType);
-            $input.val('0x800');
-            $fieldset.append($label).append($input);
-            if(edit) {
-                $input.val(existingFlow.etherType);
-            }
-            // vlanId
-            var $label = one.lib.form.label("VLAN Identification Number");
-            var $input = one.lib.form.input("VLAN Identification Number");
-            $input.attr('id', one.f.flows.id.modal.form.vlanId);
-            var $help = one.lib.form.help("Range: 0 - 4095");
-            $fieldset.append($label).append($input).append($help);
-            if(edit) {
-                $input.val(existingFlow.vlanId);
-            }
+            var removeButton = one.lib.dashlet.button.single("Remove Action", one.f.flows.id.modal.action.modal.remove, "btn-danger", "");
+            var $removeButton = one.lib.dashlet.button.button(removeButton);
+            footer.push($removeButton);
 
-            // vlanPriority
-            var $label = one.lib.form.label("VLAN Priority");
-            var $input = one.lib.form.input("VLAN Priority");
-            $input.attr('id', one.f.flows.id.modal.form.vlanPriority);
-            var $help = one.lib.form.help("Range: 0 - 7");
-            $fieldset.append($label).append($input).append($help);
-            if(edit) {
-                $input.val(existingFlow.vlanPriority);
-            }
+            var cancelButton = one.lib.dashlet.button.single("Cancel", one.f.flows.id.modal.action.modal.cancel, "", "");
+            var $cancelButton = one.lib.dashlet.button.button(cancelButton);
+            footer.push($cancelButton);
 
-            // srcMac
-            var $label = one.lib.form.label("Source MAC Address");
-            var $input = one.lib.form.input("3c:97:0e:75:c3:f7");
-            $input.attr('id', one.f.flows.id.modal.form.srcMac);
-            $fieldset.append($label).append($input);
-            if(edit) {
-                $input.val(existingFlow.srcMac);
-            }
-            // dstMac
-            var $label = one.lib.form.label("Destination MAC Address");
-            var $input = one.lib.form.input("7c:d1:c3:e8:e6:99");
-            $input.attr('id', one.f.flows.id.modal.form.dstMac);
-            $fieldset.append($label).append($input);
-            if(edit) {
-                $input.val(existingFlow.dstMac);
-            }
-            // layer 3
-            var $legend = one.lib.form.legend("Layer 3");
-            $fieldset.append($legend);
-
-            // srcIp
-            var $label = one.lib.form.label("Source IP Address");
-            var $input = one.lib.form.input("192.168.3.128");
-            $input.attr('id', one.f.flows.id.modal.form.srcIp);
-            $fieldset.append($label).append($input);
-            if(edit) {
-                $input.val(existingFlow.srcIp);
-            }
-            // dstIp
-            var $label = one.lib.form.label("Destination IP Address");
-            var $input = one.lib.form.input("2001:2334::0/32");
-            $input.attr('id', one.f.flows.id.modal.form.dstIp);
-            $fieldset.append($label).append($input);
-            if(edit) {
-                $input.val(existingFlow.dstIp);
-            }
-            // tosBits
-            var $label = one.lib.form.label("ToS Bits");
-            var $input = one.lib.form.input("ToS Bits");
-            $input.attr('id', one.f.flows.id.modal.form.tosBits);
-            var $help = one.lib.form.help("Range: 0 - 63");
-            $fieldset.append($label).append($input).append($help);
-            if(edit) {
-                $input.val(existingFlow.tosBits);
-            }
+            return footer;
+          }
+        }
+      },
+      table : {
+        add : function(action, data) {
+          var $tr = $(document.createElement('tr'));
+          var $td = $(document.createElement('td'));
+          $td.append(action);
+          $tr.append($td);
+          var $td = $(document.createElement('td'));
+          if (data != undefined) $td.append(data);
+          $tr.append($td);
+          return $tr;
+        },
+        append : function($tr) {
+          var $table = $('#'+one.f.flows.id.modal.action.table);
+          var $empty = $table.find('.empty').parent();
+          if ($empty.size() > 0) $empty.remove();
+          $table.append($tr);
+        }
+      },
+      body : {
+        common : function() {
+          var $form = $(document.createElement('form'));
+          var $fieldset = $(document.createElement('fieldset'));
+          return [$form, $fieldset];
+        },
+        addOutputPorts : function() {
+          var common = one.f.flows.modal.action.body.common();
+          var $form = common[0];
+          var $fieldset = common[1];
+          // output port
+          $label = one.lib.form.label("Select Output Ports");
+          if (one.f.flows.registry.currentNode == undefined){
+            return; //Selecting Output ports without selecting node throws an exception
+          }
+          var ports = one.f.flows.registry.nodeports[one.f.flows.registry.currentNode]['ports'];
+          $select = one.lib.form.select.create(ports, true);
+          $select.attr('id', one.f.flows.id.modal.action.addOutputPorts);
+          $fieldset.append($label).append($select);
+          $form.append($fieldset);
+          return $form;
+        },
+        addEnqueue : function() {
+          var common = one.f.flows.modal.action.body.common();
+          var $form = common[0];
+          var $fieldset = common[1];
+          // output port
+          $label = one.lib.form.label("Select Output Ports");
+          if (one.f.flows.registry.currentNode == undefined){
+            return; //Selecting Output ports without selecting node throws an exception
+          }
+          var ports = one.f.flows.registry.nodeports[one.f.flows.registry.currentNode]['ports'];
+          $select = one.lib.form.select.create(ports);
+          $select.attr('id', one.f.flows.id.modal.action.addOutputPorts);
+          $fieldset.append($label).append($select);
+          $label = one.lib.form.label('Queue (Optional)');
+          $input = one.lib.form.input('Queue')
+          .attr('id', one.f.flows.id.modal.action.queue);
+          $help = one.lib.form.help('Range: 1 - 2147483647');
+          $fieldset.append($label).append($input).append($help);
+          $form.append($fieldset);
+          return $form;
+        },
+        set : function(label, placeholder, id, help) {
+          var common = one.f.flows.modal.action.body.common();
+          var $form = common[0];
+          var $fieldset = common[1];
+          // input
+          $label = one.lib.form.label(label);
+          $input = one.lib.form.input(placeholder);
+          $input.attr('id', id);
+          $help = one.lib.form.help(help);
+          // append
+          $fieldset.append($label).append($input).append($help);
+          $form.append($fieldset);
+          return $form;
+        }
+      },
+      footer : function() {
+        var footer = [];
+        var addButton = one.lib.dashlet.button.single("Add Action", one.f.flows.id.modal.action.add, "btn-primary", "");
+        var $addButton = one.lib.dashlet.button.button(addButton);
+        footer.push($addButton);
+
+        var closeButton = one.lib.dashlet.button.single("Close", one.f.flows.id.modal.action.close, "", "");
+        var $closeButton = one.lib.dashlet.button.button(closeButton);
+        footer.push($closeButton);
+
+        return footer;
+      }
+    },
+    footer : function() {
+      var footer = [];
 
-            // layer 4
-            var $legend = one.lib.form.legend("Layer 4");
-            $fieldset.append($legend);
-            // srcPort
-            var $label = one.lib.form.label("Source Port");
-            var $input = one.lib.form.input("Source Port");
-            $input.attr('id', one.f.flows.id.modal.form.srcPort);
-            var $help = one.lib.form.help("Range: 0 - 65535");
-            $fieldset.append($label).append($input).append($help);
-            if(edit) {
-                $input.val(existingFlow.srcPort);
-            }
-            // dstPort
-            var $label = one.lib.form.label("Destination Port");
-            var $input = one.lib.form.input("Destination Port");
-            $input.attr('id', one.f.flows.id.modal.form.dstPort);
-            var $help = one.lib.form.help("Range: 0 - 65535");
-            $fieldset.append($label).append($input).append($help);
-            if(edit) {
-                $input.val(existingFlow.dstPort);
-            }
-            // protocol
-            var $label = one.lib.form.label("Protocol");
-            var $input = one.lib.form.input("Protocol");
-            $input.attr('id', one.f.flows.id.modal.form.protocol);
-            $fieldset.append($label).append($input);
-            if(edit) {
-                $input.val(existingFlow.protocol);
-            }
-            // actions
-            var $legend = one.lib.form.label("Actions");
-            $fieldset.append($legend);
-            // actions table
-            var tableAttributes = ["table-striped", "table-bordered", "table-condensed", "table-hover", "table-cursor"];
-            var $table = one.lib.dashlet.table.table(tableAttributes);
-            $table.attr('id', one.f.flows.id.modal.action.table);
-            var tableHeaders = ["Action", "Data"];
-            var $thead = one.lib.dashlet.table.header(tableHeaders);
-            var $tbody = one.lib.dashlet.table.body("", tableHeaders);
-            $table.append($thead).append($tbody);
-            // actions
-            var actions = {
-                "" : "Please Select an Action",
-                "DROP" : "Drop",
-                "LOOPBACK" : "Loopback",
-                "FLOOD" : "Flood",
-                "SW_PATH" : "Software Path",
-                "HW_PATH" : "Hardware Path",
-                "CONTROLLER" : "Controller",
-                "OUTPUT" : "Add Output Ports",
-                "SET_VLAN_ID" : "Set VLAN ID",
-                "SET_VLAN_PCP" : "Set VLAN Priority",
-                "POP_VLAN" : "Strip VLAN Header",
-                "SET_DL_SRC" : "Modify Datalayer Source Address",
-                "SET_DL_DST" : "Modify Datalayer Destination Address",
-                "SET_NW_SRC" : "Modify Network Source Address",
-                "SET_NW_DST" :"Modify Network Destination Address",
-                "SET_NW_TOS" : "Modify ToS Bits",
-                "SET_TP_SRC" : "Modify Transport Source Port",
-                "SET_TP_DST" : "Modify Transport Destination Port"
-            };
-            var $select = one.lib.form.select.create(actions);
-            // when selecting an action
-            $select.change(function() {
-                var action = $(this).find('option:selected');
-                one.f.flows.modal.action.parse(action.attr('value'));
-                $select[0].selectedIndex = 0;
-            });
+      var installButton = one.lib.dashlet.button.single("Install Flow", one.f.flows.id.modal.install, "btn-success", "");
+      var $installButton = one.lib.dashlet.button.button(installButton);
+      footer.push($installButton);
 
-            if(edit) {
-                $(existingFlow.actions).each(function(index, value){
-                    setTimeout(function(){
-                        var locEqualTo = value.indexOf("=");
-                        if ( locEqualTo == -1 ) {
-                            one.f.flows.modal.action.add.add(actions[value], value);
-                        } else {
-                            var action = value.substr(0,locEqualTo);
-                            if( action == "OUTPUT") {
-                                var portIds = value.substr(locEqualTo+1).split(",");
-                                var ports = [];
-                                var allPorts = one.f.flows.registry.nodeports[one.f.flows.registry.currentNode]['ports'];
-                                for(var i =0; i < portIds.length ; i++) {
-                                    var portName = allPorts[portIds[i]];
-                                    ports.push(portName);
-                                }
-                                one.f.flows.modal.action.add.addPortsToTable(ports.join(", "), portIds.join(","));
-                            } else {
-                                var val = value.substr(locEqualTo+1);
-                                one.f.flows.modal.action.add.addDataToTable(actions[action], val, action)
-                            }
-                        }
-                    }, 1000)
-                });
-            }
-            $fieldset.append($select).append($table);
+      var addButton = one.lib.dashlet.button.single("Save Flow", one.f.flows.id.modal.add, "btn-primary", "");
+      var $addButton = one.lib.dashlet.button.button(addButton);
+      footer.push($addButton);
 
-            // return
-            $form.append($fieldset);
-            return $form;
-        },
-        action : {
-            parse : function(option) {
-                switch (option) {
-                    case "OUTPUT" :
-                        var h3 = "Add Output Port";
-                        var $modal = one.f.flows.modal.action.initialize(h3, one.f.flows.modal.action.body.addOutputPorts, one.f.flows.modal.action.add.addOutputPorts);
-                        $modal.modal();
-                        break;
-                    case "SET_VLAN_ID" :
-                        var h3 = "Set VLAN ID";
-                        var placeholder = "VLAN Identification Number";
-                        var id = one.f.flows.id.modal.action.setVlanId;
-                        var help = "Range: 0 - 4095";
-                        var action = 'SET_VLAN_ID';
-                        var name = "VLAN ID";
-                        var body = function() {
-                            return one.f.flows.modal.action.body.set(h3, placeholder, id, help);
-                        };
-                        var add = function($modal) {
-                            one.f.flows.modal.action.add.set(name, id, action, $modal);
-                        };
-                        var $modal = one.f.flows.modal.action.initialize(h3, body, add);
-                        $modal.modal();
-                        break;
-                    case "SET_VLAN_PCP" :
-                        var h3 = "Set VLAN Priority";
-                        var placeholder = "VLAN Priority";
-                        var id = one.f.flows.id.modal.action.setVlanPriority;
-                        var help = "Range: 0 - 7";
-                        var action = 'SET_VLAN_PCP';
-                        var name = "VLAN Priority";
-                        var body = function() {
-                            return one.f.flows.modal.action.body.set(h3, placeholder, id, help);
-                        };
-                        var add = function($modal) {
-                            one.f.flows.modal.action.add.set(name, id, action, $modal);
-                        };
-                        var $modal = one.f.flows.modal.action.initialize(h3, body, add);
-                        $modal.modal();
-                        break;
-                    case "POP_VLAN" :
-                        var name = "Strip VLAN Header";
-                        var action = 'POP_VLAN';
-                        one.f.flows.modal.action.add.add(name, action);
-                        break;
-                    case "SET_DL_SRC" :
-                        var h3 = "Set Source MAC Address";
-                        var placeholder = "Source MAC Address";
-                        var id = one.f.flows.id.modal.action.modifyDatalayerSourceAddress;
-                        var help = "Example: 00:11:22:aa:bb:cc";
-                        var action = 'SET_DL_SRC';
-                        var name = "Source MAC";
-                        var body = function() {
-                            return one.f.flows.modal.action.body.set(h3, placeholder, id, help);
-                        };
-                        var add = function($modal) {
-                            one.f.flows.modal.action.add.set(name, id, action, $modal);
-                        };
-                        var $modal = one.f.flows.modal.action.initialize(h3, body, add);
-                        $modal.modal();
-                        break;
-                    case "SET_DL_DST" :
-                        var h3 = "Set Destination MAC Address";
-                        var placeholder = "Destination MAC Address";
-                        var id = one.f.flows.id.modal.action.modifyDatalayerDestinationAddress;
-                        var help = "Example: 00:11:22:aa:bb:cc";
-                        var action = 'SET_DL_DST';
-                        var name = "Destination MAC";
-                        var body = function() {
-                            return one.f.flows.modal.action.body.set(h3, placeholder, id, help);
-                        };
-                        var add = function($modal) {
-                            one.f.flows.modal.action.add.set(name, id, action, $modal);
-                        };
-                        var $modal = one.f.flows.modal.action.initialize(h3, body, add);
-                        $modal.modal();
-                        break;
-                    case "SET_NW_SRC" :
-                        var h3 = "Set IP Source Address";
-                        var placeholder = "Source IP Address";
-                        var id = one.f.flows.id.modal.action.modifyNetworkSourceAddress;
-                        var help = "Example: 127.0.0.1";
-                        var action = 'SET_NW_SRC';
-                        var name = "Source IP";
-                        var body = function() {
-                            return one.f.flows.modal.action.body.set(h3, placeholder, id, help);
-                        };
-                        var add = function($modal) {
-                            one.f.flows.modal.action.add.set(name, id, action, $modal);
-                        };
-                        var $modal = one.f.flows.modal.action.initialize(h3, body, add);
-                        $modal.modal();
-                        break;
-                    case "SET_NW_DST" :
-                        var h3 = "Set IP Destination Address";
-                        var placeholder = "Destination IP Address";
-                        var id = one.f.flows.id.modal.action.modifyNetworkDestinationAddress;
-                        var help = "Example: 127.0.0.1";
-                        var action = 'SET_NW_DST';
-                        var name = "Destination IP";
-                        var body = function() {
-                            return one.f.flows.modal.action.body.set(h3, placeholder, id, help);
-                        };
-                        var add = function($modal) {
-                            one.f.flows.modal.action.add.set(name, id, action, $modal);
-                        };
-                        var $modal = one.f.flows.modal.action.initialize(h3, body, add);
-                        $modal.modal();
-                        break;
-                    case "SET_NW_TOS" :
-                        var h3 = "Set IPv4 ToS";
-                        var placeholder = "IPv4 ToS";
-                        var id = one.f.flows.id.modal.action.modifyTosBits;
-                        var help = "Range: 0 - 63";
-                        var action = 'SET_NW_TOS';
-                        var name = "ToS Bits";
-                        var body = function() {
-                            return one.f.flows.modal.action.body.set(h3, placeholder, id, help);
-                        };
-                        var add = function($modal) {
-                            one.f.flows.modal.action.add.set(name, id, action, $modal);
-                        };
-                        var $modal = one.f.flows.modal.action.initialize(h3, body, add);
-                        $modal.modal();
-                        break;
-                    case "SET_TP_SRC" :
-                        var h3 = "Set Transport Source Port";
-                        var placeholder = "Transport Source Port";
-                        var id = one.f.flows.id.modal.action.modifyTransportSourcePort;
-                        var help = "Range: 1 - 65535";
-                        var action = 'SET_TP_SRC';
-                        var name = "Source Port";
-                        var body = function() {
-                            return one.f.flows.modal.action.body.set(h3, placeholder, id, help);
-                        };
-                        var add = function($modal) {
-                            one.f.flows.modal.action.add.set(name, id, action, $modal);
-                        };
-                        var $modal = one.f.flows.modal.action.initialize(h3, body, add);
-                        $modal.modal();
-                        break;
-                    case "SET_TP_DST" :
-                        var h3 = "Set Transport Destination Port";
-                        var placeholder = "Transport Destination Port";
-                        var id = one.f.flows.id.modal.action.modifyTransportDestinationPort;
-                        var help = "Range: 1 - 65535";
-                        var action = 'SET_TP_DST';
-                        var name = "Destination Port";
-                        var body = function() {
-                            return one.f.flows.modal.action.body.set(h3, placeholder, id, help);
-                        };
-                        var add = function($modal) {
-                            one.f.flows.modal.action.add.set(name, id, action, $modal);
-                        };
-                        var $modal = one.f.flows.modal.action.initialize(h3, body, add);
-                        $modal.modal();
-                        break;
-                    case "DROP" :
-                        var name = "Drop";
-                        var action = 'DROP';
-                        one.f.flows.modal.action.add.add(name, action);
-                        break;
-                    case "LOOPBACK" :
-                        var name = "Loopback";
-                        var action = 'LOOPBACK';
-                        one.f.flows.modal.action.add.add(name, action);
-                        break;
-                    case "FLOOD" :
-                        var name = "Flood";
-                        var action = 'FLOOD';
-                        one.f.flows.modal.action.add.add(name, action);
-                        break;
-                    case "SW_PATH" :
-                        var name = "Software Path";
-                        var action = 'SW_PATH';
-                        one.f.flows.modal.action.add.add(name, action);
-                        break;
-                    case "HW_PATH" :
-                        var name = "Hardware Path";
-                        var action = 'HW_PATH';
-                        one.f.flows.modal.action.add.add(name, action);
-                        break;
-                    case "CONTROLLER" :
-                        var name = "Controller";
-                        var action = 'CONTROLLER';
-                        one.f.flows.modal.action.add.add(name, action);
-                        break;
-                }
-            },
-            initialize : function(h3, bodyCallback, addCallback) {
-                var footer = one.f.flows.modal.action.footer();
-                var $body = bodyCallback();
-                var $modal = one.lib.modal.spawn(one.f.flows.id.modal.action.modal, h3, $body, footer);
-                // bind close button
-                $('#'+one.f.flows.id.modal.action.close, $modal).click(function() {
-                    $modal.modal('hide');
-                });
-                // bind add flow button
-                $('#'+one.f.flows.id.modal.action.add, $modal).click(function() {
-                    addCallback($modal);
-                });
-                return $modal;
-            },
-            add : {
-                addOutputPorts : function($modal) {
-                    var $options = $('#'+one.f.flows.id.modal.action.addOutputPorts).find('option:selected');
-                    var ports = '';
-                    var pid = '';
-                    $options.each(function(index, value) {
-                        ports = ports+$(value).text()+", ";
-                        pid = pid+$(value).attr('value')+",";
-                    });
-                    ports = ports.slice(0,-2);
-                    pid = pid.slice(0,-1);
-                    one.f.flows.modal.action.add.addPortsToTable(ports, pid);
-                    $modal.modal('hide');
-                },
-                addPortsToTable : function(ports, pid){
-                    var $tr = one.f.flows.modal.action.table.add("Add Output Ports", ports);
-                    $tr.attr('id', 'OUTPUT');
-                    $tr.data('action', 'OUTPUT='+pid);
-                    $tr.click(function() {
-                        one.f.flows.modal.action.add.modal.initialize(this);
-                    });
-                    one.f.flows.modal.action.table.append($tr);
-                },
-                add : function(name, action) {
-                    var $tr = one.f.flows.modal.action.table.add(name);
-                    $tr.attr('id', action);
-                    $tr.data('action', action);
-                    $tr.click(function() {
-                        one.f.flows.modal.action.add.modal.initialize(this);
-                    });
-                    one.f.flows.modal.action.table.append($tr);
-                },
-                set : function(name, id, action, $modal) {
-                    var $input = $('#'+id);
-                    var value = $input.val();
-                    one.f.flows.modal.action.add.addDataToTable(name,value,action)
-                    $modal.modal('hide');
-                },
-                addDataToTable : function(name,value,action) {
-                    var $tr = one.f.flows.modal.action.table.add(name, value);
-                    $tr.attr('id', action);
-                    $tr.data('action', action+'='+value);
-                    $tr.click(function() {
-                        one.f.flows.modal.action.add.modal.initialize(this);
-                    });
-                    one.f.flows.modal.action.table.append($tr);
-                },
-                remove : function(that) {
-                    $(that).remove();
-                    var $table = $('#'+one.f.flows.id.modal.action.table);
-                    if ($table.find('tbody').find('tr').size() == 0) {
-                        var $tr = $(document.createElement('tr'));
-                        var $td = $(document.createElement('td'));
-                        $td.attr('colspan', '3');
-                        $tr.addClass('empty');
-                        $td.text('No data available');
-                        $tr.append($td);
-                        $table.find('tbody').append($tr);
-                    }
-                },
-                modal : {
-                    initialize : function(that) {
-                        var h3 = "Remove Action";
-                        var footer = one.f.flows.modal.action.add.modal.footer();
-                        var $body = one.f.flows.modal.action.add.modal.body();
-                        var $modal = one.lib.modal.spawn(one.f.flows.id.modal.action.modal.modal, h3, $body, footer);
-
-                        // bind cancel button
-                        $('#'+one.f.flows.id.modal.action.modal.cancel, $modal).click(function() {
-                            $modal.modal('hide');
-                        });
-
-                        // bind remove button
-                        $('#'+one.f.flows.id.modal.action.modal.remove, $modal).click(function() {
-                            one.f.flows.modal.action.add.remove(that);
-                            $modal.modal('hide');
-                        });
-
-                        $modal.modal();
-                    },
-                    body : function() {
-                        var $p = $(document.createElement('p'));
-                        $p.append("Remove this action?");
-                        return $p;
-                    },
-                    footer : function() {
-                        var footer = [];
-
-                        var removeButton = one.lib.dashlet.button.single("Remove Action", one.f.flows.id.modal.action.modal.remove, "btn-danger", "");
-                        var $removeButton = one.lib.dashlet.button.button(removeButton);
-                        footer.push($removeButton);
-
-                        var cancelButton = one.lib.dashlet.button.single("Cancel", one.f.flows.id.modal.action.modal.cancel, "", "");
-                        var $cancelButton = one.lib.dashlet.button.button(cancelButton);
-                        footer.push($cancelButton);
-
-                        return footer;
-                    }
-                }
-            },
-            table : {
-                add : function(action, data) {
-                    var $tr = $(document.createElement('tr'));
-                    var $td = $(document.createElement('td'));
-                    $td.append(action);
-                    $tr.append($td);
-                    var $td = $(document.createElement('td'));
-                    if (data != undefined) $td.append(data);
-                    $tr.append($td);
-                    return $tr;
-                },
-                append : function($tr) {
-                    var $table = $('#'+one.f.flows.id.modal.action.table);
-                    var $empty = $table.find('.empty').parent();
-                    if ($empty.size() > 0) $empty.remove();
-                    $table.append($tr);
-                }
-            },
-            body : {
-                common : function() {
-                    var $form = $(document.createElement('form'));
-                    var $fieldset = $(document.createElement('fieldset'));
-                    return [$form, $fieldset];
-                },
-                addOutputPorts : function() {
-                    var common = one.f.flows.modal.action.body.common();
-                    var $form = common[0];
-                    var $fieldset = common[1];
-                    // output port
-                    $label = one.lib.form.label("Select Output Ports");
-                    if (one.f.flows.registry.currentNode == undefined){
-                        return; //Selecting Output ports without selecting node throws an exception
-                    }
-                    var ports = one.f.flows.registry.nodeports[one.f.flows.registry.currentNode]['ports'];
-                    $select = one.lib.form.select.create(ports, true);
-                    $select.attr('id', one.f.flows.id.modal.action.addOutputPorts);
-                    $fieldset.append($label).append($select);
-                    $form.append($fieldset);
-                    return $form;
-                },
-                set : function(label, placeholder, id, help) {
-                    var common = one.f.flows.modal.action.body.common();
-                    var $form = common[0];
-                    var $fieldset = common[1];
-                    // input
-                    $label = one.lib.form.label(label);
-                    $input = one.lib.form.input(placeholder);
-                    $input.attr('id', id);
-                    $help = one.lib.form.help(help);
-                    // append
-                    $fieldset.append($label).append($input).append($help);
-                    $form.append($fieldset);
-                    return $form;
-                }
-            },
-            footer : function() {
-                var footer = [];
-                var addButton = one.lib.dashlet.button.single("Add Action", one.f.flows.id.modal.action.add, "btn-primary", "");
-                var $addButton = one.lib.dashlet.button.button(addButton);
-                footer.push($addButton);
-
-                var closeButton = one.lib.dashlet.button.single("Close", one.f.flows.id.modal.action.close, "", "");
-                var $closeButton = one.lib.dashlet.button.button(closeButton);
-                footer.push($closeButton);
-
-                return footer;
-            }
-        },
-        footer : function() {
-            var footer = [];
+      var closeButton = one.lib.dashlet.button.single("Close", one.f.flows.id.modal.close, "", "");
+      var $closeButton = one.lib.dashlet.button.button(closeButton);
+      footer.push($closeButton);
 
-            var installButton = one.lib.dashlet.button.single("Install Flow", one.f.flows.id.modal.install, "btn-success", "");
-            var $installButton = one.lib.dashlet.button.button(installButton);
-            footer.push($installButton);
+      return footer;
+    },
+    footerEdit : function() {
+      var footer = [];
 
-            var addButton = one.lib.dashlet.button.single("Save Flow", one.f.flows.id.modal.add, "btn-primary", "");
-            var $addButton = one.lib.dashlet.button.button(addButton);
-            footer.push($addButton);
+      var editButton = one.lib.dashlet.button.single("Save Flow", one.f.flows.id.modal.edit, "btn-success", "");
+      var $editButton = one.lib.dashlet.button.button(editButton);
+      footer.push($editButton);
 
-            var closeButton = one.lib.dashlet.button.single("Close", one.f.flows.id.modal.close, "", "");
-            var $closeButton = one.lib.dashlet.button.button(closeButton);
-            footer.push($closeButton);
+      var closeButton = one.lib.dashlet.button.single("Close", one.f.flows.id.modal.close, "", "");
+      var $closeButton = one.lib.dashlet.button.button(closeButton);
+      footer.push($closeButton);
 
-            return footer;
-        },
-        footerEdit : function() {
-            var footer = [];
+      return footer;
+    },
+    removeMultiple: {
+      dialog: function(flows) {
+        var h3 = 'Remove Flow Entry';
+        var flowList = [];
+        for (var i = 0; i < flows.length; i++) {
+          flowList.push(flows[i]["name"]);
+        }
+        var footer = one.f.flows.modal.removeMultiple.footer();
+        var $body = one.f.flows.modal.removeMultiple.body(flowList);
+        var $modal = one.lib.modal.spawn(one.f.flows.id.modal.dialog.modal, h3, $body, footer);
 
-            var editButton = one.lib.dashlet.button.single("Save Flow", one.f.flows.id.modal.edit, "btn-success", "");
-            var $editButton = one.lib.dashlet.button.button(editButton);
-            footer.push($editButton);
+        // bind close button
+        $('#'+one.f.flows.id.modal.dialog.close, $modal).click(function() {
+          $modal.modal('hide');
+        });
 
-            var closeButton = one.lib.dashlet.button.single("Close", one.f.flows.id.modal.close, "", "");
-            var $closeButton = one.lib.dashlet.button.button(closeButton);
-            footer.push($closeButton);
+        // bind remove rule button
+        $('#'+one.f.flows.id.modal.dialog.remove, $modal).click(this, function(e) {
+          var resource = {};
+          resource['body'] = JSON.stringify(flows);
 
-            return footer;
-        },
-        removeMultiple: {
-            dialog: function(flows) {
-                var h3 = 'Remove Flow Entry';
-                var flowList = [];
-                for (var i = 0; i < flows.length; i++) {
-                    flowList.push(flows[i]["name"]);
-                }
-                var footer = one.f.flows.modal.removeMultiple.footer();
-                var $body = one.f.flows.modal.removeMultiple.body(flowList);
-                var $modal = one.lib.modal.spawn(one.f.flows.id.modal.dialog.modal, h3, $body, footer);
-
-                // bind close button
-                $('#'+one.f.flows.id.modal.dialog.close, $modal).click(function() {
-                    $modal.modal('hide');
-                });
-
-                // bind remove rule button
-                $('#'+one.f.flows.id.modal.dialog.remove, $modal).click(this, function(e) {
-                    var resource = {};
-                    resource['body'] = JSON.stringify(flows);
-
-                    $.post(one.f.address.root+one.f.address.flows.deleteFlows, resource, function(response) {
-                        $modal.modal('hide');
-                        if(response == "Success") {
-                            one.lib.alert("Flow Entry(s) successfully removed");
-                        } else {
-                            one.lib.alert(response);
-                        }
-                        one.main.dashlet.right.bottom.empty();
-                        one.f.detail.dashlet(one.main.dashlet.right.bottom);
-                        one.main.dashlet.left.top.empty();
-                        one.f.flows.dashlet(one.main.dashlet.left.top);
-                    });
-                });
-                $modal.modal();
-            },
-            footer : function() {
-                var footer = [];
-                var remove = one.lib.dashlet.button.single('Remove Flow Entry',one.f.flows.id.modal.dialog.remove, 'btn-danger', '');
-                var $remove = one.lib.dashlet.button.button(remove);
-                footer.push($remove);
-
-                var cancel = one.lib.dashlet.button.single('Cancel', one.f.flows.id.modal.dialog.close, '', '');
-                var $cancel = one.lib.dashlet.button.button(cancel);
-                footer.push($cancel);
-
-                return footer;
-            },
-            body : function (flows) {
-                var $p = $(document.createElement('p'));
-                var p = 'Remove the following Flow Entry(s)?';
-                //creata a BS label for each rule and append to list
-                $(flows).each(function(){
-                    var $span = $(document.createElement('span'));
-                    $span.append(this);
-                    p += '<br/>' + $span[0].outerHTML;
-                });
-                $p.append(p);
-                return $p;
+          $.post(one.f.address.root+one.f.address.flows.deleteFlows, resource, function(response) {
+            $modal.modal('hide');
+            if(response == "Success") {
+              one.lib.alert("Flow Entry(s) successfully removed");
+            } else {
+              one.lib.alert(response);
             }
-        }
-    },
-    ajax : {
-        dashlet : function(callback) {
-            $.getJSON(one.f.address.root+one.f.address.flows.main, function(data) {
-                one.f.flows.registry['flows'] = data.flows;
-                one.f.flows.registry['privilege'] = data.privilege;
-                one.f.flows.modal.ajax.nodes(function(){/*Empty function. Do nothing. */})
+            one.main.dashlet.right.bottom.empty();
+            one.f.detail.dashlet(one.main.dashlet.right.bottom);
+            one.main.dashlet.left.top.empty();
+            one.f.flows.dashlet(one.main.dashlet.left.top);
+          });
+        });
+        $modal.modal();
+      },
+      footer : function() {
+        var footer = [];
+        var remove = one.lib.dashlet.button.single('Remove Flow Entry',one.f.flows.id.modal.dialog.remove, 'btn-danger', '');
+        var $remove = one.lib.dashlet.button.button(remove);
+        footer.push($remove);
+
+        var cancel = one.lib.dashlet.button.single('Cancel', one.f.flows.id.modal.dialog.close, '', '');
+        var $cancel = one.lib.dashlet.button.button(cancel);
+        footer.push($cancel);
+
+        return footer;
+      },
+      body : function (flows) {
+        var $p = $(document.createElement('p'));
+        var p = 'Remove the following Flow Entry(s)?';
+        //creata a BS label for each rule and append to list
+        $(flows).each(function(){
+          var $span = $(document.createElement('span'));
+          $span.append(this);
+          p += '<br/>' + $span[0].outerHTML;
+        });
+        $p.append(p);
+        return $p;
+      }
+    }
+  },
+  ajax : {
+    dashlet : function(callback) {
+      $.getJSON(one.f.address.root+one.f.address.flows.main, function(data) {
+        one.f.flows.registry['flows'] = data.flows;
+        one.f.flows.registry['privilege'] = data.privilege;
+        one.f.flows.modal.ajax.nodes(function(){/*Empty function. Do nothing. */})
+
+        callback(data);
+      });
+    }
+  },
+  data : {
+    flowsDataGrid: function(data) {
+      var source = new StaticDataSource({
+        columns: [
+      {
+        property: 'selector',
+      label: "<input type='checkbox' id='"+one.f.flows.id.dashlet.datagrid.selectAllFlows+"'/>",
+      sortable: false
+      },
+      {
+        property: 'name',
+      label: 'Flow Name',
+      sortable: true
+      },
+      {
+        property: 'node',
+      label: 'Node',
+      sortable: true
+      }
+      ],
+      data: data.flows,
+      formatter: function(items) {
+        $.each(items, function(index, item) {
+          var $checkbox = document.createElement("input");
+          $checkbox.setAttribute("type", "checkbox");
+          $checkbox.setAttribute("name", item.name);
+          $checkbox.setAttribute("node", item.nodeId);
+          $checkbox.setAttribute('class','flowEntry')
+          item.selector = $checkbox.outerHTML;
+        item["name"] = '<span data-installInHw=' + item["flow"]["installInHw"] + 
+          ' data-flowstatus=' + item["flow"]["status"] + 
+          ' data-nodeId=' + item["nodeId"] + '>' + item["name"] + '</span>';
+        });
 
-                callback(data);
-            });
-        }
-    },
-    data : {
-        flowsDataGrid: function(data) {
-            var source = new StaticDataSource({
-                    columns: [
-                        {
-                            property: 'selector',
-                            label: "<input type='checkbox' id='"+one.f.flows.id.dashlet.datagrid.selectAllFlows+"'/>",
-                            sortable: false
-                        },
-                        {
-                            property: 'name',
-                            label: 'Flow Name',
-                            sortable: true
-                        },
-                        {
-                            property: 'node',
-                            label: 'Node',
-                            sortable: true
-                        }
-                    ],
-                    data: data.flows,
-                    formatter: function(items) {
-                        $.each(items, function(index, item) {
-                            var $checkbox = document.createElement("input");
-                            $checkbox.setAttribute("type", "checkbox");
-                            $checkbox.setAttribute("name", item.name);
-                            $checkbox.setAttribute("node", item.nodeId);
-                            $checkbox.setAttribute('class','flowEntry')
-                            item.selector = $checkbox.outerHTML;
-                                  item["name"] = '<span data-installInHw=' + item["flow"]["installInHw"] + 
-                                ' data-flowstatus=' + item["flow"]["status"] + 
-                                ' data-nodeId=' + item["nodeId"] + '>' + item["name"] + '</span>';
-                        });
-
-                    },
-                    delay: 0
-                });
-            return source;
-        },
-        dashlet : function(data) {
-            var body = [];
-            $(data).each(function(index, value) {
-                var tr = {};
-                var entry = [];
-
-                
-                entry.push(value['name']);
-                entry.push(value['node']);
-                if (value['flow']['installInHw'] == 'true' && value['flow']['status'] == 'Success')
-                    tr['type'] = ['success'];
-                else if (value['flow']['installInHw'] == 'false' && value['flow']['status'] == 'Success')
-                    tr['type'] = ['warning'];
-                else 
-                    tr['type'] = ['warning'];
-                tr['entry'] = entry;
-                tr['id'] = value['nodeId'];
-
-                body.push(tr);
-            });
-            return body;
-        }
+      },
+      delay: 0
+      });
+      return source;
     },
-    body : {
-        dashlet : function(body, callback) {
-            var attributes = ['table-striped', 'table-bordered', 'table-hover', 'table-condensed', 'table-cursor'];
-            var $table = one.lib.dashlet.table.table(attributes);
-
-            var headers = ['Flow Name', 'Node'];
-                
-            var $thead = one.lib.dashlet.table.header(headers);
-            $table.append($thead);
-
-            var $tbody = one.lib.dashlet.table.body(body);
-            $table.append($tbody);
-            return $table;
-        }
+    dashlet : function(data) {
+      var body = [];
+      $(data).each(function(index, value) {
+        var tr = {};
+        var entry = [];
+
+
+        entry.push(value['name']);
+        entry.push(value['node']);
+        if (value['flow']['installInHw'] == 'true' && value['flow']['status'] == 'Success')
+        tr['type'] = ['success'];
+        else if (value['flow']['installInHw'] == 'false' && value['flow']['status'] == 'Success')
+        tr['type'] = ['warning'];
+        else 
+        tr['type'] = ['warning'];
+      tr['entry'] = entry;
+      tr['id'] = value['nodeId'];
+
+      body.push(tr);
+      });
+      return body;
     }
+  },
+  body : {
+    dashlet : function(body, callback) {
+      var attributes = ['table-striped', 'table-bordered', 'table-hover', 'table-condensed', 'table-cursor'];
+      var $table = one.lib.dashlet.table.table(attributes);
+
+      var headers = ['Flow Name', 'Node'];
+
+      var $thead = one.lib.dashlet.table.header(headers);
+      $table.append($thead);
+
+      var $tbody = one.lib.dashlet.table.body(body);
+      $table.append($tbody);
+      return $table;
+    }
+  }
 }
 
 /** INIT **/
 // populate nav tabs
 $(one.f.menu.left.top).each(function(index, value) {
-    var $nav = $(".nav", "#left-top");
-    one.main.page.dashlet($nav, value);
+  var $nav = $(".nav", "#left-top");
+  one.main.page.dashlet($nav, value);
 });
 
 $(one.f.menu.left.bottom).each(function(index, value) {
-    var $nav = $(".nav", "#left-bottom");
-    one.main.page.dashlet($nav, value);
+  var $nav = $(".nav", "#left-bottom");
+  one.main.page.dashlet($nav, value);
 });
 
 $(one.f.menu.right.bottom).each(function(index, value) {
-    var $nav = $(".nav", "#right-bottom");
-    one.main.page.dashlet($nav, value);
+  var $nav = $(".nav", "#right-bottom");
+  one.main.page.dashlet($nav, value);
 });
 
 one.f.populate = function($dashlet, header) {
-    var $h4 = one.lib.dashlet.header(header);
-    $dashlet.append($h4);
+  var $h4 = one.lib.dashlet.header(header);
+  $dashlet.append($h4);
 };
 
 // bind dashlet nav
 $('.dash .nav a', '#main').click(function() {
-    // de/activation
-    var $li = $(this).parent();
-    var $ul = $li.parent();
-    one.lib.nav.unfocus($ul);
-    $li.addClass('active');
-    // clear respective dashlet
-    var $dashlet = $ul.parent().find('.dashlet');
-    one.lib.dashlet.empty($dashlet);
-    // callback based on menu
-    var id = $(this).attr('id');
-    var menu = one.f.dashlet;
-    switch (id) {
-        case menu.flows.id:
-            one.f.flows.dashlet($dashlet);
-            break;
-        case menu.nodes.id:
-            one.f.nodes.dashlet($dashlet);
-            break;
-        case menu.detail.id:
-            one.f.detail.dashlet($dashlet);
-            break;
-    };
+  // de/activation
+  var $li = $(this).parent();
+  var $ul = $li.parent();
+  one.lib.nav.unfocus($ul);
+  $li.addClass('active');
+  // clear respective dashlet
+  var $dashlet = $ul.parent().find('.dashlet');
+  one.lib.dashlet.empty($dashlet);
+  // callback based on menu
+  var id = $(this).attr('id');
+  var menu = one.f.dashlet;
+  switch (id) {
+    case menu.flows.id:
+      one.f.flows.dashlet($dashlet);
+      break;
+    case menu.nodes.id:
+      one.f.nodes.dashlet($dashlet);
+      break;
+    case menu.detail.id:
+      one.f.detail.dashlet($dashlet);
+      break;
+  };
 });
 
 // activate first tab on each dashlet
 $('.dash .nav').each(function(index, value) {
-    $($(value).find('li')[0]).find('a').click();
+  $($(value).find('li')[0]).find('a').click();
 });