Merge branch 'master' of https://github.com/OPENNETWORKINGLAB/ONOS
diff --git a/pom.xml b/pom.xml
index 52fe30a..44b7f07 100644
--- a/pom.xml
+++ b/pom.xml
@@ -121,6 +121,30 @@
           <locale>en</locale>
         </configuration>
       </plugin>
+      <plugin>
+        <groupId>org.jacoco</groupId>
+        <artifactId>jacoco-maven-plugin</artifactId>
+        <version>0.6.3.201306030806</version>
+        <configuration>
+          <destfile>${basedir}/target/jacoco/jacoco.exec</destfile>
+          <datafile>${basedir}/target/jacoco/jacoco.exec</datafile>
+        </configuration>
+        <executions>
+          <execution>
+            <id>jacoco-initialize</id>
+            <goals>
+              <goal>prepare-agent</goal>
+            </goals>
+          </execution>
+          <execution>
+            <id>jacoco-site</id>
+            <phase>package</phase>
+            <goals>
+              <goal>report</goal>
+            </goals>
+          </execution>
+        </executions>
+      </plugin>
     </plugins>
   </build>
   <!-- for getting visualization reporting   -->
@@ -145,6 +169,7 @@
           <reportSet>
             <reports>
               <report>dependencies</report>
+              <report>maven-emma-plugin</report>
               <report>scm</report>
             </reports>
           </reportSet>
diff --git a/src/main/java/net/onrc/onos/flow/FlowManagerImpl.java b/src/main/java/net/onrc/onos/flow/FlowManagerImpl.java
index 1f041e6..2e2706c 100644
--- a/src/main/java/net/onrc/onos/flow/FlowManagerImpl.java
+++ b/src/main/java/net/onrc/onos/flow/FlowManagerImpl.java
@@ -28,6 +28,7 @@
 import net.onrc.onos.ofcontroller.util.Dpid;
 import net.onrc.onos.ofcontroller.util.FlowEntry;
 import net.onrc.onos.ofcontroller.util.FlowEntryAction;
+import net.onrc.onos.ofcontroller.util.FlowEntryActions;
 import net.onrc.onos.ofcontroller.util.FlowEntryMatch;
 import net.onrc.onos.ofcontroller.util.FlowPath;
 import net.onrc.onos.ofcontroller.util.Port;
@@ -132,16 +133,12 @@
 		    flowEntry.setOutPort(new Port(src_port.getNumber()));
 		    flowEntry.setFlowEntryMatch(new FlowEntryMatch());
 		    flowEntry.flowEntryMatch().enableInPort(flowEntry.inPort());
-		    
+
 		    // Set the outgoing port output action
-		    ArrayList<FlowEntryAction> flowEntryActions = flowEntry.flowEntryActions();
-		    if (flowEntryActions == null) {
-			flowEntryActions = new ArrayList<FlowEntryAction>();
-			flowEntry.setFlowEntryActions(flowEntryActions);
-		    }
+		    FlowEntryActions flowEntryActions = flowEntry.flowEntryActions();
 		    FlowEntryAction flowEntryAction = new FlowEntryAction();
 		    flowEntryAction.setActionOutput(flowEntry.outPort());
-		    flowEntryActions.add(flowEntryAction);
+		    flowEntryActions.addAction(flowEntryAction);
 		    dataPath.flowEntries().add(flowEntry);
 		    
 		    FlowPath flowPath = new FlowPath();
@@ -254,14 +251,10 @@
 		    flowEntry.flowEntryMatch().enableInPort(flowEntry.inPort());
 		    
 		    // Set the outgoing port output action
-		    ArrayList<FlowEntryAction> flowEntryActions = flowEntry.flowEntryActions();
-		    if (flowEntryActions == null) {
-			flowEntryActions = new ArrayList<FlowEntryAction>();
-			flowEntry.setFlowEntryActions(flowEntryActions);
-		    }
+		    FlowEntryActions flowEntryActions = flowEntry.flowEntryActions();
 		    FlowEntryAction flowEntryAction = new FlowEntryAction();
 		    flowEntryAction.setActionOutput(flowEntry.outPort());
-		    flowEntryActions.add(flowEntryAction);
+		    flowEntryActions.addAction(flowEntryAction);
 		    dataPath.flowEntries().add(flowEntry);
 			continue;
 		    }
@@ -276,14 +269,10 @@
 		    flowEntry.flowEntryMatch().enableInPort(flowEntry.inPort());
 		    
 		    // Set the outgoing port output action
-		    ArrayList<FlowEntryAction> flowEntryActions = flowEntry.flowEntryActions();
-		    if (flowEntryActions == null) {
-			flowEntryActions = new ArrayList<FlowEntryAction>();
-			flowEntry.setFlowEntryActions(flowEntryActions);
-		    }
+		    FlowEntryActions flowEntryActions = flowEntry.flowEntryActions();
 		    FlowEntryAction flowEntryAction = new FlowEntryAction();
 		    flowEntryAction.setActionOutput(flowEntry.outPort());
-		    flowEntryActions.add(flowEntryAction);
+		    flowEntryActions.addAction(flowEntryAction);
 		    dataPath.flowEntries().add(flowEntry);
 		    dataPath.flowEntries().add(flowEntry);
 		}
diff --git a/src/main/java/net/onrc/onos/ofcontroller/core/INetMapTopologyObjects.java b/src/main/java/net/onrc/onos/ofcontroller/core/INetMapTopologyObjects.java
index 0d52171..9a96638 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/core/INetMapTopologyObjects.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/core/INetMapTopologyObjects.java
@@ -253,6 +253,9 @@
 		@Adjacency(label="flow", direction=Direction.IN)
 		public void removeFlowEntry(final IFlowEntry flowEntry);
 
+		//
+		// Matching fields
+		//
 		@JsonIgnore
 		@Property("matchSrcMac")
 		public String getMatchSrcMac();
@@ -330,6 +333,18 @@
 		@Property("matchDstTcpUdpPort")
 		public void setMatchDstTcpUdpPort(Short matchDstTcpUdpPort);
 
+		//
+		// Action-related fields
+		//
+		@Property("actions")
+		public String getActions();
+
+		@Property("actions")
+		public void setActions(String actionsStr);
+
+		//
+		// Other fields
+		//
 		@JsonIgnore
 		@GremlinGroovy("it.in('flow').out('switch')")
 		public Iterable<ISwitchObject> getSwitches();
@@ -383,6 +398,9 @@
 		@Property("error_state_code")
 		public void setErrorStateCode(String errorStateCode);
 
+		//
+		// Matching fields
+		//
 		@Property("matchInPort")
 		public Short getMatchInPort();
 
@@ -455,12 +473,24 @@
 		@Property("matchDstTcpUdpPort")
 		public void setMatchDstTcpUdpPort(Short matchDstTcpUdpPort);
 
+		//
+		// Action-related fields
+		//
 		@Property("actionOutputPort")
 		public Short getActionOutputPort();
 
 		@Property("actionOutputPort")
 		public void setActionOutputPort(Short actionOutputPort);
 
+		@Property("actions")
+		public String getActions();
+
+		@Property("actions")
+		public void setActions(String actionsStr);
+
+		//
+		// Other fields
+		//
 		@Adjacency(label="flow")
 		public IFlowPath getFlow();
 
diff --git a/src/main/java/net/onrc/onos/ofcontroller/flowmanager/FlowManager.java b/src/main/java/net/onrc/onos/ofcontroller/flowmanager/FlowManager.java
index 1784540..a072882 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/flowmanager/FlowManager.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/flowmanager/FlowManager.java
@@ -42,6 +42,8 @@
 import net.onrc.onos.ofcontroller.util.Dpid;
 import net.onrc.onos.ofcontroller.util.FlowEntry;
 import net.onrc.onos.ofcontroller.util.FlowEntryAction;
+import net.onrc.onos.ofcontroller.util.FlowEntryAction.*;
+import net.onrc.onos.ofcontroller.util.FlowEntryActions;
 import net.onrc.onos.ofcontroller.util.FlowEntryId;
 import net.onrc.onos.ofcontroller.util.FlowEntryMatch;
 import net.onrc.onos.ofcontroller.util.FlowEntrySwitchState;
@@ -58,8 +60,7 @@
 import org.openflow.protocol.OFPacketOut;
 import org.openflow.protocol.OFPort;
 import org.openflow.protocol.OFType;
-import org.openflow.protocol.action.OFAction;
-import org.openflow.protocol.action.OFActionOutput;
+import org.openflow.protocol.action.*;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -587,6 +588,7 @@
 	// - flowPath.matchIpToS()
 	// - flowPath.matchSrcTcpUdpPort()
 	// - flowPath.matchDstTcpUdpPort()
+	// - flowPath.flowEntryActions()
 	//
 	flowObj.setInstallerId(flowPath.installerId().toString());
 	flowObj.setFlowPathFlags(flowPath.flowPathFlags().flags());
@@ -627,6 +629,9 @@
 	if (flowPath.flowEntryMatch().matchDstTcpUdpPort()) {
 	    flowObj.setMatchDstTcpUdpPort(flowPath.flowEntryMatch().dstTcpUdpPort());
 	}
+	if (! flowPath.flowEntryActions().actions().isEmpty()) {
+	    flowObj.setActions(flowPath.flowEntryActions().toString());
+	}
 
 	if (dataPathSummaryStr != null) {
 	    flowObj.setDataPathSummary(dataPathSummaryStr);
@@ -720,8 +725,6 @@
 	// - InPort edge
 	// - OutPort edge
 	//
-	// - flowEntry.flowEntryMatch()
-	// - flowEntry.flowEntryActions()
 	// - flowEntry.dpid()
 	// - flowEntry.flowEntryUserState()
 	// - flowEntry.flowEntrySwitchState()
@@ -739,6 +742,7 @@
 	// - flowEntry.matchSrcTcpUdpPort()
 	// - flowEntry.matchDstTcpUdpPort()
 	// - flowEntry.actionOutputPort()
+	// - flowEntry.actions()
 	//
 	ISwitchObject sw =
 	    op.searchSwitch(flowEntry.dpid().toString());
@@ -785,7 +789,7 @@
 	    flowEntryObj.setMatchDstTcpUdpPort(flowEntry.flowEntryMatch().dstTcpUdpPort());
 	}
 
-	for (FlowEntryAction fa : flowEntry.flowEntryActions()) {
+	for (FlowEntryAction fa : flowEntry.flowEntryActions().actions()) {
 	    if (fa.actionOutput() != null) {
 		IPortObject outport =
 		    op.searchPort(flowEntry.dpid().toString(),
@@ -794,6 +798,10 @@
 		flowEntryObj.setOutPort(outport);
 	    }
 	}
+	if (! flowEntry.flowEntryActions().isEmpty()) {
+	    flowEntryObj.setActions(flowEntry.flowEntryActions().toString());
+	}
+
 	// TODO: Hacks with hard-coded state names!
 	if (found)
 	    flowEntryObj.setUserState("FE_USER_MODIFY");
@@ -1387,6 +1395,16 @@
 
 	    flowPath.setFlowEntryMatch(match);
 	}
+	//
+	// Extract the actions for the first Flow Entry
+	//
+	{
+	    String actionsStr = flowObj.getActions();
+	    if (actionsStr != null) {
+		FlowEntryActions flowEntryActions = new FlowEntryActions(actionsStr);
+		flowPath.setFlowEntryActions(flowEntryActions);
+	    }
+	}
 
 	//
 	// Extract all Flow Entries
@@ -1471,19 +1489,15 @@
 	//
 	// Extract the actions
 	//
-	ArrayList<FlowEntryAction> actions = new ArrayList<FlowEntryAction>();
-	Short actionOutputPort = flowEntryObj.getActionOutputPort();
-	if (actionOutputPort != null) {
-	    FlowEntryAction action = new FlowEntryAction();
-	    action.setActionOutput(new Port(actionOutputPort));
-	    actions.add(action);
-	}
+	FlowEntryActions actions = new FlowEntryActions();
+	String actionsStr = flowEntryObj.getActions();
+	if (actionsStr != null)
+	    actions = new FlowEntryActions(actionsStr);
 	flowEntry.setFlowEntryActions(actions);
 	flowEntry.setFlowEntryUserState(FlowEntryUserState.valueOf(userState));
 	flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.valueOf(switchState));
 	//
-	// TODO: Take care of the FlowEntryMatch, FlowEntryAction set,
-	// and FlowEntryErrorState.
+	// TODO: Take care of FlowEntryErrorState.
 	//
 	return flowEntry;
     }
@@ -1518,6 +1532,7 @@
 	computedFlowPath.setFlowPathFlags(new FlowPathFlags(flowPath.flowPathFlags().flags()));
 	computedFlowPath.setDataPath(dataPath);
 	computedFlowPath.setFlowEntryMatch(new FlowEntryMatch(flowPath.flowEntryMatch()));
+	computedFlowPath.setFlowEntryActions(new FlowEntryActions(flowPath.flowEntryActions()));
 
 	FlowId flowId = new FlowId();
 	String dataPathSummaryStr = dataPath.dataPathSummary();
@@ -1543,21 +1558,35 @@
 	// Set the incoming port matching and the outgoing port output
 	// actions for each flow entry.
 	//
+	int idx = 0;
 	for (FlowEntry flowEntry : newDataPath.flowEntries()) {
 	    // Set the incoming port matching
 	    FlowEntryMatch flowEntryMatch = new FlowEntryMatch();
 	    flowEntry.setFlowEntryMatch(flowEntryMatch);
 	    flowEntryMatch.enableInPort(flowEntry.inPort());
 
-	    // Set the outgoing port output action
-	    ArrayList<FlowEntryAction> flowEntryActions = flowEntry.flowEntryActions();
-	    if (flowEntryActions == null) {
-		flowEntryActions = new ArrayList<FlowEntryAction>();
-		flowEntry.setFlowEntryActions(flowEntryActions);
+	    //
+	    // Set the actions
+	    //
+	    FlowEntryActions flowEntryActions = flowEntry.flowEntryActions();
+	    //
+	    // If the first Flow Entry, copy the Flow Path actions to it
+	    //
+	    if (idx == 0) {
+		String actionsStr = flowObj.getActions();
+		if (actionsStr != null) {
+		    FlowEntryActions flowActions = new FlowEntryActions(actionsStr);
+		    for (FlowEntryAction action : flowActions.actions())
+			flowEntryActions.addAction(action);
+		}
 	    }
+	    idx++;
+	    //
+	    // Add the outgoing port output action
+	    //
 	    FlowEntryAction flowEntryAction = new FlowEntryAction();
 	    flowEntryAction.setActionOutput(flowEntry.outPort());
-	    flowEntryActions.add(flowEntryAction);
+	    flowEntryActions.addAction(flowEntryAction);
 	}
 
 	//
@@ -1749,16 +1778,115 @@
 	//
 	// Fetch the actions
 	//
-	// TODO: For now we support only the "OUTPUT" actions.
-	//
-	List<OFAction> actions = new ArrayList<OFAction>();
-	Short actionOutputPort = flowEntryObj.getActionOutputPort();
-	if (actionOutputPort != null) {
-	    OFActionOutput action = new OFActionOutput();
-	    // XXX: The max length is hard-coded for now
-	    action.setMaxLength((short)0xffff);
-	    action.setPort(actionOutputPort);
-	    actions.add(action);
+	Short actionOutputPort = null;
+	List<OFAction> openFlowActions = new ArrayList<OFAction>();
+	int actionsLen = 0;
+	FlowEntryActions flowEntryActions = null;
+	String actionsStr = flowEntryObj.getActions();
+	if (actionsStr != null)
+	    flowEntryActions = new FlowEntryActions(actionsStr);
+	for (FlowEntryAction action : flowEntryActions.actions()) {
+	    ActionOutput actionOutput = action.actionOutput();
+	    ActionSetVlanId actionSetVlanId = action.actionSetVlanId();
+	    ActionSetVlanPriority actionSetVlanPriority = action.actionSetVlanPriority();
+	    ActionStripVlan actionStripVlan = action.actionStripVlan();
+	    ActionSetEthernetAddr actionSetEthernetSrcAddr = action.actionSetEthernetSrcAddr();
+	    ActionSetEthernetAddr actionSetEthernetDstAddr = action.actionSetEthernetDstAddr();
+	    ActionSetIPv4Addr actionSetIPv4SrcAddr = action.actionSetIPv4SrcAddr();
+	    ActionSetIPv4Addr actionSetIPv4DstAddr = action.actionSetIPv4DstAddr();
+	    ActionSetIpToS actionSetIpToS = action.actionSetIpToS();
+	    ActionSetTcpUdpPort actionSetTcpUdpSrcPort = action.actionSetTcpUdpSrcPort();
+	    ActionSetTcpUdpPort actionSetTcpUdpDstPort = action.actionSetTcpUdpDstPort();
+	    ActionEnqueue actionEnqueue = action.actionEnqueue();
+
+	    if (actionOutput != null) {
+		actionOutputPort = actionOutput.port().value();
+		// XXX: The max length is hard-coded for now
+		OFActionOutput ofa =
+		    new OFActionOutput(actionOutput.port().value(),
+				       (short)0xffff);
+		openFlowActions.add(ofa);
+		actionsLen += ofa.getLength();
+	    }
+
+	    if (actionSetVlanId != null) {
+		OFActionVirtualLanIdentifier ofa =
+		    new OFActionVirtualLanIdentifier(actionSetVlanId.vlanId());
+		openFlowActions.add(ofa);
+		actionsLen += ofa.getLength();
+	    }
+
+	    if (actionSetVlanPriority != null) {
+		OFActionVirtualLanPriorityCodePoint ofa =
+		    new OFActionVirtualLanPriorityCodePoint(actionSetVlanPriority.vlanPriority());
+		openFlowActions.add(ofa);
+		actionsLen += ofa.getLength();
+	    }
+
+	    if (actionStripVlan != null) {
+		if (actionStripVlan.stripVlan() == true) {
+		    OFActionStripVirtualLan ofa = new OFActionStripVirtualLan();
+		    openFlowActions.add(ofa);
+		    actionsLen += ofa.getLength();
+		}
+	    }
+
+	    if (actionSetEthernetSrcAddr != null) {
+		OFActionDataLayerSource ofa = 
+		    new OFActionDataLayerSource(actionSetEthernetSrcAddr.addr().toBytes());
+		openFlowActions.add(ofa);
+		actionsLen += ofa.getLength();
+	    }
+
+	    if (actionSetEthernetDstAddr != null) {
+		OFActionDataLayerDestination ofa =
+		    new OFActionDataLayerDestination(actionSetEthernetDstAddr.addr().toBytes());
+		openFlowActions.add(ofa);
+		actionsLen += ofa.getLength();
+	    }
+
+	    if (actionSetIPv4SrcAddr != null) {
+		OFActionNetworkLayerSource ofa =
+		    new OFActionNetworkLayerSource(actionSetIPv4SrcAddr.addr().value());
+		openFlowActions.add(ofa);
+		actionsLen += ofa.getLength();
+	    }
+
+	    if (actionSetIPv4DstAddr != null) {
+		OFActionNetworkLayerDestination ofa =
+		    new OFActionNetworkLayerDestination(actionSetIPv4DstAddr.addr().value());
+		openFlowActions.add(ofa);
+		actionsLen += ofa.getLength();
+	    }
+
+	    if (actionSetIpToS != null) {
+		OFActionNetworkTypeOfService ofa =
+		    new OFActionNetworkTypeOfService(actionSetIpToS.ipToS());
+		openFlowActions.add(ofa);
+		actionsLen += ofa.getLength();
+	    }
+
+	    if (actionSetTcpUdpSrcPort != null) {
+		OFActionTransportLayerSource ofa =
+		    new OFActionTransportLayerSource(actionSetTcpUdpSrcPort.port());
+		openFlowActions.add(ofa);
+		actionsLen += ofa.getLength();
+	    }
+
+	    if (actionSetTcpUdpDstPort != null) {
+		OFActionTransportLayerDestination ofa =
+		    new OFActionTransportLayerDestination(actionSetTcpUdpDstPort.port());
+		openFlowActions.add(ofa);
+		actionsLen += ofa.getLength();
+	    }
+
+	    if (actionEnqueue != null) {
+		OFActionEnqueue ofa =
+		    new OFActionEnqueue(actionEnqueue.port().value(),
+					actionEnqueue.queueId());
+		openFlowActions.add(ofa);
+		actionsLen += ofa.getLength();
+	    }
 	}
 
 	fm.setIdleTimeout(FLOWMOD_DEFAULT_IDLE_TIMEOUT)
@@ -1768,8 +1896,8 @@
 	    .setCookie(cookie)
 	    .setCommand(flowModCommand)
 	    .setMatch(match)
-	    .setActions(actions)
-	    .setLengthU(OFFlowMod.MINIMUM_LENGTH+OFActionOutput.MINIMUM_LENGTH);
+	    .setActions(openFlowActions)
+	    .setLengthU(OFFlowMod.MINIMUM_LENGTH + actionsLen);
 	fm.setOutPort(OFPort.OFPP_NONE.getValue());
 	if ((flowModCommand == OFFlowMod.OFPFC_DELETE) ||
 	    (flowModCommand == OFFlowMod.OFPFC_DELETE_STRICT)) {
@@ -1973,27 +2101,113 @@
 	//
 	// Fetch the actions
 	//
-	// TODO: For now we support only the "OUTPUT" actions.
+	Short actionOutputPort = null;
+	List<OFAction> openFlowActions = new ArrayList<OFAction>();
+	int actionsLen = 0;
+	FlowEntryActions flowEntryActions = flowEntry.flowEntryActions();
 	//
-	fm.setOutPort(OFPort.OFPP_NONE.getValue());
-	List<OFAction> actions = new ArrayList<OFAction>();
-	ArrayList<FlowEntryAction> flowEntryActions =
-	    flowEntry.flowEntryActions();
-	for (FlowEntryAction flowEntryAction : flowEntryActions) {
-	    FlowEntryAction.ActionOutput actionOutput =
-		flowEntryAction.actionOutput();
+	for (FlowEntryAction action : flowEntryActions.actions()) {
+	    ActionOutput actionOutput = action.actionOutput();
+	    ActionSetVlanId actionSetVlanId = action.actionSetVlanId();
+	    ActionSetVlanPriority actionSetVlanPriority = action.actionSetVlanPriority();
+	    ActionStripVlan actionStripVlan = action.actionStripVlan();
+	    ActionSetEthernetAddr actionSetEthernetSrcAddr = action.actionSetEthernetSrcAddr();
+	    ActionSetEthernetAddr actionSetEthernetDstAddr = action.actionSetEthernetDstAddr();
+	    ActionSetIPv4Addr actionSetIPv4SrcAddr = action.actionSetIPv4SrcAddr();
+	    ActionSetIPv4Addr actionSetIPv4DstAddr = action.actionSetIPv4DstAddr();
+	    ActionSetIpToS actionSetIpToS = action.actionSetIpToS();
+	    ActionSetTcpUdpPort actionSetTcpUdpSrcPort = action.actionSetTcpUdpSrcPort();
+	    ActionSetTcpUdpPort actionSetTcpUdpDstPort = action.actionSetTcpUdpDstPort();
+	    ActionEnqueue actionEnqueue = action.actionEnqueue();
+
 	    if (actionOutput != null) {
-		short actionOutputPort = actionOutput.port().value();
-		OFActionOutput action = new OFActionOutput();
+		actionOutputPort = actionOutput.port().value();
 		// XXX: The max length is hard-coded for now
-		action.setMaxLength((short)0xffff);
-		action.setPort(actionOutputPort);
-		actions.add(action);
-		if ((flowModCommand == OFFlowMod.OFPFC_DELETE) ||
-		    (flowModCommand == OFFlowMod.OFPFC_DELETE_STRICT)) {
-		    fm.setOutPort(actionOutputPort);
+		OFActionOutput ofa =
+		    new OFActionOutput(actionOutput.port().value(),
+				       (short)0xffff);
+		openFlowActions.add(ofa);
+		actionsLen += ofa.getLength();
+	    }
+
+	    if (actionSetVlanId != null) {
+		OFActionVirtualLanIdentifier ofa =
+		    new OFActionVirtualLanIdentifier(actionSetVlanId.vlanId());
+		openFlowActions.add(ofa);
+		actionsLen += ofa.getLength();
+	    }
+
+	    if (actionSetVlanPriority != null) {
+		OFActionVirtualLanPriorityCodePoint ofa =
+		    new OFActionVirtualLanPriorityCodePoint(actionSetVlanPriority.vlanPriority());
+		openFlowActions.add(ofa);
+		actionsLen += ofa.getLength();
+	    }
+
+	    if (actionStripVlan != null) {
+		if (actionStripVlan.stripVlan() == true) {
+		    OFActionStripVirtualLan ofa = new OFActionStripVirtualLan();
+		    openFlowActions.add(ofa);
+		    actionsLen += ofa.getLength();
 		}
 	    }
+
+	    if (actionSetEthernetSrcAddr != null) {
+		OFActionDataLayerSource ofa = 
+		    new OFActionDataLayerSource(actionSetEthernetSrcAddr.addr().toBytes());
+		openFlowActions.add(ofa);
+		actionsLen += ofa.getLength();
+	    }
+
+	    if (actionSetEthernetDstAddr != null) {
+		OFActionDataLayerDestination ofa =
+		    new OFActionDataLayerDestination(actionSetEthernetDstAddr.addr().toBytes());
+		openFlowActions.add(ofa);
+		actionsLen += ofa.getLength();
+	    }
+
+	    if (actionSetIPv4SrcAddr != null) {
+		OFActionNetworkLayerSource ofa =
+		    new OFActionNetworkLayerSource(actionSetIPv4SrcAddr.addr().value());
+		openFlowActions.add(ofa);
+		actionsLen += ofa.getLength();
+	    }
+
+	    if (actionSetIPv4DstAddr != null) {
+		OFActionNetworkLayerDestination ofa =
+		    new OFActionNetworkLayerDestination(actionSetIPv4DstAddr.addr().value());
+		openFlowActions.add(ofa);
+		actionsLen += ofa.getLength();
+	    }
+
+	    if (actionSetIpToS != null) {
+		OFActionNetworkTypeOfService ofa =
+		    new OFActionNetworkTypeOfService(actionSetIpToS.ipToS());
+		openFlowActions.add(ofa);
+		actionsLen += ofa.getLength();
+	    }
+
+	    if (actionSetTcpUdpSrcPort != null) {
+		OFActionTransportLayerSource ofa =
+		    new OFActionTransportLayerSource(actionSetTcpUdpSrcPort.port());
+		openFlowActions.add(ofa);
+		actionsLen += ofa.getLength();
+	    }
+
+	    if (actionSetTcpUdpDstPort != null) {
+		OFActionTransportLayerDestination ofa =
+		    new OFActionTransportLayerDestination(actionSetTcpUdpDstPort.port());
+		openFlowActions.add(ofa);
+		actionsLen += ofa.getLength();
+	    }
+
+	    if (actionEnqueue != null) {
+		OFActionEnqueue ofa =
+		    new OFActionEnqueue(actionEnqueue.port().value(),
+					actionEnqueue.queueId());
+		openFlowActions.add(ofa);
+		actionsLen += ofa.getLength();
+	    }
 	}
 
 	fm.setIdleTimeout(FLOWMOD_DEFAULT_IDLE_TIMEOUT)
@@ -2003,8 +2217,14 @@
 	    .setCookie(cookie)
 	    .setCommand(flowModCommand)
 	    .setMatch(match)
-	    .setActions(actions)
-	    .setLengthU(OFFlowMod.MINIMUM_LENGTH+OFActionOutput.MINIMUM_LENGTH);
+	    .setActions(openFlowActions)
+	    .setLengthU(OFFlowMod.MINIMUM_LENGTH + actionsLen);
+	fm.setOutPort(OFPort.OFPP_NONE.getValue());
+	if ((flowModCommand == OFFlowMod.OFPFC_DELETE) ||
+	    (flowModCommand == OFFlowMod.OFPFC_DELETE_STRICT)) {
+	    if (actionOutputPort != null)
+		fm.setOutPort(actionOutputPort);
+	}
 
 	//
 	// TODO: Set the following flag
@@ -2131,14 +2351,10 @@
 	    flowEntryMatch.enableInPort(flowEntry.inPort());
 
 	    // Set the outgoing port output action
-	    ArrayList<FlowEntryAction> flowEntryActions = flowEntry.flowEntryActions();
-	    if (flowEntryActions == null) {
-		flowEntryActions = new ArrayList<FlowEntryAction>();
-		flowEntry.setFlowEntryActions(flowEntryActions);
-	    }
+	    FlowEntryActions flowEntryActions = flowEntry.flowEntryActions();
 	    FlowEntryAction flowEntryAction = new FlowEntryAction();
 	    flowEntryAction.setActionOutput(flowEntry.outPort());
-	    flowEntryActions.add(flowEntryAction);
+	    flowEntryActions.addAction(flowEntryAction);
 	}
 
 	//
diff --git a/src/main/java/net/onrc/onos/ofcontroller/util/FlowEntry.java b/src/main/java/net/onrc/onos/ofcontroller/util/FlowEntry.java
index 7dd0699..87d08ce 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/util/FlowEntry.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/util/FlowEntry.java
@@ -15,7 +15,7 @@
     private FlowId flowId;			// FlowID of flowEntry
     private FlowEntryId flowEntryId;		// The Flow Entry ID
     private FlowEntryMatch flowEntryMatch;	// The Flow Entry Match
-    private ArrayList<FlowEntryAction> flowEntryActions; // The Flow Entry Actions
+    private FlowEntryActions flowEntryActions;	// The Flow Entry Actions
     private Dpid dpid;				// The Switch DPID
     private Port inPort;		// The Switch incoming port. Used only
 					// when the entry is used to return
@@ -53,64 +53,64 @@
 	flowEntryMatch.enableDstTcpUdpPort((short)80);
 
 	FlowEntryAction action = null;
-	ArrayList<FlowEntryAction> actions = new ArrayList<FlowEntryAction>();
+	FlowEntryActions actions = new FlowEntryActions();
 
 	action = new FlowEntryAction();
 	action.setActionOutput(new Port((short)12));
-	actions.add(action);
+	actions.addAction(action);
 
 	action = new FlowEntryAction();
 	action.setActionOutputToController((short)13);
-	actions.add(action);
+	actions.addAction(action);
 
 	action = new FlowEntryAction();
 	action.setActionSetVlanId((short)14);
-	actions.add(action);
+	actions.addAction(action);
 
 	action = new FlowEntryAction();
 	action.setActionSetVlanPriority((byte)15);
-	actions.add(action);
+	actions.addAction(action);
 
 	action = new FlowEntryAction();
 	action.setActionStripVlan(true);
-	actions.add(action);
+	actions.addAction(action);
 
 	action = new FlowEntryAction();
 	action.setActionSetEthernetSrcAddr(mac);
-	actions.add(action);
+	actions.addAction(action);
 
 	action = new FlowEntryAction();
 	action.setActionSetEthernetDstAddr(mac);
-	actions.add(action);
+	actions.addAction(action);
 
 	action = new FlowEntryAction();
 	action.setActionSetIPv4SrcAddr(ipv4);
-	actions.add(action);
+	actions.addAction(action);
 
 	action = new FlowEntryAction();
 	action.setActionSetIPv4DstAddr(ipv4);
-	actions.add(action);
+	actions.addAction(action);
 
 	action = new FlowEntryAction();
 	action.setActionSetIpToS((byte)16);
-	actions.add(action);
+	actions.addAction(action);
 
 	action = new FlowEntryAction();
 	action.setActionSetTcpUdpSrcPort((short)17);
-	actions.add(action);
+	actions.addAction(action);
 
 	action = new FlowEntryAction();
 	action.setActionSetTcpUdpDstPort((short)18);
-	actions.add(action);
+	actions.addAction(action);
 
 	action = new FlowEntryAction();
 	action.setActionEnqueue(new Port((short)19), 20);
-	actions.add(action);
+	actions.addAction(action);
 
 	setFlowEntryActions(actions);
 	*/
 
-
+	flowEntryActions = new FlowEntryActions();
 	flowEntryUserState = FlowEntryUserState.FE_USER_UNKNOWN;
 	flowEntrySwitchState = FlowEntrySwitchState.FE_SWITCH_UNKNOWN;
     }
@@ -173,7 +173,7 @@
      * @return the Flow Entry Actions.
      */
     @JsonProperty("flowEntryActions")
-    public ArrayList<FlowEntryAction> flowEntryActions() {
+    public FlowEntryActions flowEntryActions() {
 	return flowEntryActions;
     }
 
@@ -183,7 +183,7 @@
      * @param flowEntryActions the Flow Entry Actions to set.
      */
     @JsonProperty("flowEntryActions")
-    public void setFlowEntryActions(ArrayList<FlowEntryAction> flowEntryActions) {
+    public void setFlowEntryActions(FlowEntryActions flowEntryActions) {
 	this.flowEntryActions = flowEntryActions;
     }
 
@@ -319,8 +319,7 @@
      * Convert the flow entry to a string.
      *
      * The string has the following form:
-     *  [flowEntryId=XXX flowEntryMatch=XXX flowEntryAction=XXX
-     *   flowEntryAction=XXX flowEntryAction=XXX dpid=XXX
+     *  [flowEntryId=XXX flowEntryMatch=XXX flowEntryActions=XXX dpid=XXX
      *   inPort=XXX outPort=XXX flowEntryUserState=XXX flowEntrySwitchState=XXX
      *   flowEntryErrorState=XXX]
      * @return the flow entry as a string.
@@ -329,9 +328,7 @@
     public String toString() {
 	String ret = "[flowEntryId=" + this.flowEntryId.toString();
 	ret += " flowEntryMatch=" + this.flowEntryMatch.toString();
-	for (FlowEntryAction fa : flowEntryActions) {
-	    ret += " flowEntryAction=" + fa.toString();
-	}
+	ret += " flowEntryActions=" + this.flowEntryActions.toString();
 	ret += " dpid=" + this.dpid.toString();
 	ret += " inPort=" + this.inPort.toString();
 	ret += " outPort=" + this.outPort.toString();
diff --git a/src/main/java/net/onrc/onos/ofcontroller/util/FlowEntryAction.java b/src/main/java/net/onrc/onos/ofcontroller/util/FlowEntryAction.java
index 22aef98..b9c41ff 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/util/FlowEntryAction.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/util/FlowEntryAction.java
@@ -59,6 +59,28 @@
 	    this.maxLen = 0;
 	}
 
+	/**
+	 * Copy constructor.
+	 *
+	 * @param other the object to copy from.
+	 */
+	public ActionOutput(ActionOutput other) {
+	    if (other.port != null)
+		this.port = new Port(other.port);
+	    this.maxLen = other.maxLen;
+	}
+
+	/**
+	 * Constructor from a string.
+	 *
+	 * The string has the following form:
+	 *  [port=XXX maxLen=XXX]
+	 *
+	 * @param actionStr the action as a string.
+	 */
+	public ActionOutput(String actionStr) {
+	    this.fromString(actionStr);
+	}
 
 	/**
 	 * Constructor for a given output port and maximum length.
@@ -121,6 +143,54 @@
 
 	    return ret;
 	}
+
+	/**
+	 * Convert a string to an action.
+	 *
+	 * The string has the following form:
+	 *  [port=XXX maxLen=XXX]
+	 *
+	 * @param actionStr the action as a string.
+	 */
+	public void fromString(String actionStr) {
+	    String[] parts = actionStr.split(" ");
+	    String decode = null;
+
+	    // Decode the "port=XXX" part
+	    if (parts.length > 0)
+		decode = parts[0];
+	    if (decode != null) {
+		String[] tokens = decode.split("port=");
+		if (tokens.length > 1 && tokens[1] != null) {
+		    try {
+			Short valueShort = Short.valueOf(tokens[1]);
+			port = new Port(valueShort);
+		    } catch (NumberFormatException e) {
+			throw new IllegalArgumentException("Invalid action string");
+		    }
+		}
+	    } else {
+		throw new IllegalArgumentException("Invalid action string");
+	    }
+
+	    // Decode the "maxLen=XXX" part
+	    decode = null;
+	    if (parts.length > 1)
+		decode = parts[1];
+	    if (decode != null) {
+		decode = decode.replace("]", "");
+		String[] tokens = decode.split("maxLen=");
+		if (tokens.length > 1 && tokens[1] != null) {
+		    try {
+			maxLen = Short.valueOf(tokens[1]);
+		    } catch (NumberFormatException e) {
+			throw new IllegalArgumentException("Invalid action string");
+		    }
+		}
+	    } else {
+		throw new IllegalArgumentException("Invalid action string");
+	    }
+	}
     }
 
     /**
@@ -137,6 +207,27 @@
 	}
 
 	/**
+	 * Copy constructor.
+	 *
+	 * @param other the object to copy from.
+	 */
+	public ActionSetVlanId(ActionSetVlanId other) {
+	    this.vlanId = other.vlanId;
+	}
+
+	/**
+	 * Constructor from a string.
+	 *
+	 * The string has the following form:
+	 *  [vlanId=XXX]
+	 *
+	 * @param actionStr the action as a string.
+	 */
+	public ActionSetVlanId(String actionStr) {
+	    this.fromString(actionStr);
+	}
+
+	/**
 	 * Constructor for a given VLAN ID.
 	 *
 	 * @param vlanId the VLAN ID to set.
@@ -171,6 +262,33 @@
 
 	    return ret;
 	}
+
+	/**
+	 * Convert a string to an action.
+	 *
+	 * The string has the following form:
+	 *  [vlanId=XXX]
+	 *
+	 * @param actionStr the action as a string.
+	 */
+	public void fromString(String actionStr) {
+	    String[] parts = actionStr.split("vlanId=");
+	    String decode = null;
+
+	    // Decode the value
+	    if (parts.length > 1)
+		decode = parts[1];
+	    if (decode != null) {
+		decode = decode.replace("]", "");
+		try {
+		    vlanId = Short.valueOf(decode);
+		} catch (NumberFormatException e) {
+		    throw new IllegalArgumentException("Invalid action string");
+		}
+	    } else {
+		throw new IllegalArgumentException("Invalid action string");
+	    }
+	}
     }
 
     /**
@@ -187,6 +305,27 @@
 	}
 
 	/**
+	 * Copy constructor.
+	 *
+	 * @param other the object to copy from.
+	 */
+	public ActionSetVlanPriority(ActionSetVlanPriority other) {
+	    this.vlanPriority = other.vlanPriority;
+	}
+
+	/**
+	 * Constructor from a string.
+	 *
+	 * The string has the following form:
+	 *  [vlanPriority=XXX]
+	 *
+	 * @param actionStr the action as a string.
+	 */
+	public ActionSetVlanPriority(String actionStr) {
+	    this.fromString(actionStr);
+	}
+
+	/**
 	 * Constructor for a given VLAN priority.
 	 *
 	 * @param vlanPriority the VLAN priority to set.
@@ -221,6 +360,33 @@
 
 	    return ret;
 	}
+
+	/**
+	 * Convert a string to an action.
+	 *
+	 * The string has the following form:
+	 *  [vlanPriority=XXX]
+	 *
+	 * @param actionStr the action as a string.
+	 */
+	public void fromString(String actionStr) {
+	    String[] parts = actionStr.split("vlanPriority=");
+	    String decode = null;
+
+	    // Decode the value
+	    if (parts.length > 1)
+		decode = parts[1];
+	    if (decode != null) {
+		decode = decode.replace("]", "");
+		try {
+		    vlanPriority = Byte.valueOf(decode);
+		} catch (NumberFormatException e) {
+		    throw new IllegalArgumentException("Invalid action string");
+		}
+	    } else {
+		throw new IllegalArgumentException("Invalid action string");
+	    }
+	}
     }
 
     /**
@@ -237,6 +403,27 @@
 	}
 
 	/**
+	 * Copy constructor.
+	 *
+	 * @param other the object to copy from.
+	 */
+	public ActionStripVlan(ActionStripVlan other) {
+	    this.stripVlan = other.stripVlan;
+	}
+
+	/**
+	 * Constructor from a string.
+	 *
+	 * The string has the following form:
+	 *  [stripVlan=XXX]
+	 *
+	 * @param actionStr the action as a string.
+	 */
+	public ActionStripVlan(String actionStr) {
+	    this.fromString(actionStr);
+	}
+
+	/**
 	 * Constructor for a given boolean flag.
 	 *
 	 * @param stripVlan if true, strip the VLAN header.
@@ -271,6 +458,29 @@
 
 	    return ret;
 	}
+
+	/**
+	 * Convert a string to an action.
+	 *
+	 * The string has the following form:
+	 *  [stripVlan=XXX]
+	 *
+	 * @param actionStr the action as a string.
+	 */
+	public void fromString(String actionStr) {
+	    String[] parts = actionStr.split("stripVlan=");
+	    String decode = null;
+
+	    // Decode the value
+	    if (parts.length > 1)
+		decode = parts[1];
+	    if (decode != null) {
+		decode = decode.replace("]", "");
+		stripVlan = Boolean.valueOf(decode);
+	    } else {
+		throw new IllegalArgumentException("Invalid action string");
+	    }
+	}
     }
 
     /**
@@ -288,6 +498,28 @@
 	}
 
 	/**
+	 * Copy constructor.
+	 *
+	 * @param other the object to copy from.
+	 */
+	public ActionSetEthernetAddr(ActionSetEthernetAddr other) {
+	    if (other.addr != null)
+		this.addr = MACAddress.valueOf(other.addr.toLong());
+	}
+
+	/**
+	 * Constructor from a string.
+	 *
+	 * The string has the following form:
+	 *  [addr=XXX]
+	 *
+	 * @param actionStr the action as a string.
+	 */
+	public ActionSetEthernetAddr(String actionStr) {
+	    this.fromString(actionStr);
+	}
+
+	/**
 	 * Constructor for a given MAC address.
 	 *
 	 * @param addr the MAC address to set.
@@ -322,6 +554,33 @@
 
 	    return ret;
 	}
+
+	/**
+	 * Convert a string to an action.
+	 *
+	 * The string has the following form:
+	 *  [addr=XXX]
+	 *
+	 * @param actionStr the action as a string.
+	 */
+	public void fromString(String actionStr) {
+	    String[] parts = actionStr.split("addr=");
+	    String decode = null;
+
+	    // Decode the value
+	    if (parts.length > 1)
+		decode = parts[1];
+	    if (decode != null) {
+		decode = decode.replace("]", "");
+		try {
+		    addr = MACAddress.valueOf(decode);
+		} catch (IllegalArgumentException e) {
+		    throw new IllegalArgumentException("Invalid action string");
+		}
+	    } else {
+		throw new IllegalArgumentException("Invalid action string");
+	    }
+	}
     }
 
     /**
@@ -339,6 +598,28 @@
 	}
 
 	/**
+	 * Copy constructor.
+	 *
+	 * @param other the object to copy from.
+	 */
+	public ActionSetIPv4Addr(ActionSetIPv4Addr other) {
+	    if (other.addr != null)
+		this.addr = new IPv4(other.addr);
+	}
+
+	/**
+	 * Constructor from a string.
+	 *
+	 * The string has the following form:
+	 *  [addr=XXX]
+	 *
+	 * @param actionStr the action as a string.
+	 */
+	public ActionSetIPv4Addr(String actionStr) {
+	    this.fromString(actionStr);
+	}
+
+	/**
 	 * Constructor for a given IPv4 address.
 	 *
 	 * @param addr the IPv4 address to set.
@@ -373,6 +654,33 @@
 
 	    return ret;
 	}
+
+	/**
+	 * Convert a string to an action.
+	 *
+	 * The string has the following form:
+	 *  [addr=XXX]
+	 *
+	 * @param actionStr the action as a string.
+	 */
+	public void fromString(String actionStr) {
+	    String[] parts = actionStr.split("addr=");
+	    String decode = null;
+
+	    // Decode the value
+	    if (parts.length > 1)
+		decode = parts[1];
+	    if (decode != null) {
+		decode = decode.replace("]", "");
+		try {
+		    addr = new IPv4(decode);
+		} catch (IllegalArgumentException e) {
+		    throw new IllegalArgumentException("Invalid action string");
+		}
+	    } else {
+		throw new IllegalArgumentException("Invalid action string");
+	    }
+	}
     }
 
     /**
@@ -390,6 +698,27 @@
 	}
 
 	/**
+	 * Copy constructor.
+	 *
+	 * @param other the object to copy from.
+	 */
+	public ActionSetIpToS(ActionSetIpToS other) {
+	    this.ipToS = other.ipToS;
+	}
+
+	/**
+	 * Constructor from a string.
+	 *
+	 * The string has the following form:
+	 *  [ipToS=XXX]
+	 *
+	 * @param actionStr the action as a string.
+	 */
+	public ActionSetIpToS(String actionStr) {
+	    this.fromString(actionStr);
+	}
+
+	/**
 	 * Constructor for a given IP ToS (DSCP field, 6 bits).
 	 *
 	 * @param ipToS the IP ToS (DSCP field, 6 bits) to set.
@@ -424,6 +753,33 @@
 
 	    return ret;
 	}
+
+	/**
+	 * Convert a string to an action.
+	 *
+	 * The string has the following form:
+	 *  [ipToS=XXX]
+	 *
+	 * @param actionStr the action as a string.
+	 */
+	public void fromString(String actionStr) {
+	    String[] parts = actionStr.split("ipToS=");
+	    String decode = null;
+
+	    // Decode the value
+	    if (parts.length > 1)
+		decode = parts[1];
+	    if (decode != null) {
+		decode = decode.replace("]", "");
+		try {
+		    ipToS = Byte.valueOf(decode);
+		} catch (NumberFormatException e) {
+		    throw new IllegalArgumentException("Invalid action string");
+		}
+	    } else {
+		throw new IllegalArgumentException("Invalid action string");
+	    }
+	}
     }
 
     /**
@@ -441,6 +797,27 @@
 	}
 
 	/**
+	 * Copy constructor.
+	 *
+	 * @param other the object to copy from.
+	 */
+	public ActionSetTcpUdpPort(ActionSetTcpUdpPort other) {
+	    this.port = other.port;
+	}
+
+	/**
+	 * Constructor from a string.
+	 *
+	 * The string has the following form:
+	 *  [port=XXX]
+	 *
+	 * @param actionStr the action as a string.
+	 */
+	public ActionSetTcpUdpPort(String actionStr) {
+	    this.fromString(actionStr);
+	}
+
+	/**
 	 * Constructor for a given TCP/UDP port.
 	 *
 	 * @param port the TCP/UDP port to set.
@@ -475,6 +852,33 @@
 
 	    return ret;
 	}
+
+	/**
+	 * Convert a string to an action.
+	 *
+	 * The string has the following form:
+	 *  [port=XXX]
+	 *
+	 * @param actionStr the action as a string.
+	 */
+	public void fromString(String actionStr) {
+	    String[] parts = actionStr.split("port=");
+	    String decode = null;
+
+	    // Decode the value
+	    if (parts.length > 1)
+		decode = parts[1];
+	    if (decode != null) {
+		decode = decode.replace("]", "");
+		try {
+		    port = Short.valueOf(decode);
+		} catch (NumberFormatException e) {
+		    throw new IllegalArgumentException("Invalid action string");
+		}
+	    } else {
+		throw new IllegalArgumentException("Invalid action string");
+	    }
+	}
     }
 
     /**
@@ -495,6 +899,29 @@
 	}
 
 	/**
+	 * Copy constructor.
+	 *
+	 * @param other the object to copy from.
+	 */
+	public ActionEnqueue(ActionEnqueue other) {
+	    if (other.port != null)
+		this.port = new Port(other.port);
+	    this.queueId = other.queueId;
+	}
+
+	/**
+	 * Constructor from a string.
+	 *
+	 * The string has the following form:
+	 *  [port=XXX queueId=XXX]
+	 *
+	 * @param actionStr the action as a string.
+	 */
+	public ActionEnqueue(String actionStr) {
+	    this.fromString(actionStr);
+	}
+
+	/**
 	 * Constructor for a given port and queue ID.
 	 *
 	 * @param port the port to set.
@@ -542,6 +969,54 @@
 
 	    return ret;
 	}
+
+	/**
+	 * Convert a string to an action.
+	 *
+	 * The string has the following form:
+	 *  [port=XXX queueId=XXX]
+	 *
+	 * @param actionStr the action as a string.
+	 */
+	public void fromString(String actionStr) {
+	    String[] parts = actionStr.split(" ");
+	    String decode = null;
+
+	    // Decode the "port=XXX" part
+	    if (parts.length > 0)
+		decode = parts[0];
+	    if (decode != null) {
+		String[] tokens = decode.split("port=");
+		if (tokens.length > 1 && tokens[1] != null) {
+		    try {
+			Short valueShort = Short.valueOf(tokens[1]);
+			port = new Port(valueShort);
+		    } catch (NumberFormatException e) {
+			throw new IllegalArgumentException("Invalid action string");
+		    }
+		}
+	    } else {
+		throw new IllegalArgumentException("Invalid action string");
+	    }
+
+	    // Decode the "queueId=XXX" part
+	    decode = null;
+	    if (parts.length > 1)
+		decode = parts[1];
+	    if (decode != null) {
+		decode = decode.replace("]", "");
+		String[] tokens = decode.split("queueId=");
+		if (tokens.length > 1 && tokens[1] != null) {
+		    try {
+			queueId = Short.valueOf(tokens[1]);
+		    } catch (NumberFormatException e) {
+			throw new IllegalArgumentException("Invalid action string");
+		    }
+		}
+	    } else {
+		throw new IllegalArgumentException("Invalid action string");
+	    }
+	}
     }
 
     private ActionValues actionType;	// The action type
@@ -571,6 +1046,88 @@
     }
 
     /**
+     * Copy constructor.
+     *
+     * @param other the object to copy from.
+     */
+    public FlowEntryAction(FlowEntryAction other) {
+	this.actionType = other.actionType;
+
+	//
+	if (other.actionOutput != null)
+	    this.actionOutput = new ActionOutput(other.actionOutput);
+	else
+	    this.actionOutput = null;
+	//
+	if (other.actionSetVlanId != null)
+	    this.actionSetVlanId = new ActionSetVlanId(other.actionSetVlanId);
+	else
+	    this.actionSetVlanId = null;
+	//
+	if (other.actionSetVlanPriority != null)
+	    this.actionSetVlanPriority = new ActionSetVlanPriority(other.actionSetVlanPriority);
+	else
+	    this.actionSetVlanPriority = null;
+	//
+	if (other.actionStripVlan != null)
+	    this.actionStripVlan = new ActionStripVlan(other.actionStripVlan);
+	else
+	    this.actionStripVlan = null;
+	//
+	if (other.actionSetEthernetSrcAddr != null)
+	    this.actionSetEthernetSrcAddr = new ActionSetEthernetAddr(other.actionSetEthernetSrcAddr);
+	else
+	    this.actionSetEthernetSrcAddr = null;
+	//
+	if (other.actionSetEthernetDstAddr != null)
+	    this.actionSetEthernetDstAddr = new ActionSetEthernetAddr(other.actionSetEthernetDstAddr);
+	else
+	    this.actionSetEthernetDstAddr = null;
+	//
+	if (other.actionSetIPv4SrcAddr != null)
+	    this.actionSetIPv4SrcAddr = new ActionSetIPv4Addr(other.actionSetIPv4SrcAddr);
+	else
+	    this.actionSetIPv4SrcAddr = null;
+	//
+	if (other.actionSetIPv4DstAddr != null)
+	    this.actionSetIPv4DstAddr = new ActionSetIPv4Addr(other.actionSetIPv4DstAddr);
+	else
+	    this.actionSetIPv4DstAddr = null;
+	//
+	if (other.actionSetIpToS != null)
+	    this.actionSetIpToS = new ActionSetIpToS(other.actionSetIpToS);
+	else
+	    this.actionSetIpToS = null;
+	//
+	if (other.actionSetTcpUdpSrcPort != null)
+	    this.actionSetTcpUdpSrcPort = new ActionSetTcpUdpPort(other.actionSetTcpUdpSrcPort);
+	else
+	    this.actionSetTcpUdpSrcPort = null;
+	//
+	if (other.actionSetTcpUdpDstPort != null)
+	    this.actionSetTcpUdpDstPort = new ActionSetTcpUdpPort(other.actionSetTcpUdpDstPort);
+	else
+	    this.actionSetTcpUdpDstPort = null;
+	//
+	if (other.actionEnqueue != null)
+	    this.actionEnqueue = new ActionEnqueue(other.actionEnqueue);
+	else
+	    this.actionEnqueue = null;
+    }
+
+    /**
+     * Constructor from a string.
+     *
+     * The string has the following form:
+     *  [type=XXX action=XXX]
+     *
+     * @param actionStr the action as a string.
+     */
+    public FlowEntryAction(String actionStr) {
+	this.fromString(actionStr);
+    }
+
+    /**
      * Get the action type.
      *
      * @return the action type.
@@ -957,12 +1514,12 @@
     }
 
     /**
-     * Convert the set of actions to a string.
+     * Convert the action to a string.
      *
      * The string has the following form:
      *  [type=XXX action=XXX]
      *
-     * @return the set of actions as a string.
+     * @return the action as a string.
      */
     @Override
     public String toString() {
@@ -1010,4 +1567,96 @@
 
 	return ret;
     }
+
+    /**
+     * Convert a string to an action.
+     *
+     * The string has the following form:
+     *  [type=XXX action=XXX]
+     *
+     * @param actionStr the action as a string.
+     */
+    public void fromString(String actionStr) {
+	String[] parts = actionStr.split("type=");
+	String decode = null;
+
+	// Extract the string after the "type="
+	if (parts.length > 1)
+	    decode = parts[1];
+	if (decode == null)
+	    throw new IllegalArgumentException("Invalid action string");
+
+	// Remove the trailing ']'
+	if ((decode.length() > 0) && (decode.charAt(decode.length() - 1) == ']')) {
+	    decode = decode.substring(0, decode.length() - 1);
+	} else {
+	    throw new IllegalArgumentException("Invalid action string");
+	}
+
+	// Extract the type value and the action value
+	parts = decode.split(" action=");
+
+	// Decode the "type=XXX" payload
+	if (parts.length > 0)
+	    decode = parts[0];
+	if (decode != null) {
+	    try {
+		actionType = Enum.valueOf(ActionValues.class, decode);
+	    } catch (IllegalArgumentException e) {
+		throw new IllegalArgumentException("Invalid action string");
+	    }
+	} else {
+	    throw new IllegalArgumentException("Invalid action string");
+	}
+
+	// Decode the "action=XXX" payload
+	decode = null;
+	if (parts.length > 1)
+	    decode = parts[1];
+	if (decode == null)
+	    throw new IllegalArgumentException("Invalid action string");
+	//
+	try {
+	    switch (actionType) {
+	    case ACTION_OUTPUT:
+		actionOutput = new ActionOutput(decode);
+		break;
+	    case ACTION_SET_VLAN_VID:
+		actionSetVlanId = new ActionSetVlanId(decode);
+		break;
+	    case ACTION_SET_VLAN_PCP:
+		actionSetVlanPriority = new ActionSetVlanPriority(decode);
+		break;
+	    case ACTION_STRIP_VLAN:
+		actionStripVlan = new ActionStripVlan(decode);
+		break;
+	    case ACTION_SET_DL_SRC:
+		actionSetEthernetSrcAddr = new ActionSetEthernetAddr(decode);
+		break;
+	    case ACTION_SET_DL_DST:
+		actionSetEthernetDstAddr = new ActionSetEthernetAddr(decode);
+		break;
+	    case ACTION_SET_NW_SRC:
+		actionSetIPv4SrcAddr = new ActionSetIPv4Addr(decode);
+		break;
+	    case ACTION_SET_NW_DST:
+		actionSetIPv4DstAddr = new ActionSetIPv4Addr(decode);
+		break;
+	    case ACTION_SET_NW_TOS:
+		actionSetIpToS = new ActionSetIpToS(decode);
+		break;
+	    case ACTION_SET_TP_SRC:
+		actionSetTcpUdpSrcPort = new ActionSetTcpUdpPort(decode);
+		break;
+	    case ACTION_SET_TP_DST:
+		actionSetTcpUdpDstPort = new ActionSetTcpUdpPort(decode);
+		break;
+	    case ACTION_ENQUEUE:
+		actionEnqueue = new ActionEnqueue(decode);
+		break;
+	    }
+	} catch (IllegalArgumentException e) {
+	    throw new IllegalArgumentException("Invalid action string");
+	}
+    }
 }
diff --git a/src/main/java/net/onrc/onos/ofcontroller/util/FlowEntryActions.java b/src/main/java/net/onrc/onos/ofcontroller/util/FlowEntryActions.java
new file mode 100644
index 0000000..46f638d
--- /dev/null
+++ b/src/main/java/net/onrc/onos/ofcontroller/util/FlowEntryActions.java
@@ -0,0 +1,146 @@
+package net.onrc.onos.ofcontroller.util;
+
+import java.util.ArrayList;
+
+import org.codehaus.jackson.annotate.JsonProperty;
+
+/**
+ * The class representing multiple Flow Entry actions.
+ *
+ * A set of Flow Entry actions need to be applied to each packet.
+ */
+public class FlowEntryActions {
+    private ArrayList<FlowEntryAction> actions;	// The Flow Entry Actions
+
+    /**
+     * Default constructor.
+     */
+    public FlowEntryActions() {
+	actions = new ArrayList<FlowEntryAction>();
+    }
+
+    /**
+     * Constructor from a string.
+     *
+     * The string has the following form:
+     *  [[type=XXX action=XXX];[type=XXX action=XXX];...;]
+     *
+     * @param actionsStr the set of actions as a string.
+     */
+    public FlowEntryActions(String actionsStr) {
+	this.fromString(actionsStr);
+    }
+
+    /**
+     * Copy constructor.
+     *
+     * @param other the object to copy from.
+     */
+    public FlowEntryActions(FlowEntryActions other) {
+	actions = new ArrayList<FlowEntryAction>();
+
+	for (FlowEntryAction action : other.actions) {
+	    FlowEntryAction newAction = new FlowEntryAction(action);
+	    actions.add(newAction);
+	}
+    }
+
+    /**
+     * Get the Flow Entry Actions.
+     *
+     * @return the Flow Entry Actions.
+     */
+    @JsonProperty("actions")
+    public ArrayList<FlowEntryAction> actions() {
+	return actions;
+    }
+
+    /**
+     * Set the Flow Entry Actions.
+     *
+     * @param actions the Flow Entry Actions to set.
+     */
+    @JsonProperty("actions")
+    public void setActions(ArrayList<FlowEntryAction> actions) {
+	this.actions = actions;
+    }
+
+    /**
+     * Add a Flow Entry Action.
+     *
+     * @param FlowEntryAction the Flow Entry Action to add.
+     */
+    public void addAction(FlowEntryAction flowEntryAction) {
+	actions.add(flowEntryAction);
+    }
+
+    /**
+     * Test whether the set of actions is empty.
+     *
+     * @return true if the set of actions is empty, otherwise false.
+     */
+    public Boolean isEmpty() {
+	return actions.isEmpty();
+    }
+
+    /**
+     * Convert the set of actions to a string.
+     *
+     * The string has the following form:
+     *  [[type=XXX action=XXX];[type=XXX action=XXX];...;]
+     *
+     * @return the set of actions as a string.
+     */
+    @Override
+    public String toString() {
+	String ret = "[";
+	for (FlowEntryAction action : actions) {
+	    ret += action.toString() + ";";
+	}
+	ret += "]";
+
+	return ret;
+    }
+
+    /**
+     * Convert a string to a set of actions.
+     *
+     * The string has the following form:
+     *  [[type=XXX action=XXX];[type=XXX action=XXX];...;]
+     *
+     * @param actionsStr the set of actions as a string.
+     */
+    public void fromString(String actionsStr) {
+	String decode = actionsStr;
+
+	actions = new ArrayList<FlowEntryAction>();
+
+	if (decode.isEmpty())
+	    return;		// Nothing to do
+
+	// Remove the '[' and ']' in the beginning and the end of the string
+	if ((decode.length() > 1) && (decode.charAt(0) == '[') &&
+	    (decode.charAt(decode.length() - 1) == ']')) {
+	    decode = decode.substring(1, decode.length() - 1);
+	} else {
+	    throw new IllegalArgumentException("Invalid action string");
+	}
+
+	// Split the string, and decode each action
+	String[] parts = decode.split(";");
+	for (int i = 0; i < parts.length; i++) {
+	    decode = parts[i];
+	    if ((decode == null) || decode.isEmpty())
+		continue;
+	    FlowEntryAction flowEntryAction = null;
+	    try {
+		flowEntryAction = new FlowEntryAction(decode);
+	    } catch (IllegalArgumentException e) {
+		// TODO: Ignore invalid actions for now
+		continue;
+	    }
+	    if (flowEntryAction != null)
+		actions.add(flowEntryAction);
+	}
+    }
+}
diff --git a/src/main/java/net/onrc/onos/ofcontroller/util/FlowPath.java b/src/main/java/net/onrc/onos/ofcontroller/util/FlowPath.java
index 8acc2e9..153e184 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/util/FlowPath.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/util/FlowPath.java
@@ -19,6 +19,8 @@
     private DataPath dataPath;		// The data path
     private FlowEntryMatch flowEntryMatch; // Common Flow Entry Match for all
 					// Flow Entries
+    private FlowEntryActions flowEntryActions; // The Flow Entry Actions for
+					// the first Flow Entry
 
     /**
      * Default constructor.
@@ -26,6 +28,7 @@
     public FlowPath() {
 	flowPathFlags = new FlowPathFlags();
 	dataPath = new DataPath();
+	flowEntryActions = new FlowEntryActions();
     }
 
     /**
@@ -82,6 +85,19 @@
     	    this.setFlowEntryMatch(match);
 	}
 
+	//
+	// Extract the actions for the first Flow Entry
+	//
+	{
+	    FlowEntryActions actions = new FlowEntryActions();
+
+	    String actionsStr = flowObj.getActions();
+	    if (actions != null)
+		actions = new FlowEntryActions(actionsStr);
+
+	    this.setFlowEntryActions(actions);
+	}
+
     	//
     	// Extract all Flow Entries
     	//
@@ -95,64 +111,77 @@
     	    // Extract the match conditions
     	    //
     	    FlowEntryMatch match = new FlowEntryMatch();
+	    //
     	    Short matchInPort = flowEntryObj.getMatchInPort();
     	    if (matchInPort != null)
     		match.enableInPort(new Port(matchInPort));
+	    //
     	    String matchSrcMac = flowEntryObj.getMatchSrcMac();
     	    if (matchSrcMac != null)
     		match.enableSrcMac(MACAddress.valueOf(matchSrcMac));
+	    //
     	    String matchDstMac = flowEntryObj.getMatchDstMac();
     	    if (matchDstMac != null)
     		match.enableDstMac(MACAddress.valueOf(matchDstMac));
+	    //
     	    Short matchEthernetFrameType = flowEntryObj.getMatchEthernetFrameType();
     	    if (matchEthernetFrameType != null)
     		match.enableEthernetFrameType(matchEthernetFrameType);
+	    //
     	    Short matchVlanId = flowEntryObj.getMatchVlanId();
     	    if (matchVlanId != null)
     		match.enableVlanId(matchVlanId);
+	    //
     	    Byte matchVlanPriority = flowEntryObj.getMatchVlanPriority();
     	    if (matchVlanPriority != null)
     		match.enableVlanPriority(matchVlanPriority);
+	    //
     	    String matchSrcIPv4Net = flowEntryObj.getMatchSrcIPv4Net();
     	    if (matchSrcIPv4Net != null)
     		match.enableSrcIPv4Net(new IPv4Net(matchSrcIPv4Net));
+	    //
     	    String matchDstIPv4Net = flowEntryObj.getMatchDstIPv4Net();
     	    if (matchDstIPv4Net != null)
     		match.enableDstIPv4Net(new IPv4Net(matchDstIPv4Net));
+	    //
     	    Byte matchIpProto = flowEntryObj.getMatchIpProto();
     	    if (matchIpProto != null)
     		match.enableIpProto(matchIpProto);
+	    //
     	    Byte matchIpToS = flowEntryObj.getMatchIpToS();
     	    if (matchIpToS != null)
     		match.enableIpToS(matchIpToS);
+	    //
     	    Short matchSrcTcpUdpPort = flowEntryObj.getMatchSrcTcpUdpPort();
     	    if (matchSrcTcpUdpPort != null)
     		match.enableSrcTcpUdpPort(matchSrcTcpUdpPort);
+	    //
     	    Short matchDstTcpUdpPort = flowEntryObj.getMatchDstTcpUdpPort();
     	    if (matchDstTcpUdpPort != null)
     		match.enableDstTcpUdpPort(matchDstTcpUdpPort);
+	    //
     	    flowEntry.setFlowEntryMatch(match);
 
-    	    //
-    	    // Extract the actions
-    	    //
-    	    ArrayList<FlowEntryAction> actions = new ArrayList<FlowEntryAction>();
-    	    Short actionOutputPort = flowEntryObj.getActionOutputPort();
-    	    if (actionOutputPort != null) {
-    		FlowEntryAction action = new FlowEntryAction();
-    		action.setActionOutput(new Port(actionOutputPort));
-    		actions.add(action);
-    	    }
-    	    flowEntry.setFlowEntryActions(actions);
+	    //
+	    // Extract the actions
+	    //
+	    {
+		FlowEntryActions actions = new FlowEntryActions();
+
+		String actionsStr = flowObj.getActions();
+		if (actions != null)
+		    actions = new FlowEntryActions(actionsStr);
+
+		flowEntry.setFlowEntryActions(actions);
+	    }
 
     	    String userState = flowEntryObj.getUserState();
     	    flowEntry.setFlowEntryUserState(FlowEntryUserState.valueOf(userState));
     	    String switchState = flowEntryObj.getSwitchState();
     	    flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.valueOf(switchState));
-    	    //
-    	    // TODO: Take care of the FlowEntryMatch, FlowEntryAction set,
-    	    // and FlowEntryErrorState.
-    	    //
+	    //
+	    // TODO: Take care of the FlowEntryErrorState.
+	    //
     	    this.dataPath().flowEntries().add(flowEntry);
     	}
     }
@@ -249,10 +278,32 @@
     }
 
     /**
+     * Get the flow path's flow entry actions for the first Flow Entry.
+     *
+     * @return the flow path's flow entry actions for the first Flow Entry.
+     */
+    @JsonProperty("flowEntryActions")
+    public FlowEntryActions flowEntryActions() {
+	return flowEntryActions;
+    }
+
+    /**
+     * Set the flow path's flow entry actions for the first Flow Entry.
+     *
+     * @param flowEntryActions the flow path's flow entry actions for the first
+     * Flow Entry.
+     */
+    @JsonProperty("flowEntryActions")
+    public void setFlowEntryActions(FlowEntryActions flowEntryActions) {
+	this.flowEntryActions = flowEntryActions;
+    }
+
+    /**
      * Convert the flow path to a string.
      *
      * The string has the following form:
-     *  [flowId=XXX installerId=XXX flowPathFlags=XXX dataPath=XXX]
+     *  [flowId=XXX installerId=XXX flowPathFlags=XXX dataPath=XXX
+     *   flowEntryMatch=XXX flowEntryActions=XXX]
      *
      * @return the flow path as a string.
      */
@@ -265,6 +316,8 @@
 	    ret += " dataPath=" + this.dataPath.toString();
 	if (flowEntryMatch != null)
 	    ret += " flowEntryMatch=" + this.flowEntryMatch.toString();
+	if (flowEntryActions != null)
+	    ret += " flowEntryActions=" + this.flowEntryActions.toString();
 	ret += "]";
 	return ret;
     }
@@ -276,5 +329,4 @@
     public int compareTo(FlowPath f) {
     	return (int) (this.flowId.value() - f.flowId.value());
     }
-
 }
diff --git a/src/main/java/net/onrc/onos/ofcontroller/util/IPv4.java b/src/main/java/net/onrc/onos/ofcontroller/util/IPv4.java
index 2081bbe..119165c 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/util/IPv4.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/util/IPv4.java
@@ -22,6 +22,15 @@
     }
 
     /**
+     * Copy constructor.
+     *
+     * @param other the object to copy from.
+     */
+    public IPv4(IPv4 other) {
+	this.value = other.value;
+    }
+
+    /**
      * Constructor from an integer value.
      *
      * @param value the value to use.
diff --git a/src/main/java/net/onrc/onos/ofcontroller/util/IPv4Net.java b/src/main/java/net/onrc/onos/ofcontroller/util/IPv4Net.java
index 52e6535..9ce247c 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/util/IPv4Net.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/util/IPv4Net.java
@@ -23,6 +23,17 @@
     }
 
     /**
+     * Copy constructor.
+     *
+     * @param other the object to copy from.
+     */
+    public IPv4Net(IPv4Net other) {
+	if (other.address != null)
+	    this.address = new IPv4(other.address);
+	this.prefixLen = other.prefixLen;
+    }
+
+    /**
      * Constructor for a given address and prefix length.
      *
      * @param address the address to use.
diff --git a/src/main/java/net/onrc/onos/ofcontroller/util/IPv6.java b/src/main/java/net/onrc/onos/ofcontroller/util/IPv6.java
index 2d28db8..f5dae11 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/util/IPv6.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/util/IPv6.java
@@ -25,6 +25,16 @@
     }
 
     /**
+     * Copy constructor.
+     *
+     * @param other the object to copy from.
+     */
+    public IPv6(IPv6 other) {
+	this.valueHigh = other.valueHigh;
+	this.valueLow = other.valueLow;
+    }
+
+    /**
      * Constructor from integer values.
      *
      * @param valueHigh the higher (more significant) 64 bits of the address.
diff --git a/src/main/java/net/onrc/onos/ofcontroller/util/IPv6Net.java b/src/main/java/net/onrc/onos/ofcontroller/util/IPv6Net.java
index bafff24..65ffe54 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/util/IPv6Net.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/util/IPv6Net.java
@@ -23,6 +23,17 @@
     }
 
     /**
+     * Copy constructor.
+     *
+     * @param other the object to copy from.
+     */
+    public IPv6Net(IPv6Net other) {
+	if (other.address != null)
+	    this.address = new IPv6(other.address);
+	this.prefixLen = other.prefixLen;
+    }
+
+    /**
      * Constructor for a given address and prefix length.
      *
      * @param address the address to use.
diff --git a/src/main/java/net/onrc/onos/ofcontroller/util/Port.java b/src/main/java/net/onrc/onos/ofcontroller/util/Port.java
index 34c807d..bb4851c 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/util/Port.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/util/Port.java
@@ -78,9 +78,9 @@
     }
 
     /**
-     * Constructor from another entry.
+     * Copy constructor.
      *
-     * @param other the other entry to use.
+     * @param other the object to copy from.
      */
     public Port(Port other) {
 	this.value = other.value();
diff --git a/src/test/java/net/onrc/onos/ofcontroller/core/internal/TestableGraphDBOperation.java b/src/test/java/net/onrc/onos/ofcontroller/core/internal/TestableGraphDBOperation.java
index dd21a26..bcff36a 100644
--- a/src/test/java/net/onrc/onos/ofcontroller/core/internal/TestableGraphDBOperation.java
+++ b/src/test/java/net/onrc/onos/ofcontroller/core/internal/TestableGraphDBOperation.java
@@ -425,6 +425,7 @@
 		private String matchSrcIpaddr,matchDstIpaddr;
 		private Byte matchIpProto, matchIpToS;
 		private Short matchSrcTcpUdpPort, matchDstTcpUdpPort;
+		private String actions;
 		
 		private List<IFlowEntry> entries;
 		private List<ISwitchObject> switches;
@@ -440,6 +441,7 @@
 		private String matchSrcIpaddrToUpdate,matchDstIpaddrToUpdate;
 		private Byte matchIpProtoToUpdate, matchIpToSToUpdate;
 		private Short matchSrcTcpUdpPortToUpdate, matchDstTcpUdpPortToUpdate;
+		private String actionsToUpdate;
 
 		private List<IFlowEntry> flowsToAdd;
 		private List<IFlowEntry> flowsToRemove;
@@ -485,6 +487,7 @@
 			if(matchIpToSToUpdate != null) { matchIpToS = matchIpToSToUpdate; }
 			if(matchSrcTcpUdpPortToUpdate != null) { matchSrcTcpUdpPort = matchSrcTcpUdpPortToUpdate; }
 			if(matchDstTcpUdpPortToUpdate != null) { matchDstTcpUdpPort = matchDstTcpUdpPortToUpdate; }
+			if(actionsToUpdate != null) { actions = actionsToUpdate; }
 		}
 		
 		public void rollback() {
@@ -506,6 +509,7 @@
 			matchSrcIpaddrToUpdate = matchDstIpaddrToUpdate = null;
 			matchIpProtoToUpdate = matchIpToSToUpdate = null;
 			matchSrcTcpUdpPortToUpdate = matchDstTcpUdpPortToUpdate = null;
+			actionsToUpdate = null;
 		}
 		
 		// Setter methods for test
@@ -531,6 +535,7 @@
 		public void setMatchIpToSForTest(Byte matchIpToS) { this.matchIpToS = matchIpToS; }
 		public void setMatchSrcTcpUdpPortForTest(Short matchSrcTcpUdpPort) { this.matchSrcTcpUdpPort = matchSrcTcpUdpPort; }
 		public void setMatchDstTcpUdpPortForTest(Short matchDstTcpUdpPort) { this.matchDstTcpUdpPort = matchDstTcpUdpPort; }
+		public void setActionsForTest(String actions) { this.actions = actions; }
 		public void addFlowEntryForTest(IFlowEntry entry) { entries.add(entry); }
 		public void addSwitchForTest(ISwitchObject sw) { switches.add(sw); }
 
@@ -693,6 +698,13 @@
 			matchDstTcpUdpPortToUpdate = matchDstTcpUdpPort; }
 
 		@Override
+		public String getActions() { return actions; }
+
+		@Override
+		public void setActions(String actions) {
+			actionsToUpdate = actions; }
+
+		@Override
 		public Iterable<ISwitchObject> getSwitches() { return switches; }
 
 		@Override
@@ -713,6 +725,7 @@
 		private Byte matchIpProto, matchIpToS;
 		private Short matchSrcTcpUdpPort, matchDstTcpUdpPort;
 		private Short actionOutputPort;
+		private String actions;
 		
 		private IFlowPath flowPath;
 		private ISwitchObject sw;
@@ -729,6 +742,7 @@
 		private Byte matchIpProtoToUpdate, matchIpToSToUpdate;
 		private Short matchSrcTcpUdpPortToUpdate, matchDstTcpUdpPortToUpdate;
 		private Short actionOutputPortToUpdate;
+		private String actionsToUpdate;
 	
 		private IFlowPath flowPathToUpdate;
 		private ISwitchObject swToUpdate;
@@ -762,6 +776,7 @@
 			if(matchSrcTcpUdpPortToUpdate != null) { matchSrcTcpUdpPort = matchSrcTcpUdpPortToUpdate; }
 			if(matchDstTcpUdpPortToUpdate != null) { matchDstTcpUdpPort = matchDstTcpUdpPortToUpdate; }
 			if(actionOutputPortToUpdate != null) { actionOutputPort = actionOutputPortToUpdate; }
+			if(actionsToUpdate != null) { actions = actionsToUpdate; }
 			
 			if(flowPathToUpdate != null) { flowPath = flowPathToUpdate; }
 			if(swToUpdate != null) { sw = swToUpdate; }
@@ -787,6 +802,7 @@
 			matchIpProtoToUpdate = matchIpToSToUpdate = null;
 			matchSrcTcpUdpPortToUpdate = matchDstTcpUdpPortToUpdate = null;
 			actionOutputPortToUpdate = null;
+			actionsToUpdate = null;
 			flowPathToUpdate = null;
 			swToUpdate = null;
 			inportToUpdate = outportToUpdate = null;
@@ -814,6 +830,7 @@
 		public void setMatchSrcTcpUdpPortForTest(Short matchSrcTcpUdpPort) { this.matchSrcTcpUdpPort = matchSrcTcpUdpPort; }
 		public void setMatchDstTcpUdpPortForTest(Short matchDstTcpUdpPort) { this.matchDstTcpUdpPort = matchDstTcpUdpPort; }
 		public void setActionOutputPortForTest(Short actionOutputPort) { this.actionOutputPort = actionOutputPort; }
+		public void setActionsForTest(String actions) { this.actions = actions; }
 		public void setFlowPathForTest(IFlowPath flowPath) { this.flowPath = flowPath; }
 		public void setSwitchForTest(ISwitchObject sw) { this.sw = sw; }
 		public void setInportForTest(IPortObject inport) { this.inport = inport; }
@@ -950,6 +967,12 @@
 	
 		@Override
 		public void setActionOutputPort(Short actionOutputPort) { actionOutputPortToUpdate = actionOutputPort; }
+
+		@Override
+		public String getActions() { return actions; }
+	
+		@Override
+		public void setActions(String actions) { actionsToUpdate = actions; }
 	
 		@Override
 		public IFlowPath getFlow() { return flowPath; }
diff --git a/src/test/java/net/onrc/onos/ofcontroller/flowmanager/FlowManagerTest.java b/src/test/java/net/onrc/onos/ofcontroller/flowmanager/FlowManagerTest.java
index 9f197a7..7bc0aac 100644
--- a/src/test/java/net/onrc/onos/ofcontroller/flowmanager/FlowManagerTest.java
+++ b/src/test/java/net/onrc/onos/ofcontroller/flowmanager/FlowManagerTest.java
@@ -1086,7 +1086,7 @@
 		flowEntry1.setOutPort(new Port((short) 11));
 		flowEntry1.setFlowEntryId(new FlowEntryId(1));
 		flowEntry1.setFlowEntryMatch(new FlowEntryMatch());
-		flowEntry1.setFlowEntryActions(new ArrayList<FlowEntryAction>());
+		flowEntry1.setFlowEntryActions(new FlowEntryActions());
 		flowEntry1.setFlowEntryErrorState(new FlowEntryErrorState());
 		
 		FlowEntry flowEntry2 = new FlowEntry();
@@ -1096,7 +1096,7 @@
 		flowEntry2.setOutPort(new Port((short) 2));
 		flowEntry2.setFlowEntryId(new FlowEntryId(2));
 		flowEntry2.setFlowEntryMatch(new FlowEntryMatch());
-		flowEntry2.setFlowEntryActions(new ArrayList<FlowEntryAction>());
+		flowEntry2.setFlowEntryActions(new FlowEntryActions());
 		flowEntry2.setFlowEntryErrorState(new FlowEntryErrorState());
 		
 		DataPath dataPath = new DataPath();
@@ -1147,6 +1147,11 @@
 		// instantiate required objects
 		FlowManager fm = new FlowManager();
 		
+		FlowEntryAction action = new FlowEntryAction();
+		action.setActionOutput(new Port((short)2));
+		FlowEntryActions actions = new FlowEntryActions();
+		actions.addAction(action);
+
 		// setup expectations
 		expectInitWithContext();
 		expect(iFlowEntry.getFlowEntryId()).andReturn(new FlowEntryId(123).toString());
@@ -1164,7 +1169,7 @@
 		expect(iFlowEntry.getMatchIpToS()).andReturn(new Byte((byte)0x3));
 		expect(iFlowEntry.getMatchSrcTcpUdpPort()).andReturn(new Short((short)40000));
 		expect(iFlowEntry.getMatchDstTcpUdpPort()).andReturn(new Short((short)80));
-		expect(iFlowEntry.getActionOutputPort()).andReturn(new Short((short) 2));
+		expect(iFlowEntry.getActions()).andReturn(actions.toString());
 		expect(floodlightProvider.getOFMessageFactory()).andReturn(basicFactory);
 		expect(basicFactory.getMessage(OFType.FLOW_MOD)).andReturn(new OFFlowMod());
 		expect(iofSwitch.getStringId()).andReturn(new Dpid(100).toString());
diff --git a/start-onos.sh b/start-onos.sh
index 13ea0ac..a35d181 100755
--- a/start-onos.sh
+++ b/start-onos.sh
@@ -16,6 +16,8 @@
 
 # Set JVM options
 JVM_OPTS=""
+## If you want JaCoCo Code Coverage reports... uncomment line below
+JVM_OPTS="$JVM_OPTS -javaagent:${ONOS_HOME}/lib/jacocoagent.jar=dumponexit=true,output=file,destfile=${LOGDIR}/jacoco.exec"
 JVM_OPTS="$JVM_OPTS -server -d64"
 #JVM_OPTS="$JVM_OPTS -Xmx2g -Xms2g -Xmn800m"
 JVM_OPTS="$JVM_OPTS -Xmx1g -Xms1g -Xmn800m"
@@ -134,7 +136,7 @@
   pids="$flpid $tdpid"
   for p in ${pids}; do
     if [ x$p != "x" ]; then
-      kill -KILL $p
+      kill -TERM $p
       echo "Killed existing process (pid: $p)"
     fi
   done
diff --git a/web/add_flow.py b/web/add_flow.py
index 9ecb102..8100f22 100755
--- a/web/add_flow.py
+++ b/web/add_flow.py
@@ -204,18 +204,19 @@
       match['dstTcpUdpPort'] = int(arg2, 0)
       # match['matchDstTcpUdpPort'] = True
     elif arg1 == "actionOutput":
-      # Just mark whether ACTION_OUTPUT action is enabled
+      # Mark whether ACTION_OUTPUT action is enabled
       actionOutputEnabled = arg2 in ['True', 'true']
-      #
-      # TODO: Complete the implementation for ACTION_OUTPUT
-      #   actionOutput = {}
-      #   outPort = {}
-      #   outPort['value'] = int(arg2, 0)
-      #   actionOutput['port'] = outPort
-      #   actionOutput['maxLen'] = int(arg3, 0)
-      #   action['actionOutput'] = actionOutput
-      #   # action['actionType'] = 'ACTION_OUTPUT'
-      #   actions.append(action)
+      # If ACTION_OUTPUT is explicitly enabled, add an entry with a fake
+      # port number. We need this entry to preserve the action ordering.
+      if actionOutputEnabled == True:
+        actionOutput = {}
+        outPort = {}
+        outPort['value'] = 0xffff
+        actionOutput['port'] = outPort
+        actionOutput['maxLen'] = 0
+        action['actionOutput'] = actionOutput
+        # action['actionType'] = 'ACTION_OUTPUT'
+        actions.append(action)
       #
     elif arg1 == "actionSetVlanId":
       vlanId = {}
@@ -346,6 +347,8 @@
   flowPathFlags = {}
   flowPathFlags['flags'] = myFlowPathFlags
 
+  flowEntryActions = {}
+
   flow_path = {}
   flow_path['flowId'] = flow_id
   flow_path['installerId'] = installer_id
@@ -367,6 +370,11 @@
       my_data_path['flowEntries'][idx]['flowEntryMatch'] = copy.deepcopy(match)
       idx = idx + 1
 
+
+  if (len(actions) > 0):
+    flowEntryActions['actions'] = copy.deepcopy(actions)
+    flow_path['flowEntryActions'] = flowEntryActions
+
   #
   # Set the actions for each flow entry
   # NOTE: The actions from the command line are aplied
@@ -388,11 +396,12 @@
       action['actionOutput'] = copy.deepcopy(actionOutput)
       # action['actionType'] = 'ACTION_OUTPUT'
       actions.append(copy.deepcopy(action))
+      flowEntryActions = {}
+      flowEntryActions['actions'] = copy.deepcopy(actions)
 
-      my_data_path['flowEntries'][idx]['flowEntryActions'] = copy.deepcopy(actions)
+      my_data_path['flowEntries'][idx]['flowEntryActions'] = flowEntryActions
       idx = idx + 1
 
-
   flow_path['dataPath'] = my_data_path
   debug("Flow Path: %s" % flow_path)
   return flow_path
@@ -516,6 +525,7 @@
   usage_msg = usage_msg + "        actionSetIpToS <IP ToS (DSCP field, 6 bits)>\n"
   usage_msg = usage_msg + "        actionSetTcpUdpSrcPort <source TCP/UDP port>\n"
   usage_msg = usage_msg + "        actionSetTcpUdpDstPort <destination TCP/UDP port>\n"
+  usage_msg = usage_msg + "    Actions (not implemented yet):\n"
   usage_msg = usage_msg + "        actionEnqueue <dummy argument>\n"
 
   # app.debug = False;
diff --git a/web/get_flow.py b/web/get_flow.py
index 6599360..9ab55da 100755
--- a/web/get_flow.py
+++ b/web/get_flow.py
@@ -33,6 +33,131 @@
 # Sample output:
 # {"flowId":{"value":"0x5"},"installerId":{"value":"FOOBAR"},"dataPath":{"srcPort":{"dpid":{"value":"00:00:00:00:00:00:00:01"},"port":{"value":0}},"dstPort":{"dpid":{"value":"00:00:00:00:00:00:00:02"},"port":{"value":0}},"flowEntries":[{"flowEntryId":"0x1389","flowEntryMatch":null,"flowEntryActions":null,"dpid":{"value":"00:00:00:00:00:00:00:01"},"inPort":{"value":0},"outPort":{"value":1},"flowEntryUserState":"FE_USER_DELETE","flowEntrySwitchState":"FE_SWITCH_NOT_UPDATED","flowEntryErrorState":null},{"flowEntryId":"0x138a","flowEntryMatch":null,"flowEntryActions":null,"dpid":{"value":"00:00:00:00:00:00:00:02"},"inPort":{"value":9},"outPort":{"value":0},"flowEntryUserState":"FE_USER_DELETE","flowEntrySwitchState":"FE_SWITCH_NOT_UPDATED","flowEntryErrorState":null}]}}
 
+def parse_match(match):
+  result = []
+
+  inPort = match['inPort']
+  matchInPort = match['matchInPort']
+  srcMac = match['srcMac']
+  matchSrcMac = match['matchSrcMac']
+  dstMac = match['dstMac']
+  matchDstMac = match['matchDstMac']
+  ethernetFrameType = match['ethernetFrameType']
+  matchEthernetFrameType = match['matchEthernetFrameType']
+  vlanId = match['vlanId']
+  matchVlanId = match['matchVlanId']
+  vlanPriority = match['vlanPriority']
+  matchVlanPriority = match['matchVlanPriority']
+  srcIPv4Net = match['srcIPv4Net']
+  matchSrcIPv4Net = match['matchSrcIPv4Net']
+  dstIPv4Net = match['dstIPv4Net']
+  matchDstIPv4Net = match['matchDstIPv4Net']
+  ipProto = match['ipProto']
+  matchIpProto = match['matchIpProto']
+  ipToS = match['ipToS']
+  matchIpToS = match['matchIpToS']
+  srcTcpUdpPort = match['srcTcpUdpPort']
+  matchSrcTcpUdpPort = match['matchSrcTcpUdpPort']
+  dstTcpUdpPort = match['dstTcpUdpPort']
+  matchDstTcpUdpPort = match['matchDstTcpUdpPort']
+  if matchInPort == True:
+    r = "inPort: %s" % inPort['value']
+    result.append(r)
+  if matchSrcMac == True:
+    r = "srcMac: %s" % srcMac['value']
+    result.append(r)
+  if matchDstMac == True:
+    r = "dstMac: %s" % dstMac['value']
+    result.append(r)
+  if matchEthernetFrameType == True:
+    r = "ethernetFrameType: %s" % hex(ethernetFrameType)
+    result.append(r)
+  if matchVlanId == True:
+    r = "vlanId: %s" % vlanId
+    result.append(r)
+  if matchVlanPriority == True:
+    r = "vlanPriority: %s" % vlanPriority
+    result.append(r)
+  if matchSrcIPv4Net == True:
+    r = "srcIPv4Net: %s" % srcIPv4Net['value']
+    result.append(r)
+  if matchDstIPv4Net == True:
+    r = "dstIPv4Net: %s" % dstIPv4Net['value']
+    result.append(r)
+  if matchIpProto == True:
+    r = "ipProto: %s" % ipProto
+    result.append(r)
+  if matchIpToS == True:
+    r = "ipToS: %s" % ipToS
+    result.append(r)
+  if matchSrcTcpUdpPort == True:
+    r = "srcTcpUdpPort: %s" % srcTcpUdpPort
+    result.append(r)
+  if matchDstTcpUdpPort == True:
+    r = "dstTcpUdpPort: %s" % dstTcpUdpPort
+    result.append(r)
+
+  return result
+
+
+def parse_actions(actions):
+  result = []
+  for a in actions:
+    actionType = a['actionType']
+    if actionType == "ACTION_OUTPUT":
+      port = a['actionOutput']['port']['value']
+      maxLen = a['actionOutput']['maxLen']
+      r = "actionType: %s port: %s maxLen: %s" % (actionType, port, maxLen)
+      result.append(r)
+    if actionType == "ACTION_SET_VLAN_VID":
+      vlanId = a['actionSetVlanId']['vlanId']
+      r = "actionType: %s vlanId: %s" % (actionType, vlanId)
+      result.append(r)
+    if actionType == "ACTION_SET_VLAN_PCP":
+      vlanPriority = a['actionSetVlanPriority']['vlanPriority']
+      r = "actionType: %s vlanPriority: %s" % (actionType, vlanPriority)
+      result.append(r)
+    if actionType == "ACTION_STRIP_VLAN":
+      stripVlan = a['actionStripVlan']['stripVlan']
+      r = "actionType: %s stripVlan: %s" % (actionType, stripVlan)
+      result.append(r)
+    if actionType == "ACTION_SET_DL_SRC":
+      setEthernetSrcAddr = a['actionSetEthernetSrcAddr']['addr']['value']
+      r = "actionType: %s setEthernetSrcAddr: %s" % (actionType, setEthernetSrcAddr)
+      result.append(r)
+    if actionType == "ACTION_SET_DL_DST":
+      setEthernetDstAddr = a['actionSetEthernetDstAddr']['addr']['value']
+      r = "actionType: %s setEthernetDstAddr: %s" % (actionType, setEthernetDstAddr)
+      result.append(r)
+    if actionType == "ACTION_SET_NW_SRC":
+      setIPv4SrcAddr = a['actionSetIPv4SrcAddr']['addr']['value']
+      r = "actionType: %s setIPv4SrcAddr: %s" % (actionType, setIPv4SrcAddr)
+      result.append(r)
+    if actionType == "ACTION_SET_NW_DST":
+      setIPv4DstAddr = a['actionSetIPv4DstAddr']['addr']['value']
+      r = "actionType: %s setIPv4DstAddr: %s" % (actionType, setIPv4DstAddr)
+      result.append(r)
+    if actionType == "ACTION_SET_NW_TOS":
+      setIpToS = a['actionSetIpToS']['ipToS']
+      r = "actionType: %s setIpToS: %s" % (actionType, setIpToS)
+      result.append(r)
+    if actionType == "ACTION_SET_TP_SRC":
+      setTcpUdpSrcPort = a['actionSetTcpUdpSrcPort']['port']
+      r = "actionType: %s setTcpUdpSrcPort: %s" % (actionType, setTcpUdpSrcPort)
+      result.append(r)
+    if actionType == "ACTION_SET_TP_DST":
+      setTcpUdpDstPort = a['actionSetTcpUdpDstPort']['port']
+      r = "actionType: %s setTcpUdpDstPort: %s" % (actionType, setTcpUdpDstPort)
+      result.append(r)
+    if actionType == "ACTION_ENQUEUE":
+      port = a['actionEnqueue']['port']['value']
+      queueId = a['actionEnqueue']['queueId']
+      r = "actionType: %s port: %s queueId: %s" % (actionType, port, queueId)
+      result.append(r)
+
+  return result
+
+
 def print_flow_path(parsedResult):
   flowId = parsedResult['flowId']['value']
   installerId = parsedResult['installerId']['value']
@@ -41,6 +166,8 @@
   srcPort = parsedResult['dataPath']['srcPort']['port']['value']
   dstSwitch = parsedResult['dataPath']['dstPort']['dpid']['value']
   dstPort = parsedResult['dataPath']['dstPort']['port']['value']
+  match = parsedResult['flowEntryMatch'];
+  actions = parsedResult['flowEntryActions']['actions']
 
   flowPathFlagsStr = ""
   if (flowPathFlags & 0x1):
@@ -53,69 +180,35 @@
     flowPathFlagsStr += "KEEP_ONLY_FIRST_HOP_ENTRY"
 
   print "FlowPath: (flowId = %s installerId = %s flowPathFlags = 0x%x(%s) src = %s/%s dst = %s/%s)" % (flowId, installerId, flowPathFlags, flowPathFlagsStr, srcSwitch, srcPort, dstSwitch, dstPort)
-  match = parsedResult['flowEntryMatch'];
+
   #
-  # Print the common conditions
+  # Print the common match conditions
   #
   if match == None:
     print "   Match: %s" % (match)
   else:
-    # inPort = match['inPort']
-    # matchInPort = match['matchInPort']
-    srcMac = match['srcMac']
-    matchSrcMac = match['matchSrcMac']
-    dstMac = match['dstMac']
-    matchDstMac = match['matchDstMac']
-    ethernetFrameType = match['ethernetFrameType']
-    matchEthernetFrameType = match['matchEthernetFrameType']
-    vlanId = match['vlanId']
-    matchVlanId = match['matchVlanId']
-    vlanPriority = match['vlanPriority']
-    matchVlanPriority = match['matchVlanPriority']
-    srcIPv4Net = match['srcIPv4Net']
-    matchSrcIPv4Net = match['matchSrcIPv4Net']
-    dstIPv4Net = match['dstIPv4Net']
-    matchDstIPv4Net = match['matchDstIPv4Net']
-    ipProto = match['ipProto']
-    matchIpProto = match['matchIpProto']
-    ipToS = match['ipToS']
-    matchIpToS = match['matchIpToS']
-    srcTcpUdpPort = match['srcTcpUdpPort']
-    matchSrcTcpUdpPort = match['matchSrcTcpUdpPort']
-    dstTcpUdpPort = match['dstTcpUdpPort']
-    matchDstTcpUdpPort = match['matchDstTcpUdpPort']
-    # if matchInPort == True:
-    #  print "    inPort: %s" % inPort['value']
-    if matchSrcMac == True:
-      print "    srcMac: %s" % srcMac['value']
-    if matchDstMac == True:
-      print "    dstMac: %s" % dstMac['value']
-    if matchEthernetFrameType == True:
-      print "    ethernetFrameType: %s" % hex(ethernetFrameType)
-    if matchVlanId == True:
-      print "    vlanId: %s" % vlanId
-    if matchVlanPriority == True:
-      print "    vlanPriority: %s" % vlanPriority
-    if matchSrcIPv4Net == True:
-      print "    srcIPv4Net: %s" % srcIPv4Net['value']
-    if matchDstIPv4Net == True:
-      print "    dstIPv4Net: %s" % dstIPv4Net['value']
-    if matchIpProto == True:
-      print "    ipProto: %s" % ipProto
-    if matchIpToS == True:
-      print "    ipToS: %s" % ipToS
-    if matchSrcTcpUdpPort == True:
-      print "    srcTcpUdpPort: %s" % srcTcpUdpPort
-    if matchDstTcpUdpPort == True:
-      print "    dstTcpUdpPort: %s" % dstTcpUdpPort
+    parsedMatch = parse_match(match)
+    for l in parsedMatch:
+      print "    %s" % l
 
+  #
+  # Print the actions
+  #
+  parsedActions = parse_actions(actions)
+  for l in parsedActions:
+    print "    %s" % l
+
+  #
+  # Print each Flow Entry
+  #
   for f in parsedResult['dataPath']['flowEntries']:
     flowEntryId = f['flowEntryId']
     dpid = f['dpid']['value']
     userState = f['flowEntryUserState']
     switchState = f['flowEntrySwitchState']
     match = f['flowEntryMatch'];
-    actions = f['flowEntryActions']
+    actions = f['flowEntryActions']['actions']
+
     print "  FlowEntry: (%s, %s, %s, %s)" % (flowEntryId, dpid, userState, switchState)
 
     #
@@ -124,101 +217,16 @@
     if match == None:
       print "   Match: %s" % (match)
     else:
-      inPort = match['inPort']
-      matchInPort = match['matchInPort']
-      srcMac = match['srcMac']
-      matchSrcMac = match['matchSrcMac']
-      dstMac = match['dstMac']
-      matchDstMac = match['matchDstMac']
-      ethernetFrameType = match['ethernetFrameType']
-      matchEthernetFrameType = match['matchEthernetFrameType']
-      vlanId = match['vlanId']
-      matchVlanId = match['matchVlanId']
-      vlanPriority = match['vlanPriority']
-      matchVlanPriority = match['matchVlanPriority']
-      srcIPv4Net = match['srcIPv4Net']
-      matchSrcIPv4Net = match['matchSrcIPv4Net']
-      dstIPv4Net = match['dstIPv4Net']
-      matchDstIPv4Net = match['matchDstIPv4Net']
-      ipProto = match['ipProto']
-      matchIpProto = match['matchIpProto']
-      ipToS = match['ipToS']
-      matchIpToS = match['matchIpToS']
-      srcTcpUdpPort = match['srcTcpUdpPort']
-      matchSrcTcpUdpPort = match['matchSrcTcpUdpPort']
-      dstTcpUdpPort = match['dstTcpUdpPort']
-      matchDstTcpUdpPort = match['matchDstTcpUdpPort']
-      if matchInPort == True:
-	print "    inPort: %s" % inPort['value']
-      if matchSrcMac == True:
-	print "    srcMac: %s" % srcMac['value']
-      if matchDstMac == True:
-	print "    dstMac: %s" % dstMac['value']
-      if matchEthernetFrameType == True:
-	print "    ethernetFrameType: %s" % hex(ethernetFrameType)
-      if matchVlanId == True:
-	print "    vlanId: %s" % vlanId
-      if matchVlanPriority == True:
-	print "    vlanPriority: %s" % vlanPriority
-      if matchSrcIPv4Net == True:
-	print "    srcIPv4Net: %s" % srcIPv4Net['value']
-      if matchDstIPv4Net == True:
-	print "    dstIPv4Net: %s" % dstIPv4Net['value']
-      if matchIpProto == True:
-	print "    ipProto: %s" % ipProto
-      if matchIpToS == True:
-	print "    ipToS: %s" % ipToS
-      if matchSrcTcpUdpPort == True:
-	print "    srcTcpUdpPort: %s" % srcTcpUdpPort
-      if matchDstTcpUdpPort == True:
-	print "    dstTcpUdpPort: %s" % dstTcpUdpPort
-
+      parsedMatch = parse_match(match)
+      for l in parsedMatch:
+	print "    %s" % l
     #
     # Print the actions
     #
-    if actions == None:
-      print "   Actions: %s" % (actions)
-    else:
-      for a in actions:
-	actionType = a['actionType']
-	if actionType == "ACTION_OUTPUT":
-	  port = a['actionOutput']['port']['value']
-	  maxLen = a['actionOutput']['maxLen']
-	  print "    actionType: %s port: %s maxLen: %s" % (actionType, port, maxLen)
-	if actionType == "ACTION_SET_VLAN_VID":
-	  vlanId = a['actionSetVlanId']['vlanId']
-	  print "    actionType: %s vlanId: %s" % (actionType, vlanId)
-	if actionType == "ACTION_SET_VLAN_PCP":
-	  vlanPriority = a['actionSetVlanPriority']['vlanPriority']
-	  print "    actionType: %s vlanPriority: %s" % (actionType, vlanPriority)
-	if actionType == "ACTION_STRIP_VLAN":
-	  stripVlan = a['actionStripVlan']['stripVlan']
-	  print "    actionType: %s stripVlan: %s" % (actionType, stripVlan)
-	if actionType == "ACTION_SET_DL_SRC":
-	  setEthernetSrcAddr = a['actionSetEthernetSrcAddr']['addr']['value']
-	  print "    actionType: %s setEthernetSrcAddr: %s" % (actionType, setEthernetSrcAddr)
-	if actionType == "ACTION_SET_DL_DST":
-	  setEthernetDstAddr = a['actionSetEthernetDstAddr']['addr']['value']
-	  print "    actionType: %s setEthernetDstAddr: %s" % (actionType, setEthernetDstAddr)
-	if actionType == "ACTION_SET_NW_SRC":
-	  setIPv4SrcAddr = a['actionSetIPv4SrcAddr']['addr']['value']
-	  print "    actionType: %s setIPv4SrcAddr: %s" % (actionType, setIPv4SrcAddr)
-	if actionType == "ACTION_SET_NW_DST":
-	  setIPv4DstAddr = a['actionSetIPv4DstAddr']['addr']['value']
-	  print "    actionType: %s setIPv4DstAddr: %s" % (actionType, setIPv4DstAddr)
-	if actionType == "ACTION_SET_NW_TOS":
-	  setIpToS = a['actionSetIpToS']['ipToS']
-	  print "    actionType: %s setIpToS: %s" % (actionType, setIpToS)
-	if actionType == "ACTION_SET_TP_SRC":
-	  setTcpUdpSrcPort = a['actionSetTcpUdpSrcPort']['port']
-	  print "    actionType: %s setTcpUdpSrcPort: %s" % (actionType, setTcpUdpSrcPort)
-	if actionType == "ACTION_SET_TP_DST":
-	  setTcpUdpDstPort = a['actionSetTcpUdpDstPort']['port']
-	  print "    actionType: %s setTcpUdpDstPort: %s" % (actionType, setTcpUdpDstPort)
-	if actionType == "ACTION_ENQUEUE":
-	  port = a['actionEnqueue']['port']['value']
-	  queueId = a['actionEnqueue']['queueId']
-	  print "    actionType: %s port: %s queueId: %s" % (actionType, port, queueId)
+    parsedActions = parse_actions(actions)
+    for l in parsedActions:
+      print "    %s" % l
+
 
 def get_flow_path(flow_id):
   try:
diff --git a/web/measurement_store_flow.py b/web/measurement_store_flow.py
index ad0eadf..0e39465 100755
--- a/web/measurement_store_flow.py
+++ b/web/measurement_store_flow.py
@@ -87,7 +87,7 @@
       if "KEEP_ONLY_FIRST_HOP_ENTRY" in arg2:
 	flowPathFlags = flowPathFlags + 0x2
     elif arg1 == "matchInPort":
-      # Just mark whether inPort matching is enabled
+      # Mark whether ACTION_OUTPUT action is enabled
       matchInPortEnabled = arg2 in ['True', 'true']
       # inPort = {}
       # inPort['value'] = int(arg2, 0)
@@ -135,18 +135,19 @@
       match['dstTcpUdpPort'] = int(arg2, 0)
       # match['matchDstTcpUdpPort'] = True
     elif arg1 == "actionOutput":
-      # Just mark whether ACTION_OUTPUT action is enabled
+      # Mark whether ACTION_OUTPUT action is enabled
       actionOutputEnabled = arg2 in ['True', 'true']
-      #
-      # TODO: Complete the implementation for ACTION_OUTPUT
-      #   actionOutput = {}
-      #   outPort = {}
-      #   outPort['value'] = int(arg2, 0)
-      #   actionOutput['port'] = outPort
-      #   actionOutput['maxLen'] = int(arg3, 0)
-      #   action['actionOutput'] = actionOutput
-      #   # action['actionType'] = 'ACTION_OUTPUT'
-      #   actions.append(action)
+      # If ACTION_OUTPUT is explicitly enabled, add an entry with a fake
+      # port number. We need this entry to preserve the action ordering.
+      if actionOutputEnabled == True:
+        actionOutput = {}
+        outPort = {}
+        outPort['value'] = 0xffff
+        actionOutput['port'] = outPort
+        actionOutput['maxLen'] = 0
+        action['actionOutput'] = actionOutput
+        # action['actionType'] = 'ACTION_OUTPUT'
+        actions.append(action)
       #
     elif arg1 == "actionSetVlanId":
       vlanId = {}
@@ -264,6 +265,8 @@
   flowPathFlags = {}
   flowPathFlags['flags'] = myFlowPathFlags
 
+  flowEntryActions = {}
+
   flow_path = {}
   flow_path['flowId'] = flow_id
   flow_path['installerId'] = installer_id
@@ -285,6 +288,11 @@
       my_data_path['flowEntries'][idx]['flowEntryMatch'] = copy.deepcopy(match)
       idx = idx + 1
 
+
+  if (len(actions) > 0):
+    flowEntryActions['actions'] = copy.deepcopy(actions)
+    flow_path['flowEntryActions'] = flowEntryActions
+
   #
   # Set the actions for each flow entry
   # NOTE: The actions from the command line are aplied
@@ -306,11 +314,12 @@
       action['actionOutput'] = copy.deepcopy(actionOutput)
       # action['actionType'] = 'ACTION_OUTPUT'
       actions.append(copy.deepcopy(action))
+      flowEntryActions = {}
+      flowEntryActions['actions'] = copy.deepcopy(actions)
 
-      my_data_path['flowEntries'][idx]['flowEntryActions'] = copy.deepcopy(actions)
+      my_data_path['flowEntries'][idx]['flowEntryActions'] = flowEntryActions
       idx = idx + 1
 
-
   flow_path['dataPath'] = my_data_path
   debug("Flow Path: %s" % flow_path)
   return flow_path
@@ -396,6 +405,7 @@
   usage_msg = usage_msg + "        actionSetIpToS <IP ToS (DSCP field, 6 bits)>\n"
   usage_msg = usage_msg + "        actionSetTcpUdpSrcPort <source TCP/UDP port>\n"
   usage_msg = usage_msg + "        actionSetTcpUdpDstPort <destination TCP/UDP port>\n"
+  usage_msg = usage_msg + "    Actions (not implemented yet):\n"
   usage_msg = usage_msg + "        actionEnqueue <dummy argument>\n"
 
   # app.debug = False;
diff --git a/web/topology_rest.py b/web/topology_rest.py
index 53f46bc..ea33a00 100755
--- a/web/topology_rest.py
+++ b/web/topology_rest.py
@@ -216,19 +216,6 @@
   resp = Response(result, status=200, mimetype='application/json')
   return resp
 
-@app.route("/proxy/gui/switchctrl/<cmd>")
-def proxy_switch_controller_setting(cmd):
-  try:
-    command = "curl -s %s/gui/switchctrl/%s" % (ONOS_GUI3_CONTROL_HOST, cmd)
-    print command
-    result = os.popen(command).read()
-  except:
-    print "REST IF has issue"
-    exit
-
-  resp = Response(result, status=200, mimetype='application/json')
-  return resp
-
 @app.route("/proxy/gui/reset")
 def proxy_gui_reset():
   result = ""