class LinkDiscoveryManager implements IOFMessageListener,
IOFSwitchListener, IStorageSourceListener, ILinkDiscoveryService,
IFloodlightModule, IInfoProvider {

	@LogMessageDocs({
		@LogMessageDoc(message="Inter-switch link detected:",
				explanation="Detected a new link between two openflow switches," +
				"use show link to find current status"),
				@LogMessageDoc(message="Inter-switch link updated:",
				explanation="Detected a link change between two openflow switches, " +
						"use show link to find current status")
	})
	protected boolean addOrUpdateLink(Link lt, LinkInfo newInfo) {

		boolean linkChanged = false;

		lock.writeLock().lock();
		try {
			// put the new info. if an old info exists, it will be returned.
			LinkInfo oldInfo = links.put(lt, newInfo);
			if (oldInfo != null
					&& oldInfo.getFirstSeenTime().getTime() < newInfo.getFirstSeenTime().getTime())
				newInfo.setFirstSeenTime(oldInfo.getFirstSeenTime());

			if (log.isTraceEnabled()) {
				log.trace("addOrUpdateLink: {} {}",
						lt,
						(newInfo.getMulticastValidTime() != null) ? "multicast"
								: "unicast");
			}

			UpdateOperation updateOperation = null;
			linkChanged = false;

			if (oldInfo == null) {
				addLink(lt, newInfo);
				updateOperation = UpdateOperation.LINK_UPDATED;
				linkChanged = true;

				// Log direct links only. Multi-hop links may be numerous
				// Add all to event history
				LinkType linkType = getLinkType(lt, newInfo);
				if (linkType == ILinkDiscovery.LinkType.DIRECT_LINK) {
					log.info("Inter-switch link detected: {}", lt);
					eventCategory.newEventNoFlush(new DirectLinkEvent(lt.getSrc(),
							lt.getSrcPort(), lt.getDst(), lt.getDstPort(), "direct-link-added::rcvd LLDP"));
				}
				notifier.postNotification("Link added: " + lt.toString());
			} else {
				linkChanged = updateLink(lt, oldInfo, newInfo);
				if (linkChanged) {
					updateOperation = UpdateOperation.LINK_UPDATED;
					LinkType linkType = getLinkType(lt, newInfo);
					if (linkType == ILinkDiscovery.LinkType.DIRECT_LINK) {
						log.info("Inter-switch link updated: {}", lt);
						eventCategory.newEventNoFlush(new DirectLinkEvent(lt.getSrc(),
								lt.getSrcPort(), lt.getDst(), lt.getDstPort(),
								"link-port-state-updated::rcvd LLDP"));
					}
					notifier.postNotification("Link updated: " + lt.toString());
				}
			}

			// Write changes to storage. This will always write the updated
			// valid time, plus the port states if they've changed (i.e. if
			// they weren't set to null in the previous block of code.
			writeLinkToStorage(lt, newInfo);

			if (linkChanged) {
				// find out if the link was added or removed here.
				updates.add(new LDUpdate(lt.getSrc(), lt.getSrcPort(),
						lt.getDst(), lt.getDstPort(),
						getLinkType(lt, newInfo),
						updateOperation));
			}
		} finally {
			lock.writeLock().unlock();
		}

		return linkChanged;
	}

}