/**
* Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v1.0 which accompanies this distribution,
* and is available at http://www.eclipse.org/legal/epl-v10.html
*/
package org.opendaylight.controller.frm.impl;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import org.opendaylight.controller.frm.FlowNodeReconciliation;
import org.opendaylight.controller.frm.ForwardingRulesManager;
import org.opendaylight.controller.md.sal.binding.api.DataBroker;
import org.opendaylight.controller.md.sal.binding.api.DataChangeListener;
import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope;
import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent;
import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.meters.Meter;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.meters.MeterKey;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.Table;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.TableKey;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowKey;
import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.Group;
import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.GroupKey;
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
import org.opendaylight.yangtools.concepts.ListenerRegistration;
import org.opendaylight.yangtools.yang.binding.DataObject;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
import org.opendaylight.yangtools.yang.binding.KeyedInstanceIdentifier;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.common.base.Optional;
import com.google.common.base.Preconditions;
/**
* forwardingrules-manager
* org.opendaylight.controller.frm
*
* FlowNode Reconciliation Listener
* Reconciliation for a new FlowNode
*
* @author Vaclav Demcak
*
* Created: Jun 13, 2014
*/
public class FlowNodeReconciliationImpl implements FlowNodeReconciliation {
private static final Logger LOG = LoggerFactory.getLogger(FlowNodeReconciliationImpl.class);
private final ForwardingRulesManager provider;
private ListenerRegistration listenerRegistration;
public FlowNodeReconciliationImpl (final ForwardingRulesManager manager, final DataBroker db) {
this.provider = Preconditions.checkNotNull(manager, "ForwardingRulesManager can not be null!");
Preconditions.checkNotNull(db, "DataBroker can not be null!");
/* Build Path */
InstanceIdentifier flowNodeWildCardIdentifier = InstanceIdentifier.create(Nodes.class)
.child(Node.class).augmentation(FlowCapableNode.class);
this.listenerRegistration = db.registerDataChangeListener(LogicalDatastoreType.OPERATIONAL,
flowNodeWildCardIdentifier, FlowNodeReconciliationImpl.this, DataChangeScope.BASE);
}
@Override
public void close() {
if (listenerRegistration != null) {
try {
listenerRegistration.close();
} catch (Exception e) {
LOG.error("Error by stop FRM FlowNodeReconilListener.", e);
}
listenerRegistration = null;
}
}
@Override
public void onDataChanged(final AsyncDataChangeEvent, DataObject> changeEvent) {
Preconditions.checkNotNull(changeEvent,"Async ChangeEvent can not be null!");
/* All DataObjects for create */
final Set> createdData = changeEvent.getCreatedData() != null
? changeEvent.getCreatedData().keySet() : Collections.> emptySet();
/* All DataObjects for remove */
final Set> removeData = changeEvent.getRemovedPaths() != null
? changeEvent.getRemovedPaths() : Collections.> emptySet();
for (InstanceIdentifier> entryKey : removeData) {
final InstanceIdentifier nodeIdent = entryKey
.firstIdentifierOf(FlowCapableNode.class);
if ( ! nodeIdent.isWildcarded()) {
flowNodeDisconnected(nodeIdent);
}
}
for (InstanceIdentifier> entryKey : createdData) {
final InstanceIdentifier nodeIdent = entryKey
.firstIdentifierOf(FlowCapableNode.class);
if ( ! nodeIdent.isWildcarded()) {
flowNodeConnected(nodeIdent);
}
}
}
@Override
public void flowNodeDisconnected(InstanceIdentifier disconnectedNode) {
provider.unregistrateNode(disconnectedNode);
}
@Override
public void flowNodeConnected(InstanceIdentifier connectedNode) {
if ( ! provider.isNodeActive(connectedNode)) {
provider.registrateNewNode(connectedNode);
reconciliation(connectedNode);
}
}
private void reconciliation(final InstanceIdentifier nodeIdent) {
ReadOnlyTransaction trans = provider.getReadTranaction();
Optional flowNode = Optional.absent();
try {
flowNode = trans.read(LogicalDatastoreType.CONFIGURATION, nodeIdent).get();
}
catch (Exception e) {
LOG.error("Fail with read Config/DS for Node {} !", nodeIdent, e);
}
if (flowNode.isPresent()) {
/* Groups - have to be first */
List groups = flowNode.get().getGroup() != null
? flowNode.get().getGroup() : Collections. emptyList();
for (Group group : groups) {
final KeyedInstanceIdentifier groupIdent =
nodeIdent.child(Group.class, group.getKey());
this.provider.getGroupCommiter().add(groupIdent, group, nodeIdent);
}
/* Meters */
List meters = flowNode.get().getMeter() != null
? flowNode.get().getMeter() : Collections. emptyList();
for (Meter meter : meters) {
final KeyedInstanceIdentifier meterIdent =
nodeIdent.child(Meter.class, meter.getKey());
this.provider.getMeterCommiter().add(meterIdent, meter, nodeIdent);
}
/* Flows */
List tables = flowNode.get().getTable() != null
? flowNode.get().getTable() : Collections. emptyList();
for (Table table : tables) {
final KeyedInstanceIdentifier tableIdent =
nodeIdent.child(Table.class, table.getKey());
List flows = table.getFlow() != null ? table.getFlow() : Collections. emptyList();
for (Flow flow : flows) {
final KeyedInstanceIdentifier flowIdent =
tableIdent.child(Flow.class, flow.getKey());
this.provider.getFlowCommiter().add(flowIdent, flow, nodeIdent);
}
}
}
/* clean transaction */
trans.close();
}
}