Controller implements IFloodlightProviderService, 
            IStorageSourceListener { @LogMessageDoc(level="ERROR", message="New switch added {switch} for already-added switch {switch}", explanation="A switch with the same DPID as another switch " + "connected to the controller. This can be caused by " + "multiple switches configured with the same DPID, or " + "by a switch reconnected very quickly after " + "disconnecting.", recommendation="If this happens repeatedly, it is likely there " + "are switches with duplicate DPIDs on the network. " + "Reconfigure the appropriate switches. If it happens " + "very rarely, then it is likely this is a transient " + "network problem that can be ignored." ) protected void addSwitch(IOFSwitch sw) { OFSwitchImpl oldSw = (OFSwitchImpl) this.activeSwitches.put(sw.getId(), sw); if (sw == oldSw) { log.info("New add switch for pre-existing switch {}", sw); return; } if (oldSw != null) { oldSw.getListenerWriteLock().lock(); try { log.error("New switch added {} for already-added switch {}", sw, oldSw); oldSw.setConnected(false); oldSw.cancelAllStatisticsReplies(); updateInactiveSwitchInfo(oldSw); if (switchListeners != null) { for (IOFSwitchListener listener : switchListeners) { listener.removedSwitch(oldSw); } } oldSw.getChannel().close(); } finally { oldSw.getListenerWriteLock().unlock(); } } updateActiveSwitchInfo(sw); SwitchUpdate update = new SwitchUpdate(sw, SwitchUpdateType.ADDED); try { this.updates.put(update); } catch (InterruptedException e) { log.error("Failure adding update to queue", e); } }  void setStorageSourceService(IStorageSourceService storageSource); void setCounterStore(ICounterStoreService counterStore); void setPktInProcessingService(IPktInProcessingTimeService pits); void setRestApiService(IRestApiService restApi); void setThreadPoolService(IThreadPoolService tp); @Override Role getRole(); @Override void setRole(Role role); @Override synchronized void addOFMessageListener(OFType type, 
                                                  IOFMessageListener listener); @Override synchronized void removeOFMessageListener(OFType type,
                                                     IOFMessageListener listener); void removeOFMessageListeners(OFType type); @Override Map<Long, IOFSwitch> getSwitches(); @Override void addOFSwitchListener(IOFSwitchListener listener); @Override void removeOFSwitchListener(IOFSwitchListener listener); @Override Map<OFType, List<IOFMessageListener>> getListeners(); @Override @LogMessageDocs({ @LogMessageDoc(message="Failed to inject OFMessage {message} onto " + "a null switch", explanation="Failed to process a message because the switch " + " is no longer connected."), @LogMessageDoc(level="ERROR", message="Error reinjecting OFMessage on switch {switch}", explanation="An I/O error occured while attempting to " + "process an OpenFlow message", recommendation=LogMessageDoc.CHECK_SWITCH) }) boolean injectOfMessage(IOFSwitch sw, OFMessage msg,
                                   FloodlightContext bc); @Override @LogMessageDoc(message="Calling System.exit", explanation="The controller is terminating") synchronized void terminate(); @Override boolean injectOfMessage(IOFSwitch sw, OFMessage msg); @Override void handleOutgoingMessage(IOFSwitch sw, OFMessage m,
                                      FloodlightContext bc); @Override BasicFactory getOFMessageFactory(); @Override String getControllerId(); @LogMessageDocs({ @LogMessageDoc(message="Listening for switch connections on {address}", explanation="The controller is ready and listening for new" + " switch connections"), @LogMessageDoc(message="Storage exception in controller " + "updates loop; terminating process", explanation=ERROR_DATABASE, recommendation=LogMessageDoc.CHECK_CONTROLLER), @LogMessageDoc(level="ERROR", message="Exception in controller updates loop", explanation="Failed to dispatch controller event", recommendation=LogMessageDoc.GENERIC_ACTION) }) void run(); void setConfigParams(Map<String, String> configParams); void init(Map<String, String> configParams); @LogMessageDoc(message="Waiting for storage source", explanation="The system database is not yet ready", recommendation="If this message persists, this indicates " + "that the system database has failed to start. " + LogMessageDoc.CHECK_CONTROLLER) void startupComponents(); @Override void addInfoProvider(String type, IInfoProvider provider); @Override void removeInfoProvider(String type, IInfoProvider provider); Map<String, Object> getControllerInfo(String type); @Override void addHAListener(IHAListener listener); @Override void removeHAListener(IHAListener listener); @Override Map<String, String> getControllerNodeIPs(); @Override void rowsModified(String tableName, Set<Object> rowKeys); @Override void rowsDeleted(String tableName, Set<Object> rowKeys); @Override long getSystemStartTime(); @Override void setAlwaysClearFlowsOnSwAdd(boolean value); boolean getAlwaysClearFlowsOnSwAdd();  }
@Test public void testAddSwitch() throws Exception { controller.activeSwitches = new ConcurrentHashMap<Long, IOFSwitch>(); OFSwitchImpl oldsw = new OFSwitchImpl(); OFFeaturesReply featuresReply = new OFFeaturesReply(); featuresReply.setDatapathId(0L); featuresReply.setPorts(new ArrayList<OFPhysicalPort>()); oldsw.setFeaturesReply(featuresReply); Channel channel = createNiceMock(Channel.class); oldsw.setChannel(channel); expect(channel.close()).andReturn(null); IOFSwitch newsw = createMock(IOFSwitch.class); expect(newsw.getId()).andReturn(0L).anyTimes(); expect(newsw.getStringId()).andReturn("00:00:00:00:00:00:00").anyTimes(); expect(newsw.getConnectedSince()).andReturn(new Date()); Channel channel2 = createMock(Channel.class); expect(newsw.getChannel()).andReturn(channel2); expect(channel2.getRemoteAddress()).andReturn(null); expect(newsw.getPorts()).andReturn(new ArrayList<OFPhysicalPort>()); expect(newsw.getCapabilities()).andReturn(0).anyTimes(); expect(newsw.getBuffers()).andReturn(0).anyTimes(); expect(newsw.getTables()).andReturn((byte)0).anyTimes(); expect(newsw.getActions()).andReturn(0).anyTimes(); controller.activeSwitches.put(0L, oldsw); replay(newsw, channel, channel2); controller.addSwitch(newsw); verify(newsw, channel, channel2); }