Addressed some checkstyle, PMD and findbugs violations in the ARP module

Change-Id: I194533ba5f96a7631ea662a93cbcbd8a2c84dea9
diff --git a/src/main/java/net/onrc/onos/ofcontroller/proxyarp/ProxyArpManager.java b/src/main/java/net/onrc/onos/ofcontroller/proxyarp/ProxyArpManager.java
index 2294a60..33d4d7d 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/proxyarp/ProxyArpManager.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/proxyarp/ProxyArpManager.java
@@ -46,780 +46,798 @@
 import com.google.common.collect.SetMultimap;
 
 public class ProxyArpManager implements IProxyArpService, IOFMessageListener,
-										IPacketOutEventHandler, IArpReplyEventHandler, 
-										IFloodlightModule {
-	private final static Logger log = LoggerFactory.getLogger(ProxyArpManager.class);
-	
-	private final long ARP_TIMER_PERIOD = 100; //ms  
+        IPacketOutEventHandler, IArpReplyEventHandler, IFloodlightModule {
+    private static final Logger log = LoggerFactory
+            .getLogger(ProxyArpManager.class);
 
-	private static final int ARP_REQUEST_TIMEOUT = 2000; //ms
-			
-	private IFloodlightProviderService floodlightProvider;
-	private IDatagridService datagrid;
-	private IConfigInfoService configService;
-	private IRestApiService restApi;
-	private IFlowPusherService flowPusher;
-	
-	private short vlan;
-	private static final short NO_VLAN = 0;
-	
-	//private ArpCache arpCache;
+    private static final long ARP_TIMER_PERIOD = 100; // ms
 
-	private SetMultimap<InetAddress, ArpRequest> arpRequests;
-	
-	private static class ArpRequest {
-		private final IArpRequester requester;
-		private final boolean retry;
-		private boolean sent = false;
-		private long requestTime;
-		
-		public ArpRequest(IArpRequester requester, boolean retry){
-			this.requester = requester;
-			this.retry = retry;
-		}
-		
-		public ArpRequest(ArpRequest old) {
-			this.requester = old.requester;
-			this.retry = old.retry;
-		}
-		
-		public boolean isExpired() {
-			return sent && ((System.currentTimeMillis() - requestTime) > ARP_REQUEST_TIMEOUT);
-		}
-		
-		public boolean shouldRetry() {
-			return retry;
-		}
-		
-		public void dispatchReply(InetAddress ipAddress, MACAddress replyMacAddress) {
-			requester.arpResponse(ipAddress, replyMacAddress);
-		}
-		
-		public void setRequestTime() {
-			this.requestTime = System.currentTimeMillis();
-			this.sent = true;
-		}
-	}
-	
-	private class HostArpRequester implements IArpRequester {
-		private final ARP arpRequest;
-		private final long dpid;
-		private final short port;
-		
-		public HostArpRequester(ARP arpRequest, long dpid, short port) {
-			this.arpRequest = arpRequest;
-			this.dpid = dpid;
-			this.port = port;
-		}
+    private static final int ARP_REQUEST_TIMEOUT = 2000; // ms
 
-		@Override
-		public void arpResponse(InetAddress ipAddress, MACAddress macAddress) {
-			ProxyArpManager.this.sendArpReply(arpRequest, dpid, port, macAddress);
-		}
-	}
-	
-	@Override
-	public Collection<Class<? extends IFloodlightService>> getModuleServices() {
-		Collection<Class<? extends IFloodlightService>> l 
-			= new ArrayList<Class<? extends IFloodlightService>>();
-		l.add(IProxyArpService.class);
-		return l;
-	}
+    private IFloodlightProviderService floodlightProvider;
+    private IDatagridService datagrid;
+    private IConfigInfoService configService;
+    private IRestApiService restApi;
+    private IFlowPusherService flowPusher;
 
-	@Override
-	public Map<Class<? extends IFloodlightService>, IFloodlightService> getServiceImpls() {
-		Map<Class<? extends IFloodlightService>, IFloodlightService> m 
-			= new HashMap<Class<? extends IFloodlightService>, IFloodlightService>();
-		m.put(IProxyArpService.class, this);
-		return m;
-	}
+    private short vlan;
+    private static final short NO_VLAN = 0;
 
-	@Override
-	public Collection<Class<? extends IFloodlightService>> getModuleDependencies() {
-		Collection<Class<? extends IFloodlightService>> dependencies 
-			= new ArrayList<Class<? extends IFloodlightService>>();
-		dependencies.add(IFloodlightProviderService.class);
-		dependencies.add(IRestApiService.class);
-		dependencies.add(IDatagridService.class);
-		dependencies.add(IConfigInfoService.class);
-		dependencies.add(IFlowPusherService.class);
-		return dependencies;
-	}
-	
-	@Override
-	public void init(FloodlightModuleContext context){
-		this.floodlightProvider = 
-				context.getServiceImpl(IFloodlightProviderService.class);
-		this.datagrid = context.getServiceImpl(IDatagridService.class);
-		this.configService = context.getServiceImpl(IConfigInfoService.class);
-		this.restApi = context.getServiceImpl(IRestApiService.class);
-		this.flowPusher = context.getServiceImpl(IFlowPusherService.class);
-		
-		//arpCache = new ArpCache();
+    private SetMultimap<InetAddress, ArpRequest> arpRequests;
 
-		arpRequests = Multimaps.synchronizedSetMultimap(
-				HashMultimap.<InetAddress, ArpRequest>create());
-		
-	}
-	
-	@Override
-	public void startUp(FloodlightModuleContext context) {
-		this.vlan = configService.getVlan();
-		log.info("vlan set to {}", this.vlan);
-		
-		restApi.addRestletRoutable(new ArpWebRoutable());
-		floodlightProvider.addOFMessageListener(OFType.PACKET_IN, this);
-		
-		datagrid.registerPacketOutEventHandler(this);
-		datagrid.registerArpReplyEventHandler(this);
-		
-		Timer arpTimer = new Timer("arp-processing");
-		arpTimer.scheduleAtFixedRate(new TimerTask() {
-			@Override
-			public void run() {
-				doPeriodicArpProcessing();
-			}
-		}, 0, ARP_TIMER_PERIOD);
-	}
-	
-	/*
-	 * Function that runs periodically to manage the asynchronous request mechanism.
-	 * It basically cleans up old ARP requests if we don't get a response for them.
-	 * The caller can designate that a request should be retried indefinitely, and
-	 * this task will handle that as well.
-	 */
-	private void doPeriodicArpProcessing() {
-		SetMultimap<InetAddress, ArpRequest> retryList 
-				= HashMultimap.<InetAddress, ArpRequest>create();
+    private static class ArpRequest {
+        private final IArpRequester requester;
+        private final boolean retry;
+        private boolean sent = false;
+        private long requestTime;
 
-		//Have to synchronize externally on the Multimap while using an iterator,
-		//even though it's a synchronizedMultimap
-		synchronized (arpRequests) {			
-			Iterator<Map.Entry<InetAddress, ArpRequest>> it 
-				= arpRequests.entries().iterator();
-			
-			while (it.hasNext()) {
-				Map.Entry<InetAddress, ArpRequest> entry
-						= it.next();
-				ArpRequest request = entry.getValue();
-				if (request.isExpired()) {
-					log.debug("Cleaning expired ARP request for {}", 
-							entry.getKey().getHostAddress());
-		
-					// If the ARP request is expired and then delete the device
-					// TODO check whether this is OK from this thread
-					// TODO: Fix the code below after deviceStorage was removed
-					/*
-					IDeviceObject targetDevice = 
-							deviceStorage.getDeviceByIP(InetAddresses.coerceToInteger(entry.getKey()));
-					if (targetDevice != null) {
-						deviceStorage.removeDevice(targetDevice);
-						if (log.isDebugEnabled()) {
-							log.debug("RemoveDevice: {} due to no have not recieve the ARP reply", targetDevice);
-						}
-					}
-					*/
-					
-					it.remove();
-					
-					if (request.shouldRetry()) {
-						retryList.put(entry.getKey(), request);
-					}
-				}
-			}
-		}
-		
-		for (Map.Entry<InetAddress, Collection<ArpRequest>> entry 
-				: retryList.asMap().entrySet()) {
-			
-			InetAddress address = entry.getKey();
-			
-			log.debug("Resending ARP request for {}", address.getHostAddress());
-			
-			// Only ARP requests sent by the controller will have the retry flag
-			// set, so for now we can just send a new ARP request for that address.
-			sendArpRequestForAddress(address);
-			
-			for (ArpRequest request : entry.getValue()) {
-				arpRequests.put(address, new ArpRequest(request));
-			}
-		}
-	}
-	
-	@Override
-	public String getName() {
-		return "proxyarpmanager";
-	}
+        public ArpRequest(IArpRequester requester, boolean retry) {
+            this.requester = requester;
+            this.retry = retry;
+        }
 
-	@Override
-	public boolean isCallbackOrderingPrereq(OFType type, String name) {
-		if (type == OFType.PACKET_IN) {
-			return "devicemanager".equals(name) || "onosdevicemanager".equals(name);
-		}
-		else {
-			return false;
-		}
-	}
+        public ArpRequest(ArpRequest old) {
+            this.requester = old.requester;
+            this.retry = old.retry;
+        }
 
-	@Override
-	public boolean isCallbackOrderingPostreq(OFType type, String name) {
-		return type == OFType.PACKET_IN && "onosforwarding".equals(name);
-	}
+        public boolean isExpired() {
+            return sent
+                    && ((System.currentTimeMillis() - requestTime) > ARP_REQUEST_TIMEOUT);
+        }
 
-	@Override
-	public Command receive(
-			IOFSwitch sw, OFMessage msg, FloodlightContext cntx) {
-		
-		OFPacketIn pi = (OFPacketIn) msg;
-		
-		Ethernet eth = IFloodlightProviderService.bcStore.get(cntx, 
+        public boolean shouldRetry() {
+            return retry;
+        }
+
+        public void dispatchReply(InetAddress ipAddress,
+                MACAddress replyMacAddress) {
+            requester.arpResponse(ipAddress, replyMacAddress);
+        }
+
+        public void setRequestTime() {
+            this.requestTime = System.currentTimeMillis();
+            this.sent = true;
+        }
+    }
+
+    private class HostArpRequester implements IArpRequester {
+        private final ARP arpRequest;
+        private final long dpid;
+        private final short port;
+
+        public HostArpRequester(ARP arpRequest, long dpid, short port) {
+            this.arpRequest = arpRequest;
+            this.dpid = dpid;
+            this.port = port;
+        }
+
+        @Override
+        public void arpResponse(InetAddress ipAddress, MACAddress macAddress) {
+            ProxyArpManager.this.sendArpReply(arpRequest, dpid, port,
+                    macAddress);
+        }
+    }
+
+    @Override
+    public Collection<Class<? extends IFloodlightService>> getModuleServices() {
+        Collection<Class<? extends IFloodlightService>> l =
+                new ArrayList<Class<? extends IFloodlightService>>();
+        l.add(IProxyArpService.class);
+        return l;
+    }
+
+    @Override
+    public Map<Class<? extends IFloodlightService>, IFloodlightService> getServiceImpls() {
+        Map<Class<? extends IFloodlightService>, IFloodlightService> m =
+                new HashMap<Class<? extends IFloodlightService>, IFloodlightService>();
+        m.put(IProxyArpService.class, this);
+        return m;
+    }
+
+    @Override
+    public Collection<Class<? extends IFloodlightService>> getModuleDependencies() {
+        Collection<Class<? extends IFloodlightService>> dependencies =
+                new ArrayList<Class<? extends IFloodlightService>>();
+        dependencies.add(IFloodlightProviderService.class);
+        dependencies.add(IRestApiService.class);
+        dependencies.add(IDatagridService.class);
+        dependencies.add(IConfigInfoService.class);
+        dependencies.add(IFlowPusherService.class);
+        return dependencies;
+    }
+
+    @Override
+    public void init(FloodlightModuleContext context) {
+        this.floodlightProvider = context
+                .getServiceImpl(IFloodlightProviderService.class);
+        this.datagrid = context.getServiceImpl(IDatagridService.class);
+        this.configService = context.getServiceImpl(IConfigInfoService.class);
+        this.restApi = context.getServiceImpl(IRestApiService.class);
+        this.flowPusher = context.getServiceImpl(IFlowPusherService.class);
+
+        // arpCache = new ArpCache();
+
+        arpRequests = Multimaps.synchronizedSetMultimap(HashMultimap
+                .<InetAddress, ArpRequest>create());
+
+    }
+
+    @Override
+    public void startUp(FloodlightModuleContext context) {
+        this.vlan = configService.getVlan();
+        log.info("vlan set to {}", this.vlan);
+
+        restApi.addRestletRoutable(new ArpWebRoutable());
+        floodlightProvider.addOFMessageListener(OFType.PACKET_IN, this);
+
+        datagrid.registerPacketOutEventHandler(this);
+        datagrid.registerArpReplyEventHandler(this);
+
+        Timer arpTimer = new Timer("arp-processing");
+        arpTimer.scheduleAtFixedRate(new TimerTask() {
+            @Override
+            public void run() {
+                doPeriodicArpProcessing();
+            }
+        }, 0, ARP_TIMER_PERIOD);
+    }
+
+    /*
+     * Function that runs periodically to manage the asynchronous request mechanism.
+     * It basically cleans up old ARP requests if we don't get a response for them.
+     * The caller can designate that a request should be retried indefinitely, and
+     * this task will handle that as well.
+     */
+    private void doPeriodicArpProcessing() {
+        SetMultimap<InetAddress, ArpRequest> retryList = HashMultimap
+                .<InetAddress, ArpRequest>create();
+
+        // Have to synchronize externally on the Multimap while using an
+        // iterator,
+        // even though it's a synchronizedMultimap
+        synchronized (arpRequests) {
+            Iterator<Map.Entry<InetAddress, ArpRequest>> it = arpRequests
+                    .entries().iterator();
+
+            while (it.hasNext()) {
+                Map.Entry<InetAddress, ArpRequest> entry = it.next();
+                ArpRequest request = entry.getValue();
+                if (request.isExpired()) {
+                    log.debug("Cleaning expired ARP request for {}", entry
+                            .getKey().getHostAddress());
+
+                    // If the ARP request is expired and then delete the device
+                    // TODO check whether this is OK from this thread
+                    // TODO: Fix the code below after deviceStorage was removed
+                    /*
+                    IDeviceObject targetDevice =
+                    		deviceStorage.getDeviceByIP(InetAddresses.coerceToInteger(entry.getKey()));
+                    if (targetDevice != null) {
+                    	deviceStorage.removeDevice(targetDevice);
+                    	if (log.isDebugEnabled()) {
+                    		log.debug("RemoveDevice: {} due to no have not recieve the ARP reply", targetDevice);
+                    	}
+                    }
+                    */
+
+                    it.remove();
+
+                    if (request.shouldRetry()) {
+                        retryList.put(entry.getKey(), request);
+                    }
+                }
+            }
+        }
+
+        for (Map.Entry<InetAddress, Collection<ArpRequest>> entry : retryList
+                .asMap().entrySet()) {
+
+            InetAddress address = entry.getKey();
+
+            log.debug("Resending ARP request for {}", address.getHostAddress());
+
+            // Only ARP requests sent by the controller will have the retry flag
+            // set, so for now we can just send a new ARP request for that
+            // address.
+            sendArpRequestForAddress(address);
+
+            for (ArpRequest request : entry.getValue()) {
+                arpRequests.put(address, new ArpRequest(request));
+            }
+        }
+    }
+
+    @Override
+    public String getName() {
+        return "proxyarpmanager";
+    }
+
+    @Override
+    public boolean isCallbackOrderingPrereq(OFType type, String name) {
+        if (type == OFType.PACKET_IN) {
+            return "devicemanager".equals(name)
+                    || "onosdevicemanager".equals(name);
+        } else {
+            return false;
+        }
+    }
+
+    @Override
+    public boolean isCallbackOrderingPostreq(OFType type, String name) {
+        return type == OFType.PACKET_IN && "onosforwarding".equals(name);
+    }
+
+    @Override
+    public Command receive(IOFSwitch sw, OFMessage msg, FloodlightContext cntx) {
+
+        OFPacketIn pi = (OFPacketIn) msg;
+
+        Ethernet eth = IFloodlightProviderService.bcStore.get(cntx,
                 IFloodlightProviderService.CONTEXT_PI_PAYLOAD);
-		
-		if (eth.getEtherType() == Ethernet.TYPE_ARP){
-			ARP arp = (ARP) eth.getPayload();	
-			if (arp.getOpCode() == ARP.OP_REQUEST) {
-				handleArpRequest(sw, pi, arp, eth);
-			}
-			else if (arp.getOpCode() == ARP.OP_REPLY) {
-				// For replies we simply send a notification via Hazelcast
-				sendArpReplyNotification(eth, pi);
-				
-				//handleArpReply(sw, pi, arp);
-			}
-			
-			// Stop ARP packets here
-			return Command.STOP;
-		}
-		
-		// Propagate everything else
-		return Command.CONTINUE;
-	}
-	
-	private void handleArpRequest(IOFSwitch sw, OFPacketIn pi, ARP arp, Ethernet eth) {
-		if (log.isTraceEnabled()) {
-			log.trace("ARP request received for {}", 
-					inetAddressToString(arp.getTargetProtocolAddress()));
-		}
 
-		InetAddress target;
-		try {
-			target = InetAddress.getByAddress(arp.getTargetProtocolAddress());
-		} catch (UnknownHostException e) {
-			log.debug("Invalid address in ARP request", e);
-			return;
-		}
+        if (eth.getEtherType() == Ethernet.TYPE_ARP) {
+            ARP arp = (ARP) eth.getPayload();
+            if (arp.getOpCode() == ARP.OP_REQUEST) {
+                handleArpRequest(sw, pi, arp, eth);
+            } else if (arp.getOpCode() == ARP.OP_REPLY) {
+                // For replies we simply send a notification via Hazelcast
+                sendArpReplyNotification(eth, pi);
 
-		if (configService.fromExternalNetwork(sw.getId(), pi.getInPort())) {
-			//If the request came from outside our network, we only care if
-			//it was a request for one of our interfaces.
-			if (configService.isInterfaceAddress(target)) {
-				log.trace("ARP request for our interface. Sending reply {} => {}",
-						target.getHostAddress(), configService.getRouterMacAddress());
+                // handleArpReply(sw, pi, arp);
+            }
 
-				sendArpReply(arp, sw.getId(), pi.getInPort(), 
-						configService.getRouterMacAddress());
-			}
+            // Stop ARP packets here
+            return Command.STOP;
+        }
 
-			return;
-		}
-		
-		//MACAddress macAddress = arpCache.lookup(target);
+        // Propagate everything else
+        return Command.CONTINUE;
+    }
 
-		arpRequests.put(target, new ArpRequest(
-				new HostArpRequester(arp, sw.getId(), pi.getInPort()), false));
+    private void handleArpRequest(IOFSwitch sw, OFPacketIn pi, ARP arp,
+            Ethernet eth) {
+        if (log.isTraceEnabled()) {
+            log.trace("ARP request received for {}",
+                    inetAddressToString(arp.getTargetProtocolAddress()));
+        }
 
-		// TODO: Fix the code below after deviceStorage was removed
-		/*
-		IDeviceObject targetDevice = 
-				deviceStorage.getDeviceByIP(InetAddresses.coerceToInteger(target));
-		*/
+        InetAddress target;
+        try {
+            target = InetAddress.getByAddress(arp.getTargetProtocolAddress());
+        } catch (UnknownHostException e) {
+            log.debug("Invalid address in ARP request", e);
+            return;
+        }
 
-		// TODO: Fix the code below after deviceStorage was removed
-		/*
-		if (targetDevice == null) {
-			if (log.isTraceEnabled()) {
-				log.trace("No device info found for {} - broadcasting",
-						target.getHostAddress());
-			}
-			
-			// We don't know the device so broadcast the request out
-			datagrid.sendPacketOutNotification(
-					new BroadcastPacketOutNotification(eth.serialize(),
-							target, sw.getId(), pi.getInPort()));
-		}
-		else {
-			// Even if the device exists in our database, we do not reply to
-			// the request directly, but check whether the device is still valid
-			MACAddress macAddress = MACAddress.valueOf(targetDevice.getMACAddress());
+        if (configService.fromExternalNetwork(sw.getId(), pi.getInPort())) {
+            // If the request came from outside our network, we only care if
+            // it was a request for one of our interfaces.
+            if (configService.isInterfaceAddress(target)) {
+                log.trace(
+                        "ARP request for our interface. Sending reply {} => {}",
+                        target.getHostAddress(),
+                        configService.getRouterMacAddress());
 
-			if (log.isTraceEnabled()) {
-				log.trace("The target Device Record in DB is: {} => {} from ARP request host at {}/{}",
-						new Object [] {
-						inetAddressToString(arp.getTargetProtocolAddress()),
-						macAddress,
-						HexString.toHexString(sw.getId()), pi.getInPort()});
-			}
+                sendArpReply(arp, sw.getId(), pi.getInPort(),
+                        configService.getRouterMacAddress());
+            }
 
-			// sendArpReply(arp, sw.getId(), pi.getInPort(), macAddress);
+            return;
+        }
 
-			Iterable<IPortObject> outPorts = targetDevice.getAttachedPorts();	
+        // MACAddress macAddress = arpCache.lookup(target);
 
-			if (!outPorts.iterator().hasNext()){
-				if (log.isTraceEnabled()) {
-					log.trace("Device {} exists but is not connected to any ports" + 
-							" - broadcasting", macAddress);
-				}
-				
-				datagrid.sendPacketOutNotification(
-						new BroadcastPacketOutNotification(eth.serialize(), 
-								target, sw.getId(), pi.getInPort()));
-			} 
-			else {
-				for (IPortObject portObject : outPorts) {
-					//long outSwitch = 0;
-					//short outPort = 0;
+        arpRequests.put(
+                target,
+                new ArpRequest(new HostArpRequester(arp, sw.getId(), pi
+                        .getInPort()), false));
 
-					// if (!portObject.getLinkedPorts().iterator().hasNext()) {
-					//	outPort = portObject.getNumber();					
-					// }
-					if (portObject.getLinkedPorts().iterator().hasNext()) {
-						continue;
-					}
+        // TODO: Fix the code below after deviceStorage was removed
+        /*
+        IDeviceObject targetDevice =
+        		deviceStorage.getDeviceByIP(InetAddresses.coerceToInteger(target));
+        */
 
-					short outPort = portObject.getNumber();
-					ISwitchObject outSwitchObject = portObject.getSwitch();
-					long outSwitch = HexString.toLong(outSwitchObject.getDPID());
+        // TODO: Fix the code below after deviceStorage was removed
+        /*
+        if (targetDevice == null) {
+        	if (log.isTraceEnabled()) {
+        		log.trace("No device info found for {} - broadcasting",
+        				target.getHostAddress());
+        	}
 
-					if (log.isTraceEnabled()) {
-						log.trace("Probing device {} on port {}/{}", 
-								new Object[] {macAddress, 
-								HexString.toHexString(outSwitch), outPort});
-					}
-					
-					datagrid.sendPacketOutNotification(
-							new SinglePacketOutNotification(eth.serialize(), 
-									target, outSwitch, outPort));
-				}
-			}
-		}
-		*/
-	}
-	
-	private void handleArpReply(IOFSwitch sw, OFPacketIn pi, ARP arp){
-		if (log.isTraceEnabled()) {
-			log.trace("ARP reply recieved: {} => {}, on {}/{}", new Object[] { 
-					inetAddressToString(arp.getSenderProtocolAddress()),
-					HexString.toHexString(arp.getSenderHardwareAddress()),
-					HexString.toHexString(sw.getId()), pi.getInPort()});
-		}
-		
-		InetAddress senderIpAddress;
-		try {
-			senderIpAddress = InetAddress.getByAddress(arp.getSenderProtocolAddress());
-		} catch (UnknownHostException e) {
-			log.debug("Invalid address in ARP reply", e);
-			return;
-		}
-		
-		MACAddress senderMacAddress = MACAddress.valueOf(arp.getSenderHardwareAddress());
-		
-		//See if anyone's waiting for this ARP reply
-		Set<ArpRequest> requests = arpRequests.get(senderIpAddress);
-		
-		//Synchronize on the Multimap while using an iterator for one of the sets
-		List<ArpRequest> requestsToSend = new ArrayList<ArpRequest>(requests.size());
-		synchronized (arpRequests) {
-			Iterator<ArpRequest> it = requests.iterator();
-			while (it.hasNext()) {
-				ArpRequest request = it.next();
-				it.remove();
-				requestsToSend.add(request);
-			}
-		}
-		
-		//Don't hold an ARP lock while dispatching requests
-		for (ArpRequest request : requestsToSend) {
-			request.dispatchReply(senderIpAddress, senderMacAddress);
-		}
-	}
-	
-	private void sendArpRequestForAddress(InetAddress ipAddress) {
-		//TODO what should the sender IP address and MAC address be if no
-		//IP addresses are configured? Will there ever be a need to send
-		//ARP requests from the controller in that case?
-		//All-zero MAC address doesn't seem to work - hosts don't respond to it
-		
-		byte[] zeroIpv4 = {0x0, 0x0, 0x0, 0x0};
-		byte[] zeroMac = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0};
-		byte[] genericNonZeroMac = {0x0, 0x0, 0x0, 0x0, 0x0, 0x01};
-		byte[] broadcastMac = {(byte)0xff, (byte)0xff, (byte)0xff, 
-				(byte)0xff, (byte)0xff, (byte)0xff};
-		
-		ARP arpRequest = new ARP();
-		
-		arpRequest.setHardwareType(ARP.HW_TYPE_ETHERNET)
-			.setProtocolType(ARP.PROTO_TYPE_IP)
-			.setHardwareAddressLength((byte)Ethernet.DATALAYER_ADDRESS_LENGTH)
-			.setProtocolAddressLength((byte)IPv4.ADDRESS_LENGTH)
-			.setOpCode(ARP.OP_REQUEST)
-			.setTargetHardwareAddress(zeroMac)
-			.setTargetProtocolAddress(ipAddress.getAddress());
+        	// We don't know the device so broadcast the request out
+        	datagrid.sendPacketOutNotification(
+        			new BroadcastPacketOutNotification(eth.serialize(),
+        					target, sw.getId(), pi.getInPort()));
+        }
+        else {
+        	// Even if the device exists in our database, we do not reply to
+        	// the request directly, but check whether the device is still valid
+        	MACAddress macAddress = MACAddress.valueOf(targetDevice.getMACAddress());
 
-		MACAddress routerMacAddress = configService.getRouterMacAddress();
-		//TODO hack for now as it's unclear what the MAC address should be
-		byte[] senderMacAddress = genericNonZeroMac;
-		if (routerMacAddress != null) {
-			senderMacAddress = routerMacAddress.toBytes();
-		}
-		arpRequest.setSenderHardwareAddress(senderMacAddress);
-		
-		byte[] senderIPAddress = zeroIpv4;
-		Interface intf = configService.getOutgoingInterface(ipAddress);
-		if (intf != null) {
-			senderIPAddress = intf.getIpAddress().getAddress();
-		}
-		
-		arpRequest.setSenderProtocolAddress(senderIPAddress);
-		
-		Ethernet eth = new Ethernet();
-		eth.setSourceMACAddress(senderMacAddress)
-			.setDestinationMACAddress(broadcastMac)
-			.setEtherType(Ethernet.TYPE_ARP)
-			.setPayload(arpRequest);
-		
-		if (vlan != NO_VLAN) {
-			eth.setVlanID(vlan)
-			   .setPriorityCode((byte)0);
-		}
-		
-		//sendArpRequestToSwitches(ipAddress, eth.serialize());
-		datagrid.sendPacketOutNotification(new SinglePacketOutNotification(eth.serialize(),
-				ipAddress, intf.getDpid(),intf.getPort()));
-	}
-	
-	private void sendArpRequestToSwitches(InetAddress dstAddress, byte[] arpRequest) {
-		sendArpRequestToSwitches(dstAddress, arpRequest, 
-				0, OFPort.OFPP_NONE.getValue());
-	}
-	
-	private void sendArpRequestToSwitches(InetAddress dstAddress, byte[] arpRequest,
-			long inSwitch, short inPort) {
+        	if (log.isTraceEnabled()) {
+        		log.trace("The target Device Record in DB is: {} => {} from ARP request host at {}/{}",
+        				new Object [] {
+        				inetAddressToString(arp.getTargetProtocolAddress()),
+        				macAddress,
+        				HexString.toHexString(sw.getId()), pi.getInPort()});
+        	}
 
-		if (configService.hasLayer3Configuration()) {
-			Interface intf = configService.getOutgoingInterface(dstAddress);
-			if (intf != null) {
-				sendArpRequestOutPort(arpRequest, intf.getDpid(), intf.getPort());
-			}
-			else {
-				//TODO here it should be broadcast out all non-interface edge ports.
-				//I think we can assume that if it's not a request for an external 
-				//network, it's an ARP for a host in our own network. So we want to 
-				//send it out all edge ports that don't have an interface configured
-				//to ensure it reaches all hosts in our network.
-				log.debug("No interface found to send ARP request for {}",
-						dstAddress.getHostAddress());
-			}
-		}
-		else {
-			//broadcastArpRequestOutEdge(arpRequest, inSwitch, inPort);
-			broadcastArpRequestOutMyEdge(arpRequest, inSwitch, inPort);
-		}
-	}
-	
-	private void sendArpReplyNotification(Ethernet eth, OFPacketIn pi) {
-		ARP arp = (ARP) eth.getPayload();
-		
-		if (log.isTraceEnabled()) {
-			log.trace("Sending ARP reply for {} to other ONOS instances",
-					inetAddressToString(arp.getSenderProtocolAddress()));
-		}
-		
-		InetAddress targetAddress;		
-		MACAddress mac = new MACAddress(arp.getSenderHardwareAddress());
-		
-		try {
-			targetAddress = InetAddress.getByAddress(arp.getSenderProtocolAddress());
-		} catch (UnknownHostException e) {
-			log.error("Unknown host", e);
-			return;
-		}
+        	// sendArpReply(arp, sw.getId(), pi.getInPort(), macAddress);
 
-		datagrid.sendArpReplyNotification(new ArpReplyNotification(targetAddress, mac));
-	}
-	
-	private void broadcastArpRequestOutMyEdge(byte[] arpRequest,
-			long inSwitch, short inPort) {
-		List<SwitchPort> switchPorts = new ArrayList<SwitchPort>();
-		
-		for (IOFSwitch sw : floodlightProvider.getSwitches().values()) {
-			
-			OFPacketOut po = new OFPacketOut();
-			po.setInPort(OFPort.OFPP_NONE)
-			.setBufferId(-1)
-			.setPacketData(arpRequest);
-			
-			List<OFAction> actions = new ArrayList<OFAction>();
+        	Iterable<IPortObject> outPorts = targetDevice.getAttachedPorts();
 
-			// TODO: Fix the code below after topoSwitchService was removed
-			/*
-			Iterable<IPortObject> ports 
-				= topoSwitchService.getPortsOnSwitch(sw.getStringId());
-			if (ports == null) {
-				continue;
-			}
-			
-			for (IPortObject portObject : ports) {
-				if (!portObject.getLinkedPorts().iterator().hasNext()) {
-					short portNumber = portObject.getNumber();
-					
-					if (sw.getId() == inSwitch && portNumber == inPort) {
-						// This is the port that the ARP message came in,
-						// so don't broadcast out this port
-						continue;
-					}
-					
-					switchPorts.add(new SwitchPort(new Dpid(sw.getId()), 
-							new Port(portNumber)));
-					actions.add(new OFActionOutput(portNumber));
-				}
-			}
-			*/
-			
-			po.setActions(actions);
-			short actionsLength = (short) 
-					(actions.size() * OFActionOutput.MINIMUM_LENGTH);
-			po.setActionsLength(actionsLength);
-			po.setLengthU(OFPacketOut.MINIMUM_LENGTH + actionsLength 
-					+ arpRequest.length);
-			
-			flowPusher.add(sw, po);
-		}
-		
-		if (log.isTraceEnabled()) {
-			log.trace("Broadcast ARP request to: {}", switchPorts);
-		}
-	}
-	
-	private void sendArpRequestOutPort(byte[] arpRequest, long dpid, short port) {
-		if (log.isTraceEnabled()) {
-			log.trace("Sending ARP request out {}/{}", 
-					HexString.toHexString(dpid), port);
-		}
-		
-		OFPacketOut po = new OFPacketOut();
-		po.setInPort(OFPort.OFPP_NONE)
-			.setBufferId(-1)
-			.setPacketData(arpRequest);
-			
-		List<OFAction> actions = new ArrayList<OFAction>();
-		actions.add(new OFActionOutput(port));
-		po.setActions(actions);
-		short actionsLength = (short) (actions.size() * OFActionOutput.MINIMUM_LENGTH);
-		po.setActionsLength(actionsLength);
-		po.setLengthU(OFPacketOut.MINIMUM_LENGTH + actionsLength 
-				+ arpRequest.length);
-		
-		IOFSwitch sw = floodlightProvider.getSwitches().get(dpid);
-		
-		if (sw == null) {
-			log.warn("Switch not found when sending ARP request");
-			return;
-		}
-		
-		flowPusher.add(sw, po);
-	}
-	
-	private void sendArpReply(ARP arpRequest, long dpid, short port, MACAddress targetMac) {
-		if (log.isTraceEnabled()) {
-			log.trace("Sending reply {} => {} to {}", new Object[] {
-					inetAddressToString(arpRequest.getTargetProtocolAddress()),
-					targetMac,
-					inetAddressToString(arpRequest.getSenderProtocolAddress())});
-		}
-		
-		ARP arpReply = new ARP();
-		arpReply.setHardwareType(ARP.HW_TYPE_ETHERNET)
-			.setProtocolType(ARP.PROTO_TYPE_IP)
-			.setHardwareAddressLength((byte)Ethernet.DATALAYER_ADDRESS_LENGTH)
-			.setProtocolAddressLength((byte)IPv4.ADDRESS_LENGTH)
-			.setOpCode(ARP.OP_REPLY)
-			.setSenderHardwareAddress(targetMac.toBytes())
-			.setSenderProtocolAddress(arpRequest.getTargetProtocolAddress())
-			.setTargetHardwareAddress(arpRequest.getSenderHardwareAddress())
-			.setTargetProtocolAddress(arpRequest.getSenderProtocolAddress());
-		
+        	if (!outPorts.iterator().hasNext()){
+        		if (log.isTraceEnabled()) {
+        			log.trace("Device {} exists but is not connected to any ports" +
+        					" - broadcasting", macAddress);
+        		}
 
-		Ethernet eth = new Ethernet();
-		eth.setDestinationMACAddress(arpRequest.getSenderHardwareAddress())
-			.setSourceMACAddress(targetMac.toBytes())
-			.setEtherType(Ethernet.TYPE_ARP)
-			.setPayload(arpReply);
-		
-		if (vlan != NO_VLAN) {
-			eth.setVlanID(vlan)
-			   .setPriorityCode((byte)0);
-		}
-		
-		List<OFAction> actions = new ArrayList<OFAction>();
-		actions.add(new OFActionOutput(port));
-		
-		OFPacketOut po = new OFPacketOut();
-		po.setInPort(OFPort.OFPP_NONE)
-			.setBufferId(-1)
-			.setPacketData(eth.serialize())
-			.setActions(actions)
-			.setActionsLength((short)OFActionOutput.MINIMUM_LENGTH)
-			.setLengthU(OFPacketOut.MINIMUM_LENGTH + OFActionOutput.MINIMUM_LENGTH
-					+ po.getPacketData().length);
-		
-		List<OFMessage> msgList = new ArrayList<OFMessage>();
-		msgList.add(po);
+        		datagrid.sendPacketOutNotification(
+        				new BroadcastPacketOutNotification(eth.serialize(),
+        						target, sw.getId(), pi.getInPort()));
+        	}
+        	else {
+        		for (IPortObject portObject : outPorts) {
+        			//long outSwitch = 0;
+        			//short outPort = 0;
 
-		IOFSwitch sw = floodlightProvider.getSwitches().get(dpid);
-		
-		if (sw == null) {
-			log.warn("Switch {} not found when sending ARP reply", 
-					HexString.toHexString(dpid));
-			return;
-		}
-		
-		flowPusher.add(sw, po);
-	}
-	
-	private String inetAddressToString(byte[] bytes) {
-		try {
-			return InetAddress.getByAddress(bytes).getHostAddress();
-		} catch (UnknownHostException e) {
-			log.debug("Invalid IP address", e);
-			return "";
-		}
-	}
-	
-	/*
-	 * IProxyArpService methods
-	 */
+        			// if (!portObject.getLinkedPorts().iterator().hasNext()) {
+        			//	outPort = portObject.getNumber();
+        			// }
+        			if (portObject.getLinkedPorts().iterator().hasNext()) {
+        				continue;
+        			}
 
-	@Override
-	public MACAddress getMacAddress(InetAddress ipAddress) {
-		//return arpCache.lookup(ipAddress);
-		return null;
-	}
+        			short outPort = portObject.getNumber();
+        			ISwitchObject outSwitchObject = portObject.getSwitch();
+        			long outSwitch = HexString.toLong(outSwitchObject.getDPID());
 
-	@Override
-	public void sendArpRequest(InetAddress ipAddress, IArpRequester requester,
-			boolean retry) {
-		arpRequests.put(ipAddress, new ArpRequest(requester, retry));
-		
-		//Sanity check to make sure we don't send a request for our own address
-		if (!configService.isInterfaceAddress(ipAddress)) {
-			sendArpRequestForAddress(ipAddress);
-		}
-	}
-	
-	@Override
-	public List<String> getMappings() {
-		//return arpCache.getMappings();
-		return new ArrayList<String>();
-	}
+        			if (log.isTraceEnabled()) {
+        				log.trace("Probing device {} on port {}/{}",
+        						new Object[] {macAddress,
+        						HexString.toHexString(outSwitch), outPort});
+        			}
 
-	/*
-	@Override
-	public void arpRequestNotification(ArpMessage arpMessage) {
-		log.debug("Received ARP notification from other instances");
+        			datagrid.sendPacketOutNotification(
+        					new SinglePacketOutNotification(eth.serialize(),
+        							target, outSwitch, outPort));
+        		}
+        	}
+        }
+        */
+    }
 
-		switch (arpMessage.getType()){
-		case REQUEST:
-			if(arpMessage.getOutSwitch() == -1 || arpMessage.getOutPort() == -1){	
-				broadcastArpRequestOutMyEdge(arpMessage.getPacket(),
-						arpMessage.getInSwitch(), arpMessage.getInPort());					
-			}else{					
-				sendArpRequestOutPort(arpMessage.getPacket(),arpMessage.getOutSwitch(),arpMessage.getOutPort());
-				log.debug("OutSwitch in ARP request message is: {}; OutPort in ARP request message is: {}",arpMessage.getOutSwitch(),arpMessage.getOutPort());
-			}
-			break;
-		case REPLY:
-			log.debug("Received ARP reply notification for {}",
-					arpMessage.getAddress());
-			sendArpReplyToWaitingRequesters(arpMessage.getAddress(),arpMessage.getMAC());
-			break;
-		}
-	}
-	*/
-	
-	private void sendArpReplyToWaitingRequesters(InetAddress address, MACAddress mac) {
-		log.debug("Sending ARP reply for {} to requesters", 
-				address.getHostAddress());
-		
-		//See if anyone's waiting for this ARP reply
-		Set<ArpRequest> requests = arpRequests.get(address);
-		
-		//Synchronize on the Multimap while using an iterator for one of the sets
-		List<ArpRequest> requestsToSend = new ArrayList<ArpRequest>(requests.size());
-		synchronized (arpRequests) {
-			Iterator<ArpRequest> it = requests.iterator();
-			while (it.hasNext()) {
-				ArpRequest request = it.next();
-				it.remove();
-				requestsToSend.add(request);
-			}
-		}
-		
-		/*IDeviceObject deviceObject = deviceStorage.getDeviceByIP(
-				InetAddresses.coerceToInteger(address));
-		
-		MACAddress mac = MACAddress.valueOf(deviceObject.getMACAddress());
-		
-		log.debug("Found {} at {} in network map", 
-				address.getHostAddress(), mac);*/
-		
-		//Don't hold an ARP lock while dispatching requests
-		for (ArpRequest request : requestsToSend) {
-			request.dispatchReply(address, mac);
-		}
-	}
+    // Not used because device manager currently updates the database
+    // for ARP replies. May be useful in the future.
+    private void handleArpReply(IOFSwitch sw, OFPacketIn pi, ARP arp) {
+        if (log.isTraceEnabled()) {
+            log.trace("ARP reply recieved: {} => {}, on {}/{}", new Object[] {
+                    inetAddressToString(arp.getSenderProtocolAddress()),
+                    HexString.toHexString(arp.getSenderHardwareAddress()),
+                    HexString.toHexString(sw.getId()), pi.getInPort()});
+        }
 
-	@Override
-	public void arpReplyEvent(ArpReplyNotification arpReply) {
-		log.debug("Received ARP reply notification for {}",
-				arpReply.getTargetAddress());
-		sendArpReplyToWaitingRequesters(arpReply.getTargetAddress(), 
-				arpReply.getTargetMacAddress());
-	}
+        InetAddress senderIpAddress;
+        try {
+            senderIpAddress = InetAddress.getByAddress(arp
+                    .getSenderProtocolAddress());
+        } catch (UnknownHostException e) {
+            log.debug("Invalid address in ARP reply", e);
+            return;
+        }
 
-	@Override
-	public void packetOutNotification(
-			PacketOutNotification packetOutNotification) {
-		
-		if (packetOutNotification instanceof SinglePacketOutNotification) {
-			SinglePacketOutNotification notification = 
-					(SinglePacketOutNotification) packetOutNotification;
-			sendArpRequestOutPort(notification.packet, notification.getOutSwitch(), 
-					notification.getOutPort());
-			
-			// set timestamp
-			InetAddress addr = notification.getTargetAddress();
-			if (addr != null) {
-				for (ArpRequest request : arpRequests.get(addr)) {
-					request.setRequestTime();
-				}
-			}
-		}
-		else if (packetOutNotification instanceof BroadcastPacketOutNotification) {
-			BroadcastPacketOutNotification notification = 
-					(BroadcastPacketOutNotification) packetOutNotification;
-			broadcastArpRequestOutMyEdge(notification.packet, 
-					notification.getInSwitch(), notification.getInPort());
-			
-			// set timestamp
-			InetAddress addr = notification.getTargetAddress();
-			if (addr != null) {
-				for (ArpRequest request : arpRequests.get(addr)) {
-					request.setRequestTime();
-				}
-			}
-		}
-		else {
-			log.warn("Unknown packet out notification received");
-		}
-	}
+        MACAddress senderMacAddress = MACAddress.valueOf(arp
+                .getSenderHardwareAddress());
+
+        // See if anyone's waiting for this ARP reply
+        Set<ArpRequest> requests = arpRequests.get(senderIpAddress);
+
+        // Synchronize on the Multimap while using an iterator for one of the
+        // sets
+        List<ArpRequest> requestsToSend = new ArrayList<ArpRequest>(
+                requests.size());
+        synchronized (arpRequests) {
+            Iterator<ArpRequest> it = requests.iterator();
+            while (it.hasNext()) {
+                ArpRequest request = it.next();
+                it.remove();
+                requestsToSend.add(request);
+            }
+        }
+
+        // Don't hold an ARP lock while dispatching requests
+        for (ArpRequest request : requestsToSend) {
+            request.dispatchReply(senderIpAddress, senderMacAddress);
+        }
+    }
+
+    private void sendArpRequestForAddress(InetAddress ipAddress) {
+        // TODO what should the sender IP address and MAC address be if no
+        // IP addresses are configured? Will there ever be a need to send
+        // ARP requests from the controller in that case?
+        // All-zero MAC address doesn't seem to work - hosts don't respond to it
+
+        byte[] zeroIpv4 = {0x0, 0x0, 0x0, 0x0};
+        byte[] zeroMac = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0};
+        byte[] genericNonZeroMac = {0x0, 0x0, 0x0, 0x0, 0x0, 0x01};
+        byte[] broadcastMac = {(byte) 0xff, (byte) 0xff, (byte) 0xff,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff};
+
+        ARP arpRequest = new ARP();
+
+        arpRequest
+                .setHardwareType(ARP.HW_TYPE_ETHERNET)
+                .setProtocolType(ARP.PROTO_TYPE_IP)
+                .setHardwareAddressLength(
+                        (byte) Ethernet.DATALAYER_ADDRESS_LENGTH)
+                .setProtocolAddressLength((byte) IPv4.ADDRESS_LENGTH)
+                .setOpCode(ARP.OP_REQUEST).setTargetHardwareAddress(zeroMac)
+                .setTargetProtocolAddress(ipAddress.getAddress());
+
+        MACAddress routerMacAddress = configService.getRouterMacAddress();
+        // TODO hack for now as it's unclear what the MAC address should be
+        byte[] senderMacAddress = genericNonZeroMac;
+        if (routerMacAddress != null) {
+            senderMacAddress = routerMacAddress.toBytes();
+        }
+        arpRequest.setSenderHardwareAddress(senderMacAddress);
+
+        byte[] senderIPAddress = zeroIpv4;
+        Interface intf = configService.getOutgoingInterface(ipAddress);
+        if (intf != null) {
+            senderIPAddress = intf.getIpAddress().getAddress();
+        }
+
+        arpRequest.setSenderProtocolAddress(senderIPAddress);
+
+        Ethernet eth = new Ethernet();
+        eth.setSourceMACAddress(senderMacAddress)
+                .setDestinationMACAddress(broadcastMac)
+                .setEtherType(Ethernet.TYPE_ARP).setPayload(arpRequest);
+
+        if (vlan != NO_VLAN) {
+            eth.setVlanID(vlan).setPriorityCode((byte) 0);
+        }
+
+        // sendArpRequestToSwitches(ipAddress, eth.serialize());
+        datagrid.sendPacketOutNotification(new SinglePacketOutNotification(eth
+                .serialize(), ipAddress, intf.getDpid(), intf.getPort()));
+    }
+
+    private void sendArpRequestToSwitches(InetAddress dstAddress,
+            byte[] arpRequest) {
+        sendArpRequestToSwitches(dstAddress, arpRequest, 0,
+                OFPort.OFPP_NONE.getValue());
+    }
+
+    private void sendArpRequestToSwitches(InetAddress dstAddress,
+            byte[] arpRequest, long inSwitch, short inPort) {
+
+        if (configService.hasLayer3Configuration()) {
+            Interface intf = configService.getOutgoingInterface(dstAddress);
+            if (intf == null) {
+                // TODO here it should be broadcast out all non-interface edge
+                // ports.
+                // I think we can assume that if it's not a request for an
+                // external
+                // network, it's an ARP for a host in our own network. So we
+                // want to
+                // send it out all edge ports that don't have an interface
+                // configured
+                // to ensure it reaches all hosts in our network.
+                log.debug("No interface found to send ARP request for {}",
+                        dstAddress.getHostAddress());
+            } else {
+                sendArpRequestOutPort(arpRequest, intf.getDpid(),
+                        intf.getPort());
+            }
+        } else {
+            // broadcastArpRequestOutEdge(arpRequest, inSwitch, inPort);
+            broadcastArpRequestOutMyEdge(arpRequest, inSwitch, inPort);
+        }
+    }
+
+    private void sendArpReplyNotification(Ethernet eth, OFPacketIn pi) {
+        ARP arp = (ARP) eth.getPayload();
+
+        if (log.isTraceEnabled()) {
+            log.trace("Sending ARP reply for {} to other ONOS instances",
+                    inetAddressToString(arp.getSenderProtocolAddress()));
+        }
+
+        InetAddress targetAddress;
+
+        try {
+            targetAddress = InetAddress.getByAddress(arp
+                    .getSenderProtocolAddress());
+        } catch (UnknownHostException e) {
+            log.error("Unknown host", e);
+            return;
+        }
+
+        MACAddress mac = new MACAddress(arp.getSenderHardwareAddress());
+
+        datagrid.sendArpReplyNotification(new ArpReplyNotification(
+                targetAddress, mac));
+    }
+
+    private void broadcastArpRequestOutMyEdge(byte[] arpRequest, long inSwitch,
+            short inPort) {
+        List<SwitchPort> switchPorts = new ArrayList<SwitchPort>();
+
+        for (IOFSwitch sw : floodlightProvider.getSwitches().values()) {
+
+            OFPacketOut po = new OFPacketOut();
+            po.setInPort(OFPort.OFPP_NONE).setBufferId(-1)
+                    .setPacketData(arpRequest);
+
+            List<OFAction> actions = new ArrayList<OFAction>();
+
+            // TODO: Fix the code below after topoSwitchService was removed
+            /*
+            Iterable<IPortObject> ports
+            	= topoSwitchService.getPortsOnSwitch(sw.getStringId());
+            if (ports == null) {
+            	continue;
+            }
+
+            for (IPortObject portObject : ports) {
+            	if (!portObject.getLinkedPorts().iterator().hasNext()) {
+            		short portNumber = portObject.getNumber();
+
+            		if (sw.getId() == inSwitch && portNumber == inPort) {
+            			// This is the port that the ARP message came in,
+            			// so don't broadcast out this port
+            			continue;
+            		}
+
+            		switchPorts.add(new SwitchPort(new Dpid(sw.getId()),
+            				new Port(portNumber)));
+            		actions.add(new OFActionOutput(portNumber));
+            	}
+            }
+            */
+
+            po.setActions(actions);
+            short actionsLength = (short) (actions.size() * OFActionOutput.MINIMUM_LENGTH);
+            po.setActionsLength(actionsLength);
+            po.setLengthU(OFPacketOut.MINIMUM_LENGTH + actionsLength
+                    + arpRequest.length);
+
+            flowPusher.add(sw, po);
+        }
+
+        if (log.isTraceEnabled()) {
+            log.trace("Broadcast ARP request to: {}", switchPorts);
+        }
+    }
+
+    private void sendArpRequestOutPort(byte[] arpRequest, long dpid, short port) {
+        if (log.isTraceEnabled()) {
+            log.trace("Sending ARP request out {}/{}",
+                    HexString.toHexString(dpid), port);
+        }
+
+        OFPacketOut po = new OFPacketOut();
+        po.setInPort(OFPort.OFPP_NONE).setBufferId(-1)
+                .setPacketData(arpRequest);
+
+        List<OFAction> actions = new ArrayList<OFAction>();
+        actions.add(new OFActionOutput(port));
+        po.setActions(actions);
+        short actionsLength = (short) (actions.size() * OFActionOutput.MINIMUM_LENGTH);
+        po.setActionsLength(actionsLength);
+        po.setLengthU(OFPacketOut.MINIMUM_LENGTH + actionsLength
+                + arpRequest.length);
+
+        IOFSwitch sw = floodlightProvider.getSwitches().get(dpid);
+
+        if (sw == null) {
+            log.warn("Switch not found when sending ARP request");
+            return;
+        }
+
+        flowPusher.add(sw, po);
+    }
+
+    private void sendArpReply(ARP arpRequest, long dpid, short port,
+            MACAddress targetMac) {
+        if (log.isTraceEnabled()) {
+            log.trace(
+                    "Sending reply {} => {} to {}",
+                    new Object[] {
+                            inetAddressToString(arpRequest
+                                    .getTargetProtocolAddress()),
+                            targetMac,
+                            inetAddressToString(arpRequest
+                                    .getSenderProtocolAddress())});
+        }
+
+        ARP arpReply = new ARP();
+        arpReply.setHardwareType(ARP.HW_TYPE_ETHERNET)
+                .setProtocolType(ARP.PROTO_TYPE_IP)
+                .setHardwareAddressLength(
+                        (byte) Ethernet.DATALAYER_ADDRESS_LENGTH)
+                .setProtocolAddressLength((byte) IPv4.ADDRESS_LENGTH)
+                .setOpCode(ARP.OP_REPLY)
+                .setSenderHardwareAddress(targetMac.toBytes())
+                .setSenderProtocolAddress(arpRequest.getTargetProtocolAddress())
+                .setTargetHardwareAddress(arpRequest.getSenderHardwareAddress())
+                .setTargetProtocolAddress(arpRequest.getSenderProtocolAddress());
+
+        Ethernet eth = new Ethernet();
+        eth.setDestinationMACAddress(arpRequest.getSenderHardwareAddress())
+                .setSourceMACAddress(targetMac.toBytes())
+                .setEtherType(Ethernet.TYPE_ARP).setPayload(arpReply);
+
+        if (vlan != NO_VLAN) {
+            eth.setVlanID(vlan).setPriorityCode((byte) 0);
+        }
+
+        List<OFAction> actions = new ArrayList<OFAction>();
+        actions.add(new OFActionOutput(port));
+
+        OFPacketOut po = new OFPacketOut();
+        po.setInPort(OFPort.OFPP_NONE)
+                .setBufferId(-1)
+                .setPacketData(eth.serialize())
+                .setActions(actions)
+                .setActionsLength((short) OFActionOutput.MINIMUM_LENGTH)
+                .setLengthU(
+                        OFPacketOut.MINIMUM_LENGTH
+                                + OFActionOutput.MINIMUM_LENGTH
+                                + po.getPacketData().length);
+
+        List<OFMessage> msgList = new ArrayList<OFMessage>();
+        msgList.add(po);
+
+        IOFSwitch sw = floodlightProvider.getSwitches().get(dpid);
+
+        if (sw == null) {
+            log.warn("Switch {} not found when sending ARP reply",
+                    HexString.toHexString(dpid));
+            return;
+        }
+
+        flowPusher.add(sw, po);
+    }
+
+    private String inetAddressToString(byte[] bytes) {
+        try {
+            return InetAddress.getByAddress(bytes).getHostAddress();
+        } catch (UnknownHostException e) {
+            log.debug("Invalid IP address", e);
+            return "";
+        }
+    }
+
+    /*
+     * IProxyArpService methods
+     */
+
+    @Override
+    public MACAddress getMacAddress(InetAddress ipAddress) {
+        // return arpCache.lookup(ipAddress);
+        return null;
+    }
+
+    @Override
+    public void sendArpRequest(InetAddress ipAddress, IArpRequester requester,
+            boolean retry) {
+        arpRequests.put(ipAddress, new ArpRequest(requester, retry));
+
+        // Sanity check to make sure we don't send a request for our own address
+        if (!configService.isInterfaceAddress(ipAddress)) {
+            sendArpRequestForAddress(ipAddress);
+        }
+    }
+
+    @Override
+    public List<String> getMappings() {
+        return new ArrayList<String>();
+    }
+
+    /*
+    @Override
+    public void arpRequestNotification(ArpMessage arpMessage) {
+    	log.debug("Received ARP notification from other instances");
+
+    	switch (arpMessage.getType()){
+    	case REQUEST:
+    		if(arpMessage.getOutSwitch() == -1 || arpMessage.getOutPort() == -1){
+    			broadcastArpRequestOutMyEdge(arpMessage.getPacket(),
+    					arpMessage.getInSwitch(), arpMessage.getInPort());
+    		}else{
+    			sendArpRequestOutPort(arpMessage.getPacket(),arpMessage.getOutSwitch(),arpMessage.getOutPort());
+    			log.debug("OutSwitch in ARP request message is: {}; " +
+    			"OutPort in ARP request message is: {}",arpMessage.getOutSwitch(),arpMessage.getOutPort());
+    		}
+    		break;
+    	case REPLY:
+    		log.debug("Received ARP reply notification for {}",
+    				arpMessage.getAddress());
+    		sendArpReplyToWaitingRequesters(arpMessage.getAddress(),arpMessage.getMAC());
+    		break;
+    	}
+    }
+    */
+
+    private void sendArpReplyToWaitingRequesters(InetAddress address,
+            MACAddress mac) {
+        log.debug("Sending ARP reply for {} to requesters",
+                address.getHostAddress());
+
+        // See if anyone's waiting for this ARP reply
+        Set<ArpRequest> requests = arpRequests.get(address);
+
+        // Synchronize on the Multimap while using an iterator for one of the
+        // sets
+        List<ArpRequest> requestsToSend = new ArrayList<ArpRequest>(
+                requests.size());
+        synchronized (arpRequests) {
+            Iterator<ArpRequest> it = requests.iterator();
+            while (it.hasNext()) {
+                ArpRequest request = it.next();
+                it.remove();
+                requestsToSend.add(request);
+            }
+        }
+
+        /*IDeviceObject deviceObject = deviceStorage.getDeviceByIP(
+        		InetAddresses.coerceToInteger(address));
+
+        MACAddress mac = MACAddress.valueOf(deviceObject.getMACAddress());
+
+        log.debug("Found {} at {} in network map",
+        		address.getHostAddress(), mac);*/
+
+        // Don't hold an ARP lock while dispatching requests
+        for (ArpRequest request : requestsToSend) {
+            request.dispatchReply(address, mac);
+        }
+    }
+
+    @Override
+    public void arpReplyEvent(ArpReplyNotification arpReply) {
+        log.debug("Received ARP reply notification for {}",
+                arpReply.getTargetAddress());
+        sendArpReplyToWaitingRequesters(arpReply.getTargetAddress(),
+                arpReply.getTargetMacAddress());
+    }
+
+    @Override
+    public void packetOutNotification(
+            PacketOutNotification packetOutNotification) {
+
+        if (packetOutNotification instanceof SinglePacketOutNotification) {
+            SinglePacketOutNotification notification = (SinglePacketOutNotification) packetOutNotification;
+            sendArpRequestOutPort(notification.packet,
+                    notification.getOutSwitch(), notification.getOutPort());
+
+            // set timestamp
+            InetAddress addr = notification.getTargetAddress();
+            if (addr != null) {
+                for (ArpRequest request : arpRequests.get(addr)) {
+                    request.setRequestTime();
+                }
+            }
+        } else if (packetOutNotification instanceof BroadcastPacketOutNotification) {
+            BroadcastPacketOutNotification notification = (BroadcastPacketOutNotification) packetOutNotification;
+            broadcastArpRequestOutMyEdge(notification.packet,
+                    notification.getInSwitch(), notification.getInPort());
+
+            // set timestamp
+            InetAddress addr = notification.getTargetAddress();
+            if (addr != null) {
+                for (ArpRequest request : arpRequests.get(addr)) {
+                    request.setRequestTime();
+                }
+            }
+        } else {
+            log.warn("Unknown packet out notification received");
+        }
+    }
 }