
org.opendaylight.controller.messagebus.app.impl.EventSourceTopic Maven / Gradle / Ivy
/*
* Copyright (c) 2015 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.messagebus.app.impl;
import static java.util.Objects.requireNonNull;
import com.google.common.util.concurrent.FluentFuture;
import com.google.common.util.concurrent.FutureCallback;
import com.google.common.util.concurrent.MoreExecutors;
import java.util.Collection;
import java.util.Optional;
import java.util.UUID;
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.concurrent.ExecutionException;
import java.util.regex.Pattern;
import org.opendaylight.mdsal.binding.api.DataObjectModification;
import org.opendaylight.mdsal.binding.api.DataTreeChangeListener;
import org.opendaylight.mdsal.binding.api.DataTreeIdentifier;
import org.opendaylight.mdsal.binding.api.DataTreeModification;
import org.opendaylight.mdsal.binding.api.ReadTransaction;
import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.messagebus.eventaggregator.rev141202.NotificationPattern;
import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.messagebus.eventaggregator.rev141202.TopicId;
import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.messagebus.eventsource.rev141202.DisJoinTopicInput;
import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.messagebus.eventsource.rev141202.DisJoinTopicInputBuilder;
import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.messagebus.eventsource.rev141202.DisJoinTopicOutput;
import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.messagebus.eventsource.rev141202.EventSourceService;
import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.messagebus.eventsource.rev141202.JoinTopicInput;
import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.messagebus.eventsource.rev141202.JoinTopicInputBuilder;
import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.messagebus.eventsource.rev141202.JoinTopicOutput;
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef;
import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology;
import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
import org.opendaylight.yangtools.concepts.ListenerRegistration;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
import org.opendaylight.yangtools.yang.common.RpcError;
import org.opendaylight.yangtools.yang.common.RpcResult;
import org.slf4j.LoggerFactory;
public final class EventSourceTopic implements DataTreeChangeListener, AutoCloseable {
private static final org.slf4j.Logger LOG = LoggerFactory.getLogger(EventSourceTopic.class);
private final NotificationPattern notificationPattern;
private final EventSourceService sourceService;
private final Pattern nodeIdPattern;
private final TopicId topicId;
private ListenerRegistration> listenerRegistration;
private final CopyOnWriteArraySet> joinedEventSources = new CopyOnWriteArraySet<>();
public static EventSourceTopic create(final NotificationPattern notificationPattern,
final String nodeIdRegexPattern, final EventSourceTopology eventSourceTopology) {
final EventSourceTopic est = new EventSourceTopic(notificationPattern, nodeIdRegexPattern,
eventSourceTopology.getEventSourceService());
est.registerListner(eventSourceTopology);
est.notifyExistingNodes(eventSourceTopology);
return est;
}
private EventSourceTopic(final NotificationPattern notificationPattern, final String nodeIdRegexPattern,
final EventSourceService sourceService) {
this.notificationPattern = requireNonNull(notificationPattern);
this.sourceService = requireNonNull(sourceService);
this.nodeIdPattern = Pattern.compile(nodeIdRegexPattern);
this.topicId = new TopicId(getUUIDIdent());
this.listenerRegistration = null;
LOG.info("EventSourceTopic created - topicId {}", topicId.getValue());
}
public TopicId getTopicId() {
return topicId;
}
@Override
public void onDataTreeChanged(final Collection> changes) {
for (DataTreeModification change: changes) {
final DataObjectModification rootNode = change.getRootNode();
switch (rootNode.getModificationType()) {
case WRITE:
case SUBTREE_MODIFIED:
final Node node = rootNode.getDataAfter();
if (getNodeIdRegexPattern().matcher(node.getNodeId().getValue()).matches()) {
notifyNode(change.getRootPath().getRootIdentifier());
}
break;
default:
break;
}
}
}
public void notifyNode(final InstanceIdentifier> nodeId) {
LOG.debug("Notify node: {}", nodeId);
try {
final RpcResult rpcResultJoinTopic =
sourceService.joinTopic(getJoinTopicInputArgument(nodeId)).get();
if (!rpcResultJoinTopic.isSuccessful()) {
for (final RpcError err : rpcResultJoinTopic.getErrors()) {
LOG.error("Can not join topic: [{}] on node: [{}]. Error: {}", getTopicId().getValue(),
nodeId.toString(), err.toString());
}
} else {
joinedEventSources.add(nodeId);
}
} catch (InterruptedException | ExecutionException e) {
LOG.error("Could not invoke join topic for node {}", nodeId);
}
}
private void notifyExistingNodes(final EventSourceTopology eventSourceTopology) {
LOG.debug("Notify existing nodes");
final Pattern nodeRegex = this.nodeIdPattern;
final FluentFuture> future;
try (ReadTransaction tx = eventSourceTopology.getDataBroker().newReadOnlyTransaction()) {
future = tx.read(LogicalDatastoreType.OPERATIONAL, EventSourceTopology.EVENT_SOURCE_TOPOLOGY_PATH);
}
future.addCallback(new FutureCallback>() {
@Override
public void onSuccess(final Optional data) {
if (data.isPresent()) {
for (final Node node : data.get().nonnullNode().values()) {
if (nodeRegex.matcher(node.getNodeId().getValue()).matches()) {
notifyNode(EventSourceTopology.EVENT_SOURCE_TOPOLOGY_PATH.child(Node.class, node.key()));
}
}
}
}
@Override
public void onFailure(final Throwable ex) {
LOG.error("Can not notify existing nodes", ex);
}
}, MoreExecutors.directExecutor());
}
private JoinTopicInput getJoinTopicInputArgument(final InstanceIdentifier> path) {
final NodeRef nodeRef = new NodeRef(path);
final JoinTopicInput jti =
new JoinTopicInputBuilder()
.setNode(nodeRef.getValue())
.setTopicId(topicId)
.setNotificationPattern(notificationPattern)
.build();
return jti;
}
public Pattern getNodeIdRegexPattern() {
return nodeIdPattern;
}
private DisJoinTopicInput getDisJoinTopicInputArgument(final InstanceIdentifier> eventSourceNodeId) {
final NodeRef nodeRef = new NodeRef(eventSourceNodeId);
final DisJoinTopicInput dji = new DisJoinTopicInputBuilder()
.setNode(nodeRef.getValue())
.setTopicId(topicId)
.build();
return dji;
}
private void registerListner(final EventSourceTopology eventSourceTopology) {
this.listenerRegistration = eventSourceTopology.getDataBroker().registerDataTreeChangeListener(
DataTreeIdentifier.create(LogicalDatastoreType.OPERATIONAL,
EventSourceTopology.EVENT_SOURCE_TOPOLOGY_PATH.child(Node.class)), this);
}
@Override
public void close() {
if (this.listenerRegistration != null) {
this.listenerRegistration.close();
}
for (final InstanceIdentifier> eventSourceNodeId : joinedEventSources) {
try {
final RpcResult result = sourceService
.disJoinTopic(getDisJoinTopicInputArgument(eventSourceNodeId)).get();
if (result.isSuccessful() == false) {
for (final RpcError err : result.getErrors()) {
LOG.error("Can not destroy topic: [{}] on node: [{}]. Error: {}", getTopicId().getValue(),
eventSourceNodeId, err.toString());
}
}
} catch (InterruptedException | ExecutionException ex) {
LOG.error("Can not close event source topic / destroy topic {} on node {}.", this.topicId.getValue(),
eventSourceNodeId, ex);
}
}
joinedEventSources.clear();
}
private static String getUUIDIdent() {
final UUID uuid = UUID.randomUUID();
return uuid.toString();
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy