static {
   FlowMod2 = new OFFlowMod();
   TestRule2 = new HashMap<String, Object>();
   TestRule2.put(COLUMN_NAME, "TestRule2");
   TestRule2.put(COLUMN_SWITCH, TestSwitch1DPID);
   // setup match
   OFMatch match = new OFMatch();
   TestRule2.put(COLUMN_NW_DST, "192.168.1.0/24");
   match.fromString("nw_dst=192.168.1.0/24");
   // setup actions
   List<OFAction> actions = new LinkedList<OFAction>();
   TestRule2.put(COLUMN_ACTIONS, "output=1");
   actions.add(new OFActionOutput((short) 1, (short) Short.MAX_VALUE));
   // done
   FlowMod2.setMatch(match);
   FlowMod2.setActions(actions);
   FlowMod2.setBufferId(-1);
   FlowMod2.setOutPort(OFPort.OFPP_NONE.getValue());
   FlowMod2.setPriority(Short.MAX_VALUE);
   FlowMod2.setLengthU(OFFlowMod.MINIMUM_LENGTH + 8); // 8 bytes of actions
 }
 static {
   FlowMod3 = new OFFlowMod();
   TestRule3 = new HashMap<String, Object>();
   TestRule3.put(COLUMN_NAME, "TestRule3");
   TestRule3.put(COLUMN_SWITCH, TestSwitch1DPID);
   // setup match
   OFMatch match = new OFMatch();
   TestRule3.put(COLUMN_DL_DST, "00:20:30:40:50:60");
   TestRule3.put(COLUMN_DL_VLAN, 4096);
   match.fromString("dl_dst=00:20:30:40:50:60,dl_vlan=4096");
   // setup actions
   TestRule3.put(COLUMN_ACTIONS, "output=controller");
   List<OFAction> actions = new LinkedList<OFAction>();
   actions.add(new OFActionOutput(OFPort.OFPP_CONTROLLER.getValue(), (short) Short.MAX_VALUE));
   // done
   FlowMod3.setMatch(match);
   FlowMod3.setActions(actions);
   FlowMod3.setBufferId(-1);
   FlowMod3.setOutPort(OFPort.OFPP_NONE.getValue());
   FlowMod3.setPriority(Short.MAX_VALUE);
   FlowMod3.setLengthU(OFFlowMod.MINIMUM_LENGTH + 8); // 8 bytes of actions
 }
  @Test
  public void testStaticFlowPush() throws IOException {
    StaticFlowEntryPusher staticFlowEntryPusher = new StaticFlowEntryPusher();
    IStorageSourceService storage = createStorageWithFlowEntries();
    long dpid = HexString.toLong(TestSwitch1DPID);

    // Create a Switch and attach a switch
    IOFSwitch mockSwitch = createNiceMock(IOFSwitch.class);
    Capture<OFMessage> writeCapture = new Capture<OFMessage>(CaptureType.ALL);
    Capture<ListenerContext> contextCapture = new Capture<ListenerContext>(CaptureType.ALL);
    Capture<List<OFMessage>> writeCaptureList = new Capture<List<OFMessage>>(CaptureType.ALL);

    // OFMessageSafeOutStream mockOutStream = createNiceMock(OFMessageSafeOutStream.class);
    mockSwitch.write(capture(writeCapture), capture(contextCapture));
    expectLastCall().anyTimes();
    mockSwitch.write(capture(writeCaptureList), capture(contextCapture));
    expectLastCall().anyTimes();
    mockSwitch.flush();
    expectLastCall().anyTimes();

    staticFlowEntryPusher.setStorageSource(storage);

    ModuleContext fmc = new ModuleContext();

    MockControllerProvider mockControllerProvider = getMockControllerProvider();
    Map<Long, IOFSwitch> switchMap = new HashMap<Long, IOFSwitch>();
    switchMap.put(dpid, mockSwitch);
    // NO ! expect(mockControllerProvider.getSwitches()).andReturn(switchMap).anyTimes();
    mockControllerProvider.setSwitches(switchMap);
    staticFlowEntryPusher.setControllerProvider(mockControllerProvider);
    RestApiServer restApi = new RestApiServer();
    try {
      restApi.init(fmc);
    } catch (ModuleException e) {
      e.printStackTrace();
    }
    staticFlowEntryPusher.restApi = restApi;
    staticFlowEntryPusher.startUp(null); // again, to hack unittest

    // verify that flowpusher read all three entries from storage
    assertEquals(TotalTestRules, staticFlowEntryPusher.countEntries());

    // if someone calls mockSwitch.getOutputStream(), return mockOutStream instead
    // expect(mockSwitch.getOutputStream()).andReturn(mockOutStream).anyTimes();

    // if someone calls getId(), return this dpid instead
    expect(mockSwitch.getId()).andReturn(dpid).anyTimes();
    expect(mockSwitch.getStringId()).andReturn(TestSwitch1DPID).anyTimes();
    replay(mockSwitch);

    // hook the static pusher up to the fake switch
    staticFlowEntryPusher.addedSwitch(mockSwitch);

    verify(mockSwitch);

    // Verify that the switch has gotten some flow_mods
    assertEquals(true, writeCapture.hasCaptured());
    assertEquals(TotalTestRules, writeCapture.getValues().size());

    // Order assumes how things are stored in hash bucket;
    // should be fixed because OFMessage.hashCode() is deterministic
    OFFlowMod firstFlowMod = (OFFlowMod) writeCapture.getValues().get(2);
    verifyFlowMod(firstFlowMod, FlowMod1);
    OFFlowMod secondFlowMod = (OFFlowMod) writeCapture.getValues().get(1);
    verifyFlowMod(secondFlowMod, FlowMod2);
    OFFlowMod thirdFlowMod = (OFFlowMod) writeCapture.getValues().get(0);
    verifyFlowMod(thirdFlowMod, FlowMod3);

    writeCapture.reset();
    contextCapture.reset();

    // delete two rules and verify they've been removed
    // this should invoke staticFlowPusher.rowsDeleted()
    storage.deleteRow(StaticFlowEntryPusher.TABLE_NAME, "TestRule1");
    storage.deleteRow(StaticFlowEntryPusher.TABLE_NAME, "TestRule2");

    assertEquals(1, staticFlowEntryPusher.countEntries());
    assertEquals(2, writeCapture.getValues().size());

    OFFlowMod firstDelete = (OFFlowMod) writeCapture.getValues().get(0);
    FlowMod1.setCommand(OFFlowMod.OFPFC_DELETE_STRICT);
    verifyFlowMod(firstDelete, FlowMod1);

    OFFlowMod secondDelete = (OFFlowMod) writeCapture.getValues().get(1);
    FlowMod2.setCommand(OFFlowMod.OFPFC_DELETE_STRICT);
    verifyFlowMod(secondDelete, FlowMod2);

    // add rules back to make sure that staticFlowPusher.rowsInserted() works
    writeCapture.reset();
    FlowMod2.setCommand(OFFlowMod.OFPFC_ADD);
    storage.insertRow(StaticFlowEntryPusher.TABLE_NAME, TestRule2);
    assertEquals(2, staticFlowEntryPusher.countEntries());
    assertEquals(1, writeCaptureList.getValues().size());
    List<OFMessage> outList = (List<OFMessage>) writeCaptureList.getValues().get(0);
    assertEquals(1, outList.size());
    OFFlowMod firstAdd = (OFFlowMod) outList.get(0);
    verifyFlowMod(firstAdd, FlowMod2);
    writeCapture.reset();
    contextCapture.reset();
    writeCaptureList.reset();

    // now try an overwriting update, calling staticFlowPusher.rowUpdated()
    TestRule3.put(COLUMN_DL_VLAN, 333);
    storage.updateRow(StaticFlowEntryPusher.TABLE_NAME, TestRule3);
    assertEquals(2, staticFlowEntryPusher.countEntries());
    assertEquals(1, writeCaptureList.getValues().size());

    outList = (List<OFMessage>) writeCaptureList.getValues().get(0);
    assertEquals(2, outList.size());
    OFFlowMod removeFlowMod = (OFFlowMod) outList.get(0);
    FlowMod3.setCommand(OFFlowMod.OFPFC_DELETE_STRICT);
    verifyFlowMod(removeFlowMod, FlowMod3);
    FlowMod3.setCommand(OFFlowMod.OFPFC_ADD);
    FlowMod3.getMatch().fromString("dl_dst=00:20:30:40:50:60,dl_vlan=333");
    OFFlowMod updateFlowMod = (OFFlowMod) outList.get(1);
    verifyFlowMod(updateFlowMod, FlowMod3);
    writeCaptureList.reset();

    // now try an action modifying update, calling staticFlowPusher.rowUpdated()
    TestRule3.put(COLUMN_ACTIONS, "output=controller,strip-vlan"); // added strip-vlan
    storage.updateRow(StaticFlowEntryPusher.TABLE_NAME, TestRule3);
    assertEquals(2, staticFlowEntryPusher.countEntries());
    assertEquals(1, writeCaptureList.getValues().size());

    outList = (List<OFMessage>) writeCaptureList.getValues().get(0);
    assertEquals(1, outList.size());
    OFFlowMod modifyFlowMod = (OFFlowMod) outList.get(0);
    FlowMod3.setCommand(OFFlowMod.OFPFC_MODIFY_STRICT);
    List<OFAction> modifiedActions = FlowMod3.getActions();
    modifiedActions.add(
        new OFActionStripVirtualLan()); // add the new action to what we should expect
    FlowMod3.setActions(modifiedActions);
    FlowMod3.setLengthU(OFFlowMod.MINIMUM_LENGTH + 16); // accommodate the addition of new actions
    verifyFlowMod(modifyFlowMod, FlowMod3);
  }
  @Override
  public void addedSwitch(IOFSwitch sw) {
    /**
     * Insert static flows on all ports of the switch to redirect DHCP client --> DHCP DHCPServer
     * traffic to the controller. DHCP client's operate on UDP port 67
     */
    OFFlowMod flow = new OFFlowMod();
    OFMatch match = new OFMatch();
    ArrayList<OFAction> actionList = new ArrayList<OFAction>();
    OFActionOutput action = new OFActionOutput();
    String flowName;

    if (sw.getStringId().equals(ROOT_NODE_WIFI_OVS_DPID)) {
      // root node, WiFi bridge, patch to tunnel port
      flow = new OFFlowMod();
      match = new OFMatch();
      match.setInputPort(ROOT_NODE_WIFI_OVS_PATCH);
      action.setType(OFActionType.OUTPUT);
      action.setPort(ROOT_NODE_WIFI_OVS_TUNNEL);
      action.setLength((short) OFActionOutput.MINIMUM_LENGTH);
      actionList.add(action);
      flow.setCookie(0);
      flow.setBufferId(-1);
      flow.setOutPort(ROOT_NODE_WIFI_OVS_TUNNEL);
      flow.setActions(actionList);
      flow.setMatch(match);
      flow.setPriority(PRIORITY_HIGH);
      flow.setLengthU(OFFlowMod.MINIMUM_LENGTH + action.getLengthU());
      flowName = "root-node-wifi-br-patch-tun";
      sfp.addFlow(flowName, flow, sw.getStringId());
      log.info("added flow on SW " + sw.getStringId() + flowName);
      actionList.clear();
      // root node, WiFi bridge, physical to patch
      flow = new OFFlowMod();
      match = new OFMatch();
      match.setInputPort(ROOT_NODE_WIFI_OVS_TUNNEL);
      action.setType(OFActionType.OUTPUT);
      action.setPort(ROOT_NODE_WIFI_OVS_PATCH);
      action.setLength((short) OFActionOutput.MINIMUM_LENGTH);
      actionList.add(action);
      flow.setCookie(0);
      flow.setBufferId(-1);
      flow.setOutPort(ROOT_NODE_WIFI_OVS_PATCH);
      flow.setActions(actionList);
      flow.setMatch(match);
      flow.setPriority(PRIORITY_HIGH);
      flow.setLengthU(OFFlowMod.MINIMUM_LENGTH + action.getLengthU());
      flowName = "root-node-wifi-br-tun-patch";
      sfp.addFlow(flowName, flow, sw.getStringId());
      log.info("added flow on SW " + sw.getStringId() + flowName);
      actionList.clear();
    } else if (sw.getStringId().equals(ROOT_NODE_WIMAX_OVS_DPID)) {
      // root node, WiMAX bridge, patch to physical
      flow = new OFFlowMod();
      match = new OFMatch();
      match.setInputPort(ROOT_NODE_WIMAX_OVS_PATCH);
      action.setType(OFActionType.OUTPUT);
      action.setPort(ROOT_NODE_WIMAX_OVS_VLAN);
      action.setLength((short) OFActionOutput.MINIMUM_LENGTH);
      actionList.add(action);
      flow.setCookie(0);
      flow.setBufferId(-1);
      flow.setOutPort(ROOT_NODE_WIMAX_OVS_VLAN);
      flow.setActions(actionList);
      flow.setMatch(match);
      flow.setPriority(PRIORITY_HIGH);
      flow.setLengthU(OFFlowMod.MINIMUM_LENGTH + action.getLengthU());
      flowName = "root-node-wimax-br-patch-phys";
      sfp.addFlow(flowName, flow, sw.getStringId());
      log.info("added flow on SW " + sw.getStringId() + flowName);
      actionList.clear();
      // root node, WiMAX bridge, interface to patch
      flow = new OFFlowMod();
      match = new OFMatch();
      match.setInputPort(ROOT_NODE_WIMAX_OVS_VLAN);
      action.setType(OFActionType.OUTPUT);
      action.setPort(ROOT_NODE_WIMAX_OVS_PATCH);
      action.setLength((short) OFActionOutput.MINIMUM_LENGTH);
      actionList.add(action);
      flow.setCookie(0);
      flow.setBufferId(-1);
      flow.setOutPort(ROOT_NODE_WIMAX_OVS_PATCH);
      flow.setActions(actionList);
      flow.setMatch(match);
      flow.setPriority(PRIORITY_HIGH);
      flow.setLengthU(OFFlowMod.MINIMUM_LENGTH + action.getLengthU());
      flowName = "root-node-wimax-br-phys-patch";
      sfp.addFlow(flowName, flow, sw.getStringId());
      log.info("added flow on SW " + sw.getStringId() + flowName);
      actionList.clear();
      // root node, WiMAX bridge, DHCP on physical
      match.setInputPort(ROOT_NODE_WIMAX_OVS_VLAN);
      match.setDataLayerType(Ethernet.TYPE_IPv4);
      match.setNetworkProtocol(IPv4.PROTOCOL_UDP);
      match.setTransportSource(UDP.DHCP_CLIENT_PORT);
      action.setType(OFActionType.OUTPUT);
      action.setLength((short) OFActionOutput.MINIMUM_LENGTH);
      action.setPort(OFPort.OFPP_CONTROLLER.getValue());
      actionList.add(action);
      flow.setCookie(0);
      flow.setBufferId(-1);
      flow.setOutPort(OFPort.OFPP_CONTROLLER.getValue());
      flow.setActions(actionList);
      flow.setMatch(match);
      flow.setPriority(PRIORITY_MAX);
      flow.setLengthU(OFFlowMod.MINIMUM_LENGTH + action.getLengthU());
      flowName = "root-node-wimax-br-DHCP-phys";
      sfp.addFlow(flowName, flow, sw.getStringId());
      log.info("added flow on SW " + sw.getStringId() + flowName);
      actionList.clear();
    } else if (sw.getStringId().equals(ROOT_NODE_ROOT_OVS_DPID)) {
      // root node, root bridge, patch AP3 (WiFi) to Linux
      flow = new OFFlowMod();
      match = new OFMatch();
      match.setInputPort(ROOT_NODE_ROOT_OVS_WIFI_PATCH);
      action.setType(OFActionType.OUTPUT);
      action.setPort(OFPort.OFPP_LOCAL.getValue());
      action.setLength((short) OFActionOutput.MINIMUM_LENGTH);
      actionList.add(action);
      flow.setCookie(0);
      flow.setBufferId(-1);
      flow.setOutPort(OFPort.OFPP_LOCAL.getValue());
      flow.setActions(actionList);
      flow.setMatch(match);
      flow.setPriority(PRIORITY_HIGH);
      flow.setLengthU(OFFlowMod.MINIMUM_LENGTH + action.getLengthU());
      flowName = "root-node-root-br-patchWiFi-linux";
      sfp.addFlow(flowName, flow, sw.getStringId());
      log.info("added flow on SW " + sw.getStringId() + flowName);
      actionList.clear();
      // root node, root bridge, patch WiMAX to Linux
      flow = new OFFlowMod();
      match = new OFMatch();
      match.setInputPort(ROOT_NODE_ROOT_OVS_WIMAX_PATCH);
      action.setType(OFActionType.OUTPUT);
      action.setPort(OFPort.OFPP_LOCAL.getValue());
      action.setLength((short) OFActionOutput.MINIMUM_LENGTH);
      actionList.add(action);
      flow.setCookie(0);
      flow.setBufferId(-1);
      flow.setOutPort(OFPort.OFPP_LOCAL.getValue());
      flow.setActions(actionList);
      flow.setMatch(match);
      flow.setPriority(PRIORITY_HIGH);
      flow.setLengthU(OFFlowMod.MINIMUM_LENGTH + action.getLengthU());
      flowName = "root-node-root-br-patchWiMAX-linux";
      sfp.addFlow(flowName, flow, sw.getStringId());
      log.info("added flow on SW " + sw.getStringId() + flowName);
      actionList.clear();
      // root node, root bridge, physical to Linux
      // flow = new OFFlowMod();
      // match = new OFMatch();
      // match.setInputPort((short) 1);
      // action.setType(OFActionType.OUTPUT);
      // action.setPort(OFPort.OFPP_LOCAL.getValue());
      // action.setLength((short) OFActionOutput.MINIMUM_LENGTH);
      // actionList.add(action);
      // flow.setCookie(0);
      // flow.setBufferId(-1);
      // flow.setOutPort(OFPort.OFPP_LOCAL.getValue());
      // flow.setActions(actionList);
      // flow.setMatch(match);
      // flow.setPriority(PRIORITY_HIGH);
      // flow.setLengthU(OFFlowMod.MINIMUM_LENGTH + action.getLengthU());
      // flowName = "root-ovs-root-br-phys-linux";
      // sfp.addFlow(flowName, flow, sw.getStringId());
      // log.info("added flow on SW " + sw.getStringId() + flowName);
      // actionList.clear();
      // root node, root bridge, Linux to physical (match extra: src-ip of root node...i.e. it's
      // outbound)
      // flow = new OFFlowMod();
      // match = new OFMatch();
      // match.setInputPort(OFPort.OFPP_LOCAL.getValue());
      // match.setDataLayerType(Ethernet.TYPE_IPv4); // ... IP packets ... required for a match on
      // an IP address
      // match.setNetworkSource(ROOT_NODE_ROOT_OVS_IP);
      // action.setType(OFActionType.OUTPUT);
      // action.setPort((short) 1);
      // action.setLength((short) OFActionOutput.MINIMUM_LENGTH);
      // actionList.add(action);
      // flow.setCookie(0);
      // flow.setBufferId(-1);
      // flow.setOutPort((short) 1);
      // flow.setActions(actionList);
      // flow.setMatch(match);
      // flow.setPriority(PRIORITY_HIGH);
      // flow.setLengthU(OFFlowMod.MINIMUM_LENGTH + action.getLengthU());
      // flowName = "root-ovs-root-br-linux-phys-egress";
      // sfp.addFlow(flowName, flow, sw.getStringId());
      // log.info("added flow on SW " + sw.getStringId() + flowName);
      // actionList.clear();
    } else if (sw.getStringId().equals(WIFI_NODE_WIFI_OVS_DPID)) {
      // WiFi node, WiFi bridge, physical to patch
      flow = new OFFlowMod();
      match = new OFMatch();
      match.setInputPort((short) 1);
      action.setType(OFActionType.OUTPUT);
      action.setPort(WIFI_NODE_WIFI_OVS_PATCH);
      action.setLength((short) OFActionOutput.MINIMUM_LENGTH);
      actionList.add(action);
      flow.setCookie(0);
      flow.setBufferId(-1);
      flow.setOutPort(WIFI_NODE_WIFI_OVS_PATCH);
      flow.setActions(actionList);
      flow.setMatch(match);
      flow.setPriority(PRIORITY_HIGH);
      flow.setLengthU(OFFlowMod.MINIMUM_LENGTH + action.getLengthU());
      flowName = "wifi-node-wifi-br-phys-patch";
      sfp.addFlow(flowName, flow, sw.getStringId());
      log.info("added flow on SW " + sw.getStringId() + flowName);
      actionList.clear();
      // WiFi node, WiFi bridge, patch to physical
      flow = new OFFlowMod();
      match = new OFMatch();
      match.setInputPort(WIFI_NODE_WIFI_OVS_PATCH);
      action.setType(OFActionType.OUTPUT);
      action.setPort((short) 1);
      action.setLength((short) OFActionOutput.MINIMUM_LENGTH);
      actionList.add(action);
      flow.setCookie(0);
      flow.setBufferId(-1);
      flow.setOutPort((short) 1);
      flow.setActions(actionList);
      flow.setMatch(match);
      flow.setPriority(PRIORITY_HIGH);
      flow.setLengthU(OFFlowMod.MINIMUM_LENGTH + action.getLengthU());
      flowName = "wifi-node-wifi-br-patch-phys";
      sfp.addFlow(flowName, flow, sw.getStringId());
      log.info("added flow on SW " + sw.getStringId() + flowName);
      actionList.clear();
      // root node, WiMAX bridge, DHCP on physical
      match.setInputPort((short) 1);
      match.setDataLayerType(Ethernet.TYPE_IPv4);
      match.setNetworkProtocol(IPv4.PROTOCOL_UDP);
      match.setTransportSource(UDP.DHCP_CLIENT_PORT);
      action.setType(OFActionType.OUTPUT);
      action.setLength((short) OFActionOutput.MINIMUM_LENGTH);
      action.setPort(OFPort.OFPP_CONTROLLER.getValue());
      actionList.add(action);
      flow.setCookie(0);
      flow.setBufferId(-1);
      flow.setOutPort(OFPort.OFPP_CONTROLLER.getValue());
      flow.setActions(actionList);
      flow.setMatch(match);
      flow.setPriority(PRIORITY_MAX);
      flow.setLengthU(OFFlowMod.MINIMUM_LENGTH + action.getLengthU());
      flowName = "wifi-node-wifi-br-DHCP-phys";
      sfp.addFlow(flowName, flow, sw.getStringId());
      log.info("added flow on SW " + sw.getStringId() + flowName);
      actionList.clear();
    } else if (sw.getStringId().equals(WIFI_NODE_TUNNEL_OVS_DPID)) {
      // WiFi node, tunnel bridge, tunnel to patch
      flow = new OFFlowMod();
      match = new OFMatch();
      match.setInputPort(WIFI_NODE_TUNNEL_OVS_TUNNEL);
      action.setType(OFActionType.OUTPUT);
      action.setPort(WIFI_NODE_TUNNEL_OVS_PATCH);
      action.setLength((short) OFActionOutput.MINIMUM_LENGTH);
      actionList.add(action);
      flow.setCookie(0);
      flow.setBufferId(-1);
      flow.setOutPort(WIFI_NODE_TUNNEL_OVS_PATCH);
      flow.setActions(actionList);
      flow.setMatch(match);
      flow.setPriority(PRIORITY_HIGH);
      flow.setLengthU(OFFlowMod.MINIMUM_LENGTH + action.getLengthU());
      flowName = "wifi-node-tunnel-br-tun-patch";
      sfp.addFlow(flowName, flow, sw.getStringId());
      log.info("added flow on SW " + sw.getStringId() + flowName);
      actionList.clear();
      // WiFi node, tunnel bridge, patch to tunnel
      flow = new OFFlowMod();
      match = new OFMatch();
      match.setInputPort(WIFI_NODE_TUNNEL_OVS_PATCH);
      action.setType(OFActionType.OUTPUT);
      action.setPort(WIFI_NODE_TUNNEL_OVS_TUNNEL);
      action.setLength((short) OFActionOutput.MINIMUM_LENGTH);
      actionList.add(action);
      flow.setCookie(0);
      flow.setBufferId(-1);
      flow.setOutPort(WIFI_NODE_TUNNEL_OVS_TUNNEL);
      flow.setActions(actionList);
      flow.setMatch(match);
      flow.setPriority(PRIORITY_HIGH);
      flow.setLengthU(OFFlowMod.MINIMUM_LENGTH + action.getLengthU());
      flowName = "wifi-node-tunnel-br-patch-tun";
      sfp.addFlow(flowName, flow, sw.getStringId());
      log.info("added flow on SW " + sw.getStringId() + flowName);
      actionList.clear();
    }
  }