/**
  * Creates new overlay item or adds new underlay item into existing overlay item if the condition
  * for correlation is satisfied
  *
  * @param newItem - new underlay item on which the correlation is created
  */
 private void checkForPossibleAggregation(UnderlayItem newItem, String topologyId) {
   for (TopologyStore ts : topoStoreProvider.getTopologyStores()) {
     if ((!ts.getId().equals(topologyId)) || ts.isAggregateInside()) {
       for (Entry<YangInstanceIdentifier, UnderlayItem> topoStoreEntry :
           ts.getUnderlayItems().entrySet()) {
         UnderlayItem topoStoreItem = topoStoreEntry.getValue();
         if (newItem.getCorrelationItem() == CorrelationItemEnum.Link) {
           checkForPossibleAggregationOfLinks(newItem, topoStoreItem);
         } else {
           if (scriptEngine != null) {
             if (aggregableWithScript(newItem, topoStoreItem)) {
               aggregateItems(newItem, topoStoreItem);
               return;
             }
           } else if (!newItem.equals(topoStoreItem)
               && matchTargetFields(newItem, topoStoreItem)) {
             // no previous aggregation on this node
             aggregateItems(newItem, topoStoreItem);
             return;
           }
         }
       }
     }
   }
   if (wrapSingleItem()) {
     List<UnderlayItem> itemsToAggregate = new ArrayList<>();
     itemsToAggregate.add(newItem);
     OverlayItem overlayItem = new OverlayItem(itemsToAggregate, newItem.getCorrelationItem());
     newItem.setOverlayItem(overlayItem);
     topologyManager.addOverlayItem(overlayItem);
   }
 }
 @Override
 public void processRemovedChanges(YangInstanceIdentifier identifier, String topologyId) {
   if (identifier != null) {
     LOGGER.trace("Processing removeChanges");
     Map<YangInstanceIdentifier, UnderlayItem> items =
         topoStoreProvider.getTopologyStore(topologyId).getUnderlayItems();
     UnderlayItem underlayItem = items.remove(identifier);
     if (null != underlayItem) {
       manager.removeOverlayItem(underlayItem.getOverlayItem());
     }
   }
 }
 private boolean matchTargetFields(UnderlayItem item1, UnderlayItem item2) {
   boolean targetFieldsMatch = false;
   if (item1.getLeafNodes().size() == item2.getLeafNodes().size()) {
     targetFieldsMatch = true;
     for (Entry<Integer, NormalizedNode<?, ?>> targetFieldEntryOfItem1 :
         item1.getLeafNodes().entrySet()) {
       NormalizedNode<?, ?> targetFieldOfItem2 =
           item2.getLeafNodes().get(targetFieldEntryOfItem1.getKey());
       if (!targetFieldEntryOfItem1.getValue().equals(targetFieldOfItem2)) {
         return false;
       }
     }
   }
   return targetFieldsMatch;
 }
 @Override
 public void processUpdatedChanges(
     YangInstanceIdentifier identifier, UnderlayItem updatedEntry, String topologyId) {
   if (updatedEntry != null) {
     LOGGER.trace("Processing updateChanges");
     Map<YangInstanceIdentifier, UnderlayItem> items =
         topoStoreProvider.getTopologyStore(topologyId).getUnderlayItems();
     UnderlayItem oldItem = items.get(identifier);
     OverlayItem item = oldItem.getOverlayItem();
     Queue<UnderlayItem> underlayItems = new ConcurrentLinkedQueue<>();
     underlayItems.add(updatedEntry);
     item.setUnderlayItems(underlayItems);
     updatedEntry.setOverlayItem(item);
     items.put(identifier, updatedEntry);
     manager.updateOverlayItem(item);
   }
 }
 private void removeUnderlayItemFromOverlayItem(UnderlayItem itemToRemove) {
   OverlayItem overlayItemIdentifier = itemToRemove.getOverlayItem();
   if (null != overlayItemIdentifier) {
     Queue<UnderlayItem> underlayItems = overlayItemIdentifier.getUnderlayItems();
     underlayItems.remove(itemToRemove);
     itemToRemove.setOverlayItem(null);
     if (underlayItems.size() < getMinUnderlayItems()) {
       LOG.debug("Removing overlay item");
       for (UnderlayItem remainingNode : underlayItems) {
         remainingNode.setOverlayItem(null);
       }
       topologyManager.removeOverlayItem(overlayItemIdentifier);
     } else {
       LOG.debug("Removing underlay item from overlay item");
       topologyManager.updateOverlayItem(overlayItemIdentifier);
     }
   }
 }
 @Override
 public void processCreatedChanges(
     YangInstanceIdentifier identifier, UnderlayItem createdEntry, String topologyId) {
   if (createdEntry != null) {
     LOGGER.trace("Processing createdChnages");
     Map<YangInstanceIdentifier, UnderlayItem> items =
         topoStoreProvider.getTopologyStore(topologyId).getUnderlayItems();
     items.put(identifier, createdEntry);
     OverlayItem item = wrapUnderlayItem(createdEntry);
     createdEntry.setOverlayItem(item);
     manager.addOverlayItem(item);
   }
 }
 @Override
 public void processCreatedChanges(
     YangInstanceIdentifier identifier, UnderlayItem createdItem, final String topologyId) {
   LOG.trace("Processing createdChanges");
   for (TopologyStore ts : topoStoreProvider.getTopologyStores()) {
     // Link aggregation has always only one topology store
     if (ts.getId().equals(topologyId)
         || createdItem.getCorrelationItem() == CorrelationItemEnum.Link) {
       ts.getUnderlayItems().put(identifier, createdItem);
     }
   }
   checkForPossibleAggregation(createdItem, topologyId);
 }
 private void checkForPossibleAggregationOfLinks(
     UnderlayItem newItem, UnderlayItem topoStoreItem) {
   if (newItem instanceof ComputedLink && topoStoreItem instanceof ComputedLink) {
     ComputedLink newLink = (ComputedLink) newItem;
     ComputedLink topoStoreLink = (ComputedLink) topoStoreItem;
     if (scriptEngine != null) {
       if (aggregableWithScript(newItem, topoStoreItem)
           && newLink.getSrcNode().equals(topoStoreLink.getSrcNode())
           && newLink.getDstNode().equals(topoStoreLink.getDstNode())) {
         aggregateItems(newItem, topoStoreItem);
         return;
       }
     } else if (!newItem.equals(topoStoreItem)
         && matchTargetFields(newItem, topoStoreItem)
         && newLink.getSrcNode().equals(topoStoreLink.getSrcNode())
         && newLink.getDstNode().equals(topoStoreLink.getDstNode())) {
       // no previous aggregation on this link
       aggregateItems(newItem, topoStoreItem);
       return;
     }
   }
 }
 /**
  * @param newItem item received from notification
  * @param topoStoreItem item already stored in topostore
  */
 private void aggregateItems(UnderlayItem newItem, UnderlayItem topoStoreItem) {
   if (topoStoreItem.getOverlayItem() == null) {
     LOG.debug("Creating new Logical Node");
     // create new logical node
     List<UnderlayItem> nodesToAggregate = new ArrayList<>();
     nodesToAggregate.add(newItem);
     nodesToAggregate.add(topoStoreItem);
     OverlayItem overlayItem =
         new OverlayItem(nodesToAggregate, topoStoreItem.getCorrelationItem());
     topoStoreItem.setOverlayItem(overlayItem);
     newItem.setOverlayItem(overlayItem);
     topologyManager.addOverlayItem(overlayItem);
     return;
   }
   LOG.debug("Adding physical node to existing Logical Node");
   // add new physical node into existing logical node
   OverlayItem overlayItem = topoStoreItem.getOverlayItem();
   newItem.setOverlayItem(overlayItem);
   overlayItem.addUnderlayItem(newItem);
   topologyManager.updateOverlayItem(overlayItem);
 }
 private OverlayItem wrapUnderlayItem(UnderlayItem underlayItem) {
   List<UnderlayItem> underlayItems = Collections.singletonList(underlayItem);
   OverlayItem overlayItem = new OverlayItem(underlayItems, underlayItem.getCorrelationItem());
   return overlayItem;
 }
 @Override
 public void processUpdatedChanges(
     YangInstanceIdentifier identifier, UnderlayItem updatedItem, String topologyId) {
   LOG.trace("Processing updatedChanges");
   for (TopologyStore ts : topoStoreProvider.getTopologyStores()) {
     if (ts.getId().equals(topologyId)) {
       LOG.debug("Updating overlay item");
       UnderlayItem underlayItem = ts.getUnderlayItems().get(identifier);
       Preconditions.checkNotNull(
           underlayItem, "Updated underlay item not found in the Topology store");
       underlayItem.setItem(updatedItem.getItem());
       if (underlayItem.getCorrelationItem() == CorrelationItemEnum.Link) {
         if (underlayItem instanceof ComputedLink && updatedItem instanceof ComputedLink) {
           ComputedLink underlayLink = (ComputedLink) underlayItem;
           ComputedLink updatedLink = (ComputedLink) updatedItem;
           if (!matchTargetFields(underlayItem, updatedItem)
               || !underlayLink.getSrcNode().equals(updatedLink.getSrcNode())
               || !underlayLink.getDstNode().equals(updatedLink.getDstNode())) {
             underlayLink.setLeafNodes(updatedLink.getLeafNodes());
             underlayLink.setSrcNode(updatedLink.getSrcNode());
             underlayLink.setDstNode(updatedLink.getDstNode());
             if (underlayItem.getOverlayItem() != null) {
               removeUnderlayItemFromOverlayItem(underlayItem);
             }
             checkForPossibleAggregationOfLinks(updatedLink, underlayLink);
           } else if (underlayItem.getOverlayItem() != null) {
             // in case that only Link value was changed
             topologyManager.updateOverlayItem(underlayItem.getOverlayItem());
           }
           break;
         }
       } else {
         // if Leaf Node was changed
         if (!matchTargetFields(underlayItem, updatedItem)) {
           underlayItem.setLeafNodes(updatedItem.getLeafNodes());
           if (underlayItem.getOverlayItem() != null) {
             removeUnderlayItemFromOverlayItem(underlayItem);
           }
           checkForPossibleAggregation(underlayItem, topologyId);
         } else if (underlayItem.getOverlayItem() != null) {
           // in case that only Node value was changed
           topologyManager.updateOverlayItem(underlayItem.getOverlayItem());
         }
         break;
       }
     }
   }
 }