*/
package org.opendaylight.openflowplugin.applications.frm.impl;
-import com.google.common.base.Optional;
import com.google.common.base.Preconditions;
-
+import org.opendaylight.controller.md.sal.binding.api.DataObjectModification;
+import org.opendaylight.controller.md.sal.binding.api.DataTreeModification;
import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent;
import org.opendaylight.openflowplugin.applications.frm.ForwardingRulesCommiter;
import org.opendaylight.openflowplugin.applications.frm.ForwardingRulesManager;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
import org.opendaylight.yangtools.yang.binding.DataObject;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
-import java.util.Collections;
-import java.util.Map;
-import java.util.Set;
+import java.util.Collection;
/**
* AbstractChangeListner implemented basic {@link AsyncDataChangeEvent} processing for
*/
public abstract class AbstractListeningCommiter <T extends DataObject> implements ForwardingRulesCommiter<T> {
+ private static final Logger LOG = LoggerFactory.getLogger(AbstractListeningCommiter.class);
+
protected ForwardingRulesManager provider;
protected final Class<T> clazz;
}
@Override
- public void onDataChanged(final AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> changeEvent) {
- Preconditions.checkNotNull(changeEvent,"Async ChangeEvent can not be null!");
-
- /* All DataObjects for create */
- final Map<InstanceIdentifier<?>, DataObject> createdData = changeEvent.getCreatedData() != null
- ? changeEvent.getCreatedData() : Collections.<InstanceIdentifier<?>, DataObject> emptyMap();
- /* All DataObjects for remove */
- final Set<InstanceIdentifier<?>> removeData = changeEvent.getRemovedPaths() != null
- ? changeEvent.getRemovedPaths() : Collections.<InstanceIdentifier<?>> emptySet();
- /* All DataObjects for updates */
- final Map<InstanceIdentifier<?>, DataObject> updateData = changeEvent.getUpdatedData() != null
- ? changeEvent.getUpdatedData() : Collections.<InstanceIdentifier<?>, DataObject> emptyMap();
- /* All Original DataObjects */
- final Map<InstanceIdentifier<?>, DataObject> originalData = changeEvent.getOriginalData() != null
- ? changeEvent.getOriginalData() : Collections.<InstanceIdentifier<?>, DataObject> emptyMap();
-
- this.createData(createdData);
- this.updateData(updateData, originalData);
- this.removeData(removeData, originalData);
- }
-
- /**
- * Method return wildCardPath for Listener registration
- * and for identify the correct KeyInstanceIdentifier from data;
- */
- protected abstract InstanceIdentifier<T> getWildCardPath();
-
-
-
- @SuppressWarnings("unchecked")
- private void createData(final Map<InstanceIdentifier<?>, DataObject> createdData) {
- final Set<InstanceIdentifier<?>> keys = createdData.keySet() != null
- ? createdData.keySet() : Collections.<InstanceIdentifier<?>> emptySet();
- for (InstanceIdentifier<?> key : keys) {
- if (clazz.equals(key.getTargetType())) {
- final InstanceIdentifier<FlowCapableNode> nodeIdent =
- key.firstIdentifierOf(FlowCapableNode.class);
- if (preConfigurationCheck(nodeIdent)) {
- InstanceIdentifier<T> createKeyIdent = key.firstIdentifierOf(clazz);
- final Optional<DataObject> value = Optional.of(createdData.get(key));
- if (value.isPresent()) {
- this.add(createKeyIdent, (T)value.get(), nodeIdent);
+ public void onDataTreeChanged(Collection<DataTreeModification<T>> changes) {
+ Preconditions.checkNotNull(changes, "Changes may not be null!");
+
+ for (DataTreeModification<T> change : changes) {
+ final InstanceIdentifier<T> key = change.getRootPath().getRootIdentifier();
+ final DataObjectModification<T> mod = change.getRootNode();
+ final InstanceIdentifier<FlowCapableNode> nodeIdent =
+ key.firstIdentifierOf(FlowCapableNode.class);
+
+ if (preConfigurationCheck(nodeIdent)) {
+ switch (mod.getModificationType()) {
+ case DELETE:
+ remove(key, mod.getDataBefore(), nodeIdent);
+ break;
+ case SUBTREE_MODIFIED:
+ update(key, mod.getDataBefore(), mod.getDataAfter(), nodeIdent);
+ break;
+ case WRITE:
+ if (mod.getDataBefore() == null) {
+ add(key, mod.getDataAfter(), nodeIdent);
+ } else {
+ update(key, mod.getDataBefore(), mod.getDataAfter(), nodeIdent);
}
+ break;
+ default:
+ throw new IllegalArgumentException("Unhandled modification type " + mod.getModificationType());
}
}
- }
- }
-
- @SuppressWarnings("unchecked")
- private void updateData(final Map<InstanceIdentifier<?>, DataObject> updateData,
- final Map<InstanceIdentifier<?>, DataObject> originalData) {
-
- final Set<InstanceIdentifier<?>> keys = updateData.keySet() != null
- ? updateData.keySet() : Collections.<InstanceIdentifier<?>> emptySet();
- for (InstanceIdentifier<?> key : keys) {
- if (clazz.equals(key.getTargetType())) {
- final InstanceIdentifier<FlowCapableNode> nodeIdent =
- key.firstIdentifierOf(FlowCapableNode.class);
- if (preConfigurationCheck(nodeIdent)) {
- InstanceIdentifier<T> updateKeyIdent = key.firstIdentifierOf(clazz);
- final Optional<DataObject> value = Optional.of(updateData.get(key));
- final Optional<DataObject> original = Optional.of(originalData.get(key));
- if (value.isPresent() && original.isPresent()) {
- this.update(updateKeyIdent, (T)original.get(), (T)value.get(), nodeIdent);
+ else{
+ if (provider.getConfiguration().isStaleMarkingEnabled()) {
+ LOG.info("Stale-Marking ENABLED and switch {} is NOT connected, storing stale entities",
+ nodeIdent.toString());
+ // Switch is NOT connected
+ switch (mod.getModificationType()) {
+ case DELETE:
+ createStaleMarkEntity(key, mod.getDataBefore(), nodeIdent);
+ break;
+ case SUBTREE_MODIFIED:
+ break;
+ case WRITE:
+ break;
+ default:
+ throw new IllegalArgumentException("Unhandled modification type " + mod.getModificationType());
}
}
}
}
}
- @SuppressWarnings("unchecked")
- private void removeData(final Set<InstanceIdentifier<?>> removeData,
- final Map<InstanceIdentifier<?>, DataObject> originalData) {
-
- for (InstanceIdentifier<?> key : removeData) {
- if (clazz.equals(key.getTargetType())) {
- final InstanceIdentifier<FlowCapableNode> nodeIdent =
- key.firstIdentifierOf(FlowCapableNode.class);
- if (preConfigurationCheck(nodeIdent)) {
- final InstanceIdentifier<T> ident = key.firstIdentifierOf(clazz);
- final DataObject removeValue = originalData.get(key);
- this.remove(ident, (T)removeValue, nodeIdent);
- }
- }
- }
- }
+ /**
+ * Method return wildCardPath for Listener registration
+ * and for identify the correct KeyInstanceIdentifier from data;
+ */
+ protected abstract InstanceIdentifier<T> getWildCardPath();
private boolean preConfigurationCheck(final InstanceIdentifier<FlowCapableNode> nodeIdent) {
Preconditions.checkNotNull(nodeIdent, "FlowCapableNode ident can not be null!");
- return provider.isNodeActive(nodeIdent);
+ // In single node cluster, node should be in local cache before we get any flow/group/meter
+ // data change event from data store. So first check should pass.
+ // In case of 3-node cluster, when shard leader changes, clustering will send blob of data
+ // present in operational data store and config data store. So ideally local node cache
+ // should get populated. But to handle a scenario where flow request comes before the blob
+ // of config/operational data gets processes, it won't find node in local cache and it will
+ // skip the flow/group/meter operational. This requires an addition check, where it reads
+ // node from operational data store and if it's present it calls flowNodeConnected to explictly
+ // trigger the event of new node connected.
+
+ if (!provider.isNodeActive(nodeIdent)) {
+ if (provider.checkNodeInOperationalDataStore(nodeIdent)) {
+ provider.getFlowNodeReconciliation().flowNodeConnected(nodeIdent);
+ return true;
+ } else {
+ return false;
+ }
+ }
+ return true;
}
}