blob: 2355b0367fdaf970fa1d155c47eea33949b332d4 [file] [log] [blame]
package net.onrc.onos.ofcontroller.networkgraph;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import net.onrc.onos.datastore.topology.RCLink;
import net.onrc.onos.datastore.topology.RCPort;
import net.onrc.onos.datastore.topology.RCSwitch;
import net.onrc.onos.ofcontroller.networkgraph.PortEvent.SwitchPort;
import net.onrc.onos.ofcontroller.util.Dpid;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import edu.stanford.ramcloud.JRamCloud.ObjectDoesntExistException;
/**
* The "NB" read-only Network Map.
*
* - Maintain Invariant/Relationships between Topology Objects.
*
* TODO To be synchronized based on TopologyEvent Notification.
*
* TODO TBD: Caller is expected to maintain parent/child calling order. Parent
* Object must exist before adding sub component(Add Switch -> Port). Child
* Object need to be removed before removing parent (Delete Port->Switch)
*
* TODO TBD: This class may delay the requested change to handle event
* re-ordering. e.g.) Link Add came in, but Switch was not there.
*
*/
public class NetworkGraphImpl extends AbstractNetworkGraph implements
NetworkGraphDiscoveryInterface, NetworkGraphReplicationInterface {
private static final Logger log = LoggerFactory
.getLogger(NetworkGraphImpl.class);
private final NetworkGraphDatastore datastore;
public NetworkGraphImpl() {
super();
datastore = new NetworkGraphDatastore(this);
}
/**
* put Switch
*
* XXX Internal In-memory object mutation method. Will not write to DB.
* Will not fire Notification.
*
* @param swEvt
*/
void putSwitch(SwitchEvent swEvt) {
if (swEvt == null) {
throw new IllegalArgumentException("Switch cannot be null");
}
Switch sw = switches.get(swEvt.getDpid());
if (sw == null) {
sw = new SwitchImpl(this, swEvt.getDpid());
Switch existing = switches.putIfAbsent(swEvt.getDpid(), sw);
if (existing != null) {
log.warn(
"Concurrent putSwitch not expected. Continuing updating {}",
existing);
sw = existing;
}
}
// Update when more attributes are added to Event object
// no attribute to update for now
// TODO handle child Port event properly for performance
for (PortEvent portEvt : swEvt.getPorts() ) {
putPort(portEvt);
}
}
/**
* remove Switch.
*
* XXX Internal In-memory object mutation method. Will not write to DB.
* Will not fire Notification.
*
* @param swEvt
*/
void removeSwitch(SwitchEvent swEvt) {
if (swEvt == null) {
throw new IllegalArgumentException("Switch cannot be null");
}
// TODO handle child Port event properly for performance
for (PortEvent portEvt : swEvt.getPorts() ) {
removePort(portEvt);
}
Switch sw = switches.get(swEvt.getDpid());
if (sw == null) {
log.warn("Switch {} already removed, ignoring", swEvt);
return;
}
// Sanity check
if (!sw.getPorts().isEmpty()) {
log.warn(
"Ports on Switch {} should be removed prior to removing Switch. Removing Switch anyways",
swEvt);
// XXX Should we remove Port?
}
if (!sw.getDevices().isEmpty()) {
log.warn(
"Devices on Switch {} should be removed prior to removing Switch. Removing Switch anyways",
swEvt);
// XXX Should we remove Device to Switch relation?
}
if (!sw.getIncomingLinks().iterator().hasNext()) {
log.warn(
"IncomingLinks on Switch {} should be removed prior to removing Switch. Removing Switch anyways",
swEvt);
// XXX Should we remove Link?
}
if (!sw.getOutgoingLinks().iterator().hasNext()) {
log.warn(
"OutgoingLinks on Switch {} should be removed prior to removing Switch. Removing Switch anyways",
swEvt);
// XXX Should we remove Link?
}
boolean removed = switches.remove(swEvt.getDpid(), sw);
if (removed) {
log.warn(
"Switch instance was replaced concurrently while removing {}. Something is not right.",
sw);
}
}
/**
* put Port
*
* XXX Internal In-memory object mutation method. Will not write to DB.
* Will not fire Notification.
*
* @param portEvt
*/
void putPort(PortEvent portEvt) {
if (portEvt == null) {
throw new IllegalArgumentException("Port cannot be null");
}
Switch sw = switches.get(portEvt.getDpid());
if (sw == null) {
throw new BrokenInvariantException(String.format(
"Switch with dpid %s did not exist.",
new Dpid(portEvt.getDpid())));
}
Port p = sw.getPort(portEvt.getNumber());
PortImpl port = null;
if (p != null) {
port = getPortImpl(p);
}
if (port == null) {
port = new PortImpl(this, sw, portEvt.getNumber());
}
// TODO update attributes
SwitchImpl s = getSwitchImpl(sw);
s.addPort(port);
}
/**
* remove Port
*
* XXX Internal In-memory object mutation method. Will not write to DB.
* Will not fire Notification.
*
* @param portEvt
*/
void removePort(PortEvent portEvt) {
if (portEvt == null) {
throw new IllegalArgumentException("Port cannot be null");
}
Switch sw = switches.get(portEvt.getDpid());
if (sw == null) {
log.warn("Parent Switch for Port {} already removed, ignoring", portEvt);
return;
}
Port p = sw.getPort(portEvt.getNumber());
if (p == null) {
log.warn("Port {} already removed, ignoring", portEvt);
return;
}
// check if there is something referring to this Port
if (!p.getDevices().iterator().hasNext()) {
log.warn(
"Devices on Port {} should be removed prior to removing Port. Removing Port anyways",
portEvt);
// XXX Should we remove Device to Port relation?
}
if (p.getIncomingLink() != null) {
log.warn(
"IncomingLinks on Port {} should be removed prior to removing Port. Removing Port anyways",
portEvt);
// XXX Should we remove Link?
}
if (p.getOutgoingLink() != null) {
log.warn(
"OutgoingLinks on Port {} should be removed prior to removing Port. Removing Port anyways",
portEvt);
// XXX Should we remove Link?
}
// remove Port from Switch
SwitchImpl s = getSwitchImpl(sw);
s.removePort(p);
}
/**
* put Link
*
* XXX Internal In-memory object mutation method. Will not write to DB.
* Will not fire Notification.
*
* @param linkEvt
*/
void putLink(LinkEvent linkEvt) {
if (linkEvt == null) {
throw new IllegalArgumentException("Link cannot be null");
}
Switch srcSw = switches.get(linkEvt.getSrc().dpid);
if (srcSw == null) {
throw new BrokenInvariantException(
String.format(
"Switch with dpid %s did not exist.",
new Dpid(linkEvt.getSrc().dpid)));
}
Switch dstSw = switches.get(linkEvt.getDst().dpid);
if (dstSw == null) {
throw new BrokenInvariantException(
String.format(
"Switch with dpid %s did not exist.",
new Dpid(linkEvt.getDst().dpid)));
}
Port srcPort = srcSw.getPort(linkEvt.getSrc().number);
if (srcPort == null) {
throw new BrokenInvariantException(
String.format(
"Src Port %s of a Link did not exist.",
linkEvt.getSrc() ));
}
Port dstPort = dstSw.getPort(linkEvt.getDst().number);
if (dstPort == null) {
throw new BrokenInvariantException(
String.format(
"Dst Port %s of a Link did not exist.",
linkEvt.getDst() ));
}
// getting Link instance from destination port incoming Link
Link l = dstPort.getIncomingLink();
LinkImpl link = null;
assert( l == srcPort.getOutgoingLink() );
if (l != null) {
link = getLinkImpl(l);
}
if (link == null) {
link = new LinkImpl(this, srcPort, dstPort);
}
PortImpl dstPortMem = getPortImpl(dstPort);
PortImpl srcPortMem = getPortImpl(srcPort);
// Add Link first to avoid further Device addition
// add Link to Port
dstPortMem.setIncomingLink(link);
srcPortMem.setOutgoingLink(link);
// remove Device Pointing to Port if any
for(Device d : dstPortMem.getDevices() ) {
log.error("Device {} on Port {} should have been removed prior to adding Link {}", d, dstPort, linkEvt);
DeviceImpl dev = getDeviceImpl(d);
dev.removeAttachmentPoint(dstPort);
// XXX This implies that change is made to Device Object,
// which need to be written to DB, how should that be done?
// should we write here or ignore and leave DB in inconsistent state?
}
dstPortMem.removeAllDevice();
for(Device d : srcPortMem.getDevices() ) {
log.error("Device {} on Port {} should have been removed prior to adding Link {}", d, srcPort, linkEvt);
DeviceImpl dev = getDeviceImpl(d);
dev.removeAttachmentPoint(srcPort);
// XXX This implies that change is made to Device Object,
// which need to be written to DB, how should that be done?
// should we write here or ignore and leave DB in inconsistent state?
}
srcPortMem.removeAllDevice();
}
/**
* removeLink
*
* XXX Internal In-memory object mutation method. Will not write to DB.
* Will not fire Notification.
*
* @param linkEvt
*/
void removeLink(LinkEvent linkEvt) {
if (linkEvt == null) {
throw new IllegalArgumentException("Link cannot be null");
}
Switch srcSw = switches.get(linkEvt.getSrc().dpid);
if (srcSw == null) {
log.warn("Src Switch for Link {} already removed, ignoring", linkEvt);
return;
}
Switch dstSw = switches.get(linkEvt.getDst().dpid);
if (dstSw == null) {
log.warn("Dst Switch for Link {} already removed, ignoring", linkEvt);
return;
}
Port srcPort = srcSw.getPort(linkEvt.getSrc().number);
if (srcPort == null) {
log.warn("Src Port for Link {} already removed, ignoring", linkEvt);
return;
}
Port dstPort = dstSw.getPort(linkEvt.getDst().number);
if (dstPort == null) {
log.warn("Dst Port for Link {} already removed, ignoring", linkEvt);
return;
}
Link l = dstPort.getIncomingLink();
if ( l == null ) {
log.warn("Link {} already removed on destination Port", linkEvt);
}
l = srcPort.getOutgoingLink();
if ( l == null ) {
log.warn("Link {} already removed on src Port", linkEvt);
}
getPortImpl(dstPort).setIncomingLink(null);
getPortImpl(srcPort).setOutgoingLink(null);
}
// XXX Need to rework Device related
/**
* Add new device to DB
*
* @param device
*/
void putDevice(DeviceEvent deviceEvt) {
if (deviceEvt == null) {
throw new IllegalArgumentException("Device cannot be null");
}
// for each attachment point
/// TODO check if Link exist on that Port
// TODO Auto-generated method stub
// Device existingDevice =
// getDeviceByMac(deviceToUpdate.getMacAddress());
// if (existingDevice != deviceToUpdate) {
// throw new IllegalArgumentException(
// "Must supply Device Object in this NetworkGraph");
// }
//
// DeviceImpl device = getDeviceImpl(deviceToUpdate);
//
// // Update IP Addr
// // uniq
// Set<InetAddress> prevAddrs = new HashSet<>(
// deviceToUpdate.getIpAddress());
// Set<InetAddress> newAddrs = updatedIpAddrs;
//
// // delta
// @SuppressWarnings("unchecked")
// Collection<InetAddress> delAddr = CollectionUtils.subtract(newAddrs,
// prevAddrs);
// @SuppressWarnings("unchecked")
// Collection<InetAddress> addAddr = CollectionUtils.subtract(prevAddrs,
// newAddrs);
//
// for (InetAddress addr : delAddr) {
// Set<Device> devices = addr2Device.get(addr);
// if (devices == null) {
// continue;
// }
// devices.remove(device);
// device.removeIpAddress(addr);
// }
// for (InetAddress addr : addAddr) {
// Set<Device> devices = addr2Device.get(addr);
// if (devices == null) {
// devices = new HashSet<>();
// addr2Device.put(addr, devices);
// }
// devices.add(device);
// device.addIpAddress(addr);
// }
//
// // Update Attachment Point
// // uniq
// Set<Port> prevPorts = new HashSet<>();
// CollectionUtils.addAll(prevAddrs,
// deviceToUpdate.getAttachmentPoints()
// .iterator());
// Set<Port> newPorts = updatedAttachmentPoints;
// // delta
// @SuppressWarnings("unchecked")
// Collection<Port> delPorts = CollectionUtils.subtract(newPorts,
// prevPorts);
// @SuppressWarnings("unchecked")
// Collection<Port> addPorts = CollectionUtils.subtract(prevPorts,
// newPorts);
//
// for (Port p : delPorts) {
// device.removeAttachmentPoint(p);
// getPortImpl(p).removeDevice(device);
// }
//
// for (Port p : addPorts) {
// device.addAttachmentPoint(p);
// getPortImpl(p).addDevice(device);
// }
// TODO Auto-generated method stub
}
void removeDevice(DeviceEvent device) {
if (device == null) {
throw new IllegalArgumentException("Device cannot be null");
}
// TODO Auto-generated method stub
}
private SwitchImpl getSwitchImpl(Switch sw) {
if (sw instanceof SwitchImpl) {
return (SwitchImpl) sw;
}
throw new ClassCastException("SwitchImpl expected, but found: " + sw);
}
private PortImpl getPortImpl(Port p) {
if (p instanceof PortImpl) {
return (PortImpl) p;
}
throw new ClassCastException("PortImpl expected, but found: " + p);
}
private LinkImpl getLinkImpl(Link l) {
if (l instanceof LinkImpl) {
return (LinkImpl) l;
}
throw new ClassCastException("LinkImpl expected, but found: " + l);
}
private DeviceImpl getDeviceImpl(Device d) {
if (d instanceof DeviceImpl) {
return (DeviceImpl) d;
}
throw new ClassCastException("DeviceImpl expected, but found: " + d);
}
public void loadWholeTopologyFromDB() {
// TODO this method needs to use East-bound API if we still need this
// XXX clear everything first?
for (RCSwitch sw : RCSwitch.getAllSwitches()) {
try {
sw.read();
// TODO if there is going to be inactive Switch in DB, skip
// TODO update other attributes if there exist any
putSwitch(new SwitchEvent(sw.getDpid()));
} catch (ObjectDoesntExistException e) {
log.error("Read Switch Failed, skipping", e);
}
}
for (RCPort p : RCPort.getAllPorts()) {
try {
p.read();
Switch sw = this.getSwitch(p.getDpid());
if (sw == null) {
log.error("Switch {} missing when adding Port {}",
new Dpid(p.getDpid()), p);
continue;
}
PortEvent portEvent = new PortEvent(p.getDpid(), p.getNumber());
// TODO update other attributes if there exist any
putPort(portEvent);
} catch (ObjectDoesntExistException e) {
log.error("Read Port Failed, skipping", e);
}
}
// TODO Is Device going to be in DB? If so, read from DB.
// for (RCDevice d : RCDevice.getAllDevices()) {
// try {
// d.read();
//
// } catch (ObjectDoesntExistException e) {
// log.debug("Read Device Failed, skipping", e);
// }
// }
for (RCLink l : RCLink.getAllLinks()) {
try {
l.read();
Switch srcSw = this.getSwitch(l.getSrc().dpid);
if (srcSw == null) {
log.error("Switch {} missing when adding Link {}",
new Dpid(l.getSrc().dpid), l);
continue;
}
Switch dstSw = this.getSwitch(l.getDst().dpid);
if (dstSw == null) {
log.error("Switch {} missing when adding Link {}",
new Dpid(l.getDst().dpid), l);
continue;
}
LinkEvent linkEvent = new LinkEvent(l.getSrc().dpid,
l.getSrc().number, l.getDst().dpid, l.getDst().number);
// TODO update other attributes if there exist any
putLink(linkEvent);
} catch (ObjectDoesntExistException e) {
log.debug("Delete Link Failed", e);
}
}
}
/**
* Exception to be thrown when Modification to the Network Graph cannot be continued due to broken invariant.
*
* XXX Should this be checked exception or RuntimeException
*/
public static class BrokenInvariantException extends RuntimeException {
private static final long serialVersionUID = 1L;
public BrokenInvariantException() {
super();
}
public BrokenInvariantException(String message) {
super(message);
}
}
/* ******************************
* NetworkGraphDiscoveryInterface methods
* ******************************/
@Override
public void putSwitchEvent(SwitchEvent switchEvent) {
if (prepareForAddSwitchEvent(switchEvent)) {
datastore.addSwitch(switchEvent);
putSwitch(switchEvent);
// TODO send out notification
}
// TODO handle invariant violation
}
@Override
public void removeSwitchEvent(SwitchEvent switchEvent) {
if (prepareForRemoveSwitchEvent(switchEvent)) {
datastore.deactivateSwitch(switchEvent);
removeSwitch(switchEvent);
// TODO send out notification
}
// TODO handle invariant violation
}
@Override
public void putPortEvent(PortEvent portEvent) {
// TODO Auto-generated method stub
}
@Override
public void removePortEvent(PortEvent portEvent) {
// TODO Auto-generated method stub
}
@Override
public void putLinkEvent(LinkEvent linkEvent) {
if (prepareForAddLinkEvent(linkEvent)) {
datastore.addLink(linkEvent);
putLink(linkEvent);
// TODO send out notification
}
// TODO handle invariant violation
}
@Override
public void removeLinkEvent(LinkEvent linkEvent) {
if (prepareForRemoveLinkEvent(linkEvent)) {
datastore.removeLink(linkEvent);
removeLink(linkEvent);
// TODO send out notification
}
// TODO handle invariant violation
}
@Override
public void putDeviceEvent(DeviceEvent device) {
// XXX if prepareFor~ method returned false, event should be dropped
// TODO Auto-generated method stub
}
@Override
public void removeDeviceEvent(DeviceEvent deviceEvent) {
// TODO Auto-generated method stub
}
/* *****************
* Internal methods to maintain invariants of the network graph
* *****************/
/**
*
* @param swEvt
* @return true if ready to accept event.
*/
private boolean prepareForAddSwitchEvent(SwitchEvent swEvt) {
// No show stopping precondition?
// Prep: remove(deactivate) Ports on Switch, which is not on event
removePortsNotOnEvent(swEvt);
return true;
}
private boolean prepareForRemoveSwitchEvent(SwitchEvent swEvt) {
// No show stopping precondition?
// Prep: remove(deactivate) Ports on Switch, which is not on event
// XXX may be remove switch should imply wipe all ports
removePortsNotOnEvent(swEvt);
return true;
}
private void removePortsNotOnEvent(SwitchEvent swEvt) {
Switch sw = switches.get( swEvt.getDpid() );
if ( sw != null ) {
Set<Long> port_noOnEvent = new HashSet<>();
for( PortEvent portEvent : swEvt.getPorts()) {
port_noOnEvent.add(portEvent.getNumber());
}
// Existing ports not on event should be removed.
// TODO Should batch eventually for performance?
for( Port p : sw.getPorts() ) {
if ( !port_noOnEvent.contains(p.getNumber()) ) {
PortEvent rmEvent = new PortEvent(p.getSwitch().getDpid(), p.getNumber());
// calling Discovery removePort() API to wipe from DB, etc.
removePortEvent(rmEvent);
}
}
}
}
private boolean prepareForAddPortEvent(PortEvent portEvt) {
// Parent Switch must exist
if ( getSwitch(portEvt.getDpid()) == null) {
return false;
}
// Prep: None
return true;
}
private boolean prepareForRemovePortEvent(PortEvent portEvt) {
// Parent Switch must exist
Switch sw = getSwitch(portEvt.getDpid());
if ( sw == null ) {
return false;
}
Port port = sw.getPort(portEvt.getNumber());
if ( port == null ) {
log.debug("Port already removed? {}", portEvt);
// let it pass
return true;
}
// Prep: Remove Link and Device Attachment
for (Device device : port.getDevices()) {
DeviceEvent devEvt = new DeviceEvent(device.getMacAddress());
devEvt.addAttachmentPoint(new SwitchPort(port.getSwitch().getDpid(), port.getNumber()));
// calling Discovery API to wipe from DB, etc.
removeDeviceEvent(devEvt);
}
Set<Link> links = new HashSet<>();
links.add(port.getOutgoingLink());
links.add(port.getIncomingLink());
for ( Link link : links) {
if (link == null ) {
continue;
}
LinkEvent linkEvent = new LinkEvent(link.getSourceSwitchDpid(), link.getSourcePortNumber(), link.getDestinationSwitchDpid(), link.getDestinationPortNumber());
// calling Discovery API to wipe from DB, etc.
removeLinkEvent(linkEvent);
}
return true;
}
private boolean prepareForAddLinkEvent(LinkEvent linkEvt) {
// Src/Dst Switch must exist
Switch srcSw = getSwitch(linkEvt.getSrc().dpid);
Switch dstSw = getSwitch(linkEvt.getDst().dpid);
if ( srcSw == null || dstSw == null ) {
return false;
}
// Src/Dst Port must exist
Port srcPort = srcSw.getPort(linkEvt.getSrc().number);
Port dstPort = srcSw.getPort(linkEvt.getDst().number);
if ( srcPort == null || dstPort == null ) {
return false;
}
// Prep: remove Device attachment on both Ports
for (Device device : srcPort.getDevices()) {
DeviceEvent devEvt = new DeviceEvent(device.getMacAddress());
devEvt.addAttachmentPoint(new SwitchPort(srcPort.getSwitch().getDpid(), srcPort.getNumber()));
// calling Discovery API to wipe from DB, etc.
removeDeviceEvent(devEvt);
}
for (Device device : dstPort.getDevices()) {
DeviceEvent devEvt = new DeviceEvent(device.getMacAddress());
devEvt.addAttachmentPoint(new SwitchPort(dstPort.getSwitch().getDpid(), dstPort.getNumber()));
// calling Discovery API to wipe from DB, etc.
removeDeviceEvent(devEvt);
}
return true;
}
private boolean prepareForRemoveLinkEvent(LinkEvent linkEvt) {
// Src/Dst Switch must exist
Switch srcSw = getSwitch(linkEvt.getSrc().dpid);
Switch dstSw = getSwitch(linkEvt.getDst().dpid);
if ( srcSw == null || dstSw == null ) {
return false;
}
// Src/Dst Port must exist
Port srcPort = srcSw.getPort(linkEvt.getSrc().number);
Port dstPort = srcSw.getPort(linkEvt.getDst().number);
if ( srcPort == null || dstPort == null ) {
return false;
}
// Prep: None
return true;
}
/**
*
* @param deviceEvt Event will be modified to remove inapplicable attachemntPoints/ipAddress
* @return false if this event should be dropped.
*/
private boolean prepareForAddDeviceEvent(DeviceEvent deviceEvt) {
boolean preconditionBroken = false;
ArrayList<PortEvent.SwitchPort> failedSwitchPort = new ArrayList<>();
for ( PortEvent.SwitchPort swp : deviceEvt.getAttachmentPoints() ) {
// Attached Ports' Parent Switch must exist
Switch sw = getSwitch(swp.dpid);
if ( sw == null ) {
preconditionBroken = true;
failedSwitchPort.add(swp);
continue;
}
// Attached Ports must exist
Port port = sw.getPort(swp.number);
if ( port == null ) {
preconditionBroken = true;
failedSwitchPort.add(swp);
continue;
}
// Attached Ports must not have Link
if ( port.getOutgoingLink() != null || port.getIncomingLink() != null ) {
preconditionBroken = true;
failedSwitchPort.add(swp);
continue;
}
}
// Rewriting event to exclude failed attachmentPoint
// XXX Assumption behind this is that inapplicable device event should
// be dropped, not deferred. If we decide to defer Device event,
// rewriting can become a problem
List<SwitchPort> attachmentPoints = deviceEvt.getAttachmentPoints();
attachmentPoints.removeAll(failedSwitchPort);
deviceEvt.setAttachmentPoints(attachmentPoints);
if ( deviceEvt.getAttachmentPoints().isEmpty() && deviceEvt.getIpAddresses().isEmpty() ) {
// XXX return false to represent: Nothing left to do for this event. Caller should drop event
return false;
}
// Should we return false to tell caller that the event was trimmed?
// if ( preconditionBroken ) {
// return false;
// }
return true;
}
private boolean prepareForRemoveDeviceEvent(DeviceEvent deviceEvt) {
// No show stopping precondition?
// Prep: none
return true;
}
@Override
public void putSwitchReplicationEvent(SwitchEvent switchEvent) {
if (prepareForAddSwitchEvent(switchEvent)) {
putSwitch(switchEvent);
}
// TODO handle invariant violation
}
@Override
public void removeSwitchReplicationEvent(SwitchEvent switchEvent) {
// TODO Auto-generated method stub
}
@Override
public void putPortReplicationEvent(PortEvent portEvent) {
// TODO Auto-generated method stub
}
@Override
public void removePortReplicationEvent(PortEvent portEvent) {
// TODO Auto-generated method stub
}
@Override
public void putLinkReplicationEvent(LinkEvent linkEvent) {
// TODO Auto-generated method stub
}
@Override
public void removeLinkReplicationEvent(LinkEvent linkEvent) {
// TODO Auto-generated method stub
}
@Override
public void putDeviceReplicationEvent(DeviceEvent deviceEvent) {
// TODO Auto-generated method stub
}
@Override
public void removeDeviceReplicationEvent(DeviceEvent deviceEvent) {
// TODO Auto-generated method stub
}
}