/** * 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.md.statistics.manager.impl; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Set; 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.ReadWriteTransaction; 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.controller.md.statistics.manager.StatNodeRegistration; import org.opendaylight.controller.md.statistics.manager.StatPermCollector.StatCapabTypes; import org.opendaylight.controller.md.statistics.manager.StatisticsManager; import org.opendaylight.controller.md.statistics.manager.StatisticsManager.StatDataStoreOperation; import org.opendaylight.controller.sal.binding.api.NotificationProviderService; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FeatureCapability; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeUpdated; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowFeatureCapabilityFlowStats; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowFeatureCapabilityGroupStats; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowFeatureCapabilityPortStats; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowFeatureCapabilityQueueStats; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowFeatureCapabilityTableStats; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.flow.node.SwitchFeatures; import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorRemoved; import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorUpdated; import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef; import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRemoved; import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeUpdated; 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.slf4j.Logger; import org.slf4j.LoggerFactory; import com.google.common.base.Optional; import com.google.common.base.Preconditions; /** * statistics-manager * org.opendaylight.controller.md.statistics.manager.impl * * StatNodeRegistrationImpl * {@link FlowCapableNode} Registration Implementation contains two method for registration/unregistration * {@link FeatureCapability} for every connect/disconnect {@link FlowCapableNode}. Process of connection/disconnection * is substituted by listening Operation/DS for add/delete {@link FeatureCapability}. * All statistic capabilities are reading from new Node directly without contacting device or DS. * * @author Vaclav Demcak * * Created: Aug 28, 2014 */ public class StatNodeRegistrationImpl implements StatNodeRegistration, DataChangeListener { private static final Logger LOG = LoggerFactory.getLogger(StatNodeRegistrationImpl.class); private final StatisticsManager manager; private ListenerRegistration listenerRegistration; private ListenerRegistration notifListenerRegistration; public StatNodeRegistrationImpl(final StatisticsManager manager, final DataBroker db, final NotificationProviderService notificationService) { this.manager = Preconditions.checkNotNull(manager, "StatisticManager can not be null!"); Preconditions.checkArgument(db != null, "DataBroker can not be null!"); Preconditions.checkArgument(notificationService != null, "NotificationProviderService can not be null!"); notifListenerRegistration = notificationService.registerNotificationListener(this); /* Build Path */ final InstanceIdentifier flowNodeWildCardIdentifier = InstanceIdentifier.create(Nodes.class) .child(Node.class).augmentation(FlowCapableNode.class); listenerRegistration = db.registerDataChangeListener(LogicalDatastoreType.OPERATIONAL, flowNodeWildCardIdentifier, StatNodeRegistrationImpl.this, DataChangeScope.BASE); } @Override public void close() throws Exception { if (notifListenerRegistration != null) { try { notifListenerRegistration.close(); } catch (final Exception e) { LOG.warn("Error by stop FlowCapableNode Notification StatNodeRegistration."); } notifListenerRegistration = null; } if (listenerRegistration != null) { try { listenerRegistration.close(); } catch (final Exception e) { LOG.warn("Error by stop FlowCapableNode DataChange StatListeningCommiter.", e); } listenerRegistration = null; } } @Override public void connectFlowCapableNode(final InstanceIdentifier keyIdent, final SwitchFeatures data, final InstanceIdentifier nodeIdent) { Preconditions.checkNotNull(keyIdent, "InstanceIdentifier can not be null!"); Preconditions.checkNotNull(data, "SwitchFeatures data for {} can not be null!", keyIdent); Preconditions.checkArgument(( ! keyIdent.isWildcarded()), "InstanceIdentifier is WildCarded!"); manager.enqueue(new StatDataStoreOperation() { @Override public void applyOperation(final ReadWriteTransaction tx) { final List statCapabTypes = new ArrayList<>(); Short maxCapTables = Short.valueOf("1"); final List> capabilities = data.getCapabilities() != null ? data.getCapabilities() : Collections.> emptyList(); for (final Class capability : capabilities) { if (capability == FlowFeatureCapabilityTableStats.class) { statCapabTypes.add(StatCapabTypes.TABLE_STATS); } else if (capability == FlowFeatureCapabilityFlowStats.class) { statCapabTypes.add(StatCapabTypes.FLOW_STATS); } else if (capability == FlowFeatureCapabilityGroupStats.class) { statCapabTypes.add(StatCapabTypes.GROUP_STATS); } else if (capability == FlowFeatureCapabilityPortStats.class) { statCapabTypes.add(StatCapabTypes.PORT_STATS); } else if (capability == FlowFeatureCapabilityQueueStats.class) { statCapabTypes.add(StatCapabTypes.QUEUE_STATS); } } maxCapTables = data.getMaxTables(); final Optional maxTables = Optional. of(maxCapTables); manager.connectedNodeRegistration(nodeIdent, Collections.unmodifiableList(statCapabTypes), maxTables.get()); } }); } @Override public void disconnectFlowCapableNode(final InstanceIdentifier nodeIdent) { Preconditions.checkArgument(nodeIdent != null, "InstanceIdentifier can not be NULL!"); Preconditions.checkArgument(( ! nodeIdent.isWildcarded()), "InstanceIdentifier {} is WildCarded!", nodeIdent); manager.enqueue(new StatDataStoreOperation() { @Override public void applyOperation(final ReadWriteTransaction tx) { manager.disconnectedNodeUnregistration(nodeIdent); } }); } @Override public void onNodeConnectorRemoved(final NodeConnectorRemoved notification) { // NOOP } @Override public void onNodeConnectorUpdated(final NodeConnectorUpdated notification) { // NOOP } @Override public void onNodeRemoved(final NodeRemoved notification) { Preconditions.checkNotNull(notification); final NodeRef nodeRef = notification.getNodeRef(); final InstanceIdentifier nodeRefIdent = nodeRef.getValue(); final InstanceIdentifier nodeIdent = nodeRefIdent.firstIdentifierOf(Node.class); if (nodeIdent != null) { disconnectFlowCapableNode(nodeIdent); } } @Override public void onNodeUpdated(final NodeUpdated notification) { Preconditions.checkNotNull(notification); final FlowCapableNodeUpdated newFlowNode = notification.getAugmentation(FlowCapableNodeUpdated.class); if (newFlowNode != null && newFlowNode.getSwitchFeatures() != null) { final NodeRef nodeRef = notification.getNodeRef(); final InstanceIdentifier nodeRefIdent = nodeRef.getValue(); final InstanceIdentifier nodeIdent = nodeRefIdent.firstIdentifierOf(Node.class); final InstanceIdentifier swichFeaturesIdent = nodeIdent.augmentation(FlowCapableNode.class).child(SwitchFeatures.class); final SwitchFeatures switchFeatures = newFlowNode.getSwitchFeatures(); connectFlowCapableNode(swichFeaturesIdent, switchFeatures, nodeIdent); } } @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(); for (final InstanceIdentifier entryKey : createdData) { final InstanceIdentifier nodeIdent = entryKey .firstIdentifierOf(Node.class); if ( ! nodeIdent.isWildcarded()) { final NodeRef nodeRef = new NodeRef(nodeIdent); // FIXME: these calls is a job for handshake or for inventory manager /* check Group and Meter future */ manager.getRpcMsgManager().getGroupFeaturesStat(nodeRef); manager.getRpcMsgManager().getMeterFeaturesStat(nodeRef); } } } }