RESTCONF notification changes
* Added a callback function mechanism to the RESTCONF notification
listener. Applications can register their callbacks to a listener.
This is to allow multiple SB providers share one generic listener.
while still being able to process app-specific events.
* Created a default RESTCONF notification listener implementation.
* Refactored TE provider code to allow TE-topology and TE-tunnel share one
RESTCONF event listener
Change-Id: I26dc4972683fcda3eefacde131353312809aa95e
diff --git a/providers/ietfte/pom.xml b/providers/ietfte/pom.xml
index 1931d2f..8661bdf 100644
--- a/providers/ietfte/pom.xml
+++ b/providers/ietfte/pom.xml
@@ -28,18 +28,6 @@
<artifactId>onos-ietfte-providers</artifactId>
<packaging>pom</packaging>
- <build>
- <plugins>
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-compiler-plugin</artifactId>
- <configuration>
- <source>1.6</source>
- <target>1.6</target>
- </configuration>
- </plugin>
- </plugins>
- </build>
<modules>
<module>topology</module>
<module>tunnel</module>
diff --git a/providers/ietfte/topology/src/main/java/org/onosproject/provider/te/topology/TeTopologyRestconfProvider.java b/providers/ietfte/topology/src/main/java/org/onosproject/provider/te/topology/TeTopologyRestconfProvider.java
index c75f01d..a377e51 100644
--- a/providers/ietfte/topology/src/main/java/org/onosproject/provider/te/topology/TeTopologyRestconfProvider.java
+++ b/providers/ietfte/topology/src/main/java/org/onosproject/provider/te/topology/TeTopologyRestconfProvider.java
@@ -34,9 +34,10 @@
import org.onosproject.net.provider.AbstractProvider;
import org.onosproject.net.provider.ProviderId;
import org.onosproject.protocol.rest.RestSBDevice;
-import org.onosproject.protocol.restconf.RestConfNotificationEventListener;
import org.onosproject.protocol.restconf.RestConfSBController;
import org.onosproject.provider.te.utils.DefaultJsonCodec;
+import org.onosproject.provider.te.utils.RestconfNotificationEventProcessor;
+import org.onosproject.provider.te.utils.TeTopologyRestconfEventListener;
import org.onosproject.provider.te.utils.YangCompositeEncodingImpl;
import org.onosproject.tetopology.management.api.TeTopologyProvider;
import org.onosproject.tetopology.management.api.TeTopologyProviderRegistry;
@@ -78,6 +79,8 @@
import static org.onosproject.net.config.NetworkConfigEvent.Type.CONFIG_ADDED;
import static org.onosproject.net.config.NetworkConfigEvent.Type.CONFIG_UPDATED;
import static org.onosproject.net.config.basics.SubjectFactories.APP_SUBJECT_FACTORY;
+import static org.onosproject.provider.te.utils.TeTopologyRestconfEventType.TE_TOPOLOGY_LINK_NOTIFICATION;
+import static org.onosproject.provider.te.utils.TeTopologyRestconfEventType.TE_TOPOLOGY_NODE_NOTIFICATION;
import static org.slf4j.LoggerFactory.getLogger;
/**
@@ -93,8 +96,6 @@
private static final String IETF_NETWORK_URI = "ietf-network:networks";
private static final String IETF_NETWORKS_PREFIX =
"{\"ietf-network:networks\":";
- private static final String TE_NOTIFICATION_PREFIX =
- "{\"ietf-te-topology:ietf-te-topology\":";
private static final String TE_LINK_EVENT_PREFIX =
"{\"ietf-te-topology:te-link-event\":";
private static final String TE_NODE_EVENT_PREFIX =
@@ -290,11 +291,27 @@
// topologyProviderService.networkUpdated(network);
// }
- RestConfNotificationEventListener<String> callBackListener =
- new InternalRestconfNotificationEventListener();
- restconfClient.enableNotifications(deviceId, IETF_NOTIFICATION_URI,
- "application/json",
- callBackListener);
+ subscribeRestconfNotification(deviceId);
+ }
+
+ private void subscribeRestconfNotification(DeviceId deviceId) {
+
+ TeTopologyRestconfEventListener listener =
+ new TeTopologyRestconfEventListener();
+
+ listener.addCallbackFunction(TE_TOPOLOGY_LINK_NOTIFICATION,
+ new InternalLinkEventProcessor());
+ listener.addCallbackFunction(TE_TOPOLOGY_NODE_NOTIFICATION,
+ new InternalNodeEventProcessor());
+
+ if (!restconfClient.isNotificationEnabled(deviceId)) {
+ restconfClient.enableNotifications(deviceId,
+ IETF_NOTIFICATION_URI,
+ "application/json",
+ listener);
+ } else {
+ restconfClient.addNotificationListener(deviceId, listener);
+ }
}
private String removePrefixTagFromJson(String jsonString, String prefixTag) {
@@ -304,42 +321,15 @@
return jsonString;
}
- private class InternalNetworkConfigListener implements NetworkConfigListener {
+ private class InternalLinkEventProcessor implements
+ RestconfNotificationEventProcessor<String> {
@Override
- public void event(NetworkConfigEvent event) {
- executor.execute(TeTopologyRestconfProvider.this::connectDevices);
- }
-
- @Override
- public boolean isRelevant(NetworkConfigEvent event) {
- return event.configClass().equals(RestconfServerConfig.class) &&
- (event.type() == CONFIG_ADDED ||
- event.type() == CONFIG_UPDATED);
- }
- }
-
- private class InternalRestconfNotificationEventListener implements
- RestConfNotificationEventListener<String> {
- @Override
- public void handleNotificationEvent(DeviceId deviceId,
- String eventJsonString) {
- log.debug("New notification: {} for device: {}",
- eventJsonString, deviceId.toString());
-
- String teEventString = removePrefixTagFromJson(eventJsonString,
- TE_NOTIFICATION_PREFIX);
- if (teEventString.startsWith(TE_LINK_EVENT_PREFIX)) {
- String linkString = removePrefixTagFromJson(teEventString,
- TE_LINK_EVENT_PREFIX);
- log.debug("link event={}", linkString);
- handleRestconfLinkNotification(linkString);
- } else if (teEventString.startsWith(TE_NODE_EVENT_PREFIX)) {
- String nodeString = removePrefixTagFromJson(teEventString,
- TE_NODE_EVENT_PREFIX);
- log.debug("node event={}", nodeString);
- handleRestconfNodeNotification(nodeString);
- }
+ public void processEventPayload(String payload) {
+ String linkString = removePrefixTagFromJson(payload,
+ TE_LINK_EVENT_PREFIX);
+ log.debug("link event={}", linkString);
+ handleRestconfLinkNotification(linkString);
}
private void handleRestconfLinkNotification(String linkString) {
@@ -377,29 +367,16 @@
topologyProviderService.linkUpdated(linkKey, networkLink);
}
+ }
- private IetfTeTopologyEvent convertJson2IetfTeTopologyEvent(String uriString,
- String jsonBody) {
+ private class InternalNodeEventProcessor implements
+ RestconfNotificationEventProcessor<String> {
- YangCompositeEncodingImpl yce =
- new YangCompositeEncodingImpl(YangResourceIdentifierType.URI,
- uriString,
- jsonBody);
- Object yo = codecHandler.decode(yce,
- YangProtocolEncodingFormat.JSON,
- YmsOperationType.NOTIFICATION);
-
- if (yo == null) {
- log.error("YMS decoder error");
- return null;
- }
-
- if (!(yo instanceof IetfTeTopologyEvent)) {
- log.error("ERROR: YO is not IetfTeTopologyEvent");
- return null;
- }
-
- return (IetfTeTopologyEvent) yo;
+ @Override
+ public void processEventPayload(String payload) {
+ String nodeString = removePrefixTagFromJson(payload, TE_NODE_EVENT_PREFIX);
+ log.debug("node event={}", nodeString);
+ handleRestconfNodeNotification(nodeString);
}
private void handleRestconfNodeNotification(String nodeString) {
@@ -437,4 +414,43 @@
topologyProviderService.nodeUpdated(nodeKey, networkNode);
}
}
+
+ private class InternalNetworkConfigListener implements NetworkConfigListener {
+
+ @Override
+ public void event(NetworkConfigEvent event) {
+ executor.execute(TeTopologyRestconfProvider.this::connectDevices);
+ }
+
+ @Override
+ public boolean isRelevant(NetworkConfigEvent event) {
+ return event.configClass().equals(RestconfServerConfig.class) &&
+ (event.type() == CONFIG_ADDED ||
+ event.type() == CONFIG_UPDATED);
+ }
+ }
+
+ private IetfTeTopologyEvent convertJson2IetfTeTopologyEvent(String uriString,
+ String jsonBody) {
+
+ YangCompositeEncodingImpl yce =
+ new YangCompositeEncodingImpl(YangResourceIdentifierType.URI,
+ uriString,
+ jsonBody);
+ Object yo = codecHandler.decode(yce,
+ YangProtocolEncodingFormat.JSON,
+ YmsOperationType.NOTIFICATION);
+
+ if (yo == null) {
+ log.error("YMS decoder error");
+ return null;
+ }
+
+ if (!(yo instanceof IetfTeTopologyEvent)) {
+ log.error("ERROR: YO is not IetfTeTopologyEvent");
+ return null;
+ }
+
+ return (IetfTeTopologyEvent) yo;
+ }
}
diff --git a/providers/ietfte/tunnel/src/main/java/org/onosproject/provider/te/tunnel/TeTunnelRestconfProvider.java b/providers/ietfte/tunnel/src/main/java/org/onosproject/provider/te/tunnel/TeTunnelRestconfProvider.java
index 3a081ce..1d9468d 100644
--- a/providers/ietfte/tunnel/src/main/java/org/onosproject/provider/te/tunnel/TeTunnelRestconfProvider.java
+++ b/providers/ietfte/tunnel/src/main/java/org/onosproject/provider/te/tunnel/TeTunnelRestconfProvider.java
@@ -33,8 +33,8 @@
import org.onosproject.net.Path;
import org.onosproject.net.provider.AbstractProvider;
import org.onosproject.net.provider.ProviderId;
-import org.onosproject.protocol.restconf.RestConfNotificationEventListener;
import org.onosproject.protocol.restconf.RestConfSBController;
+import org.onosproject.protocol.restconf.RestconfNotificationEventListener;
import org.onosproject.provider.te.utils.DefaultJsonCodec;
import org.onosproject.provider.te.utils.YangCompositeEncodingImpl;
import org.onosproject.tetopology.management.api.TeTopology;
@@ -89,6 +89,7 @@
private static final int DEFAULT_INDEX = 1;
private static final String TUNNELS = "tunnels";
private static final String TUNNELS_URL = IETF + ":" + TE + "/" + TUNNELS;
+ private static final String IETF_NOTIFICATION_URI = "netconf";
private static final String MEDIA_TYPE_JSON = "json";
private static final String SHOULD_IN_ONE = "Tunnel should be setup in one topo";
@@ -96,8 +97,8 @@
private static final String RESTCONF_ROOT = "/onos/restconf";
private static final String TE_TUNNEL_KEY = "TeTunnelKey";
- private final RestConfNotificationEventListener listener =
- new InternalTunnelNotificationListener();
+ //private final RestconfNotificationEventListener listener =
+ // new InternalTunnelNotificationListener();
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected RestConfSBController controller;
@@ -165,9 +166,14 @@
private void subscribe() {
for (DeviceId deviceId : controller.getDevices().keySet()) {
try {
- controller.enableNotifications(deviceId, TUNNELS_URL,
- MEDIA_TYPE_JSON,
- listener);
+ if (!controller.isNotificationEnabled(deviceId)) {
+ controller.enableNotifications(deviceId, IETF_NOTIFICATION_URI,
+ "application/json",
+ new InternalTunnelNotificationListener());
+ } else {
+ controller.addNotificationListener(deviceId,
+ new InternalTunnelNotificationListener());
+ }
} catch (Exception e) {
log.error("Failed to subscribe for {} : {}", deviceId,
e.getMessage());
@@ -179,7 +185,8 @@
controller.getDevices()
.keySet()
.forEach(deviceId -> controller
- .removeNotificationListener(deviceId));
+ .removeNotificationListener(deviceId,
+ new InternalTunnelNotificationListener()));
}
@Override
@@ -343,8 +350,9 @@
return deviceId;
}
+
private class InternalTunnelNotificationListener implements
- RestConfNotificationEventListener {
+ RestconfNotificationEventListener {
@Override
public void handleNotificationEvent(DeviceId deviceId, Object eventJsonString) {
diff --git a/providers/ietfte/utils/BUCK b/providers/ietfte/utils/BUCK
index 7817d31..0964039 100644
--- a/providers/ietfte/utils/BUCK
+++ b/providers/ietfte/utils/BUCK
@@ -2,6 +2,7 @@
'//lib:CORE_DEPS',
'//apps/yms/api:onos-apps-yms-api',
'//protocols/restconf/server/utils:onos-protocols-restconf-server-utils',
+ '//protocols/restconf/client/api:onos-protocols-restconf-client-api',
]
TEST_DEPS = [
diff --git a/providers/ietfte/utils/pom.xml b/providers/ietfte/utils/pom.xml
index 35c727e..3174a8b 100644
--- a/providers/ietfte/utils/pom.xml
+++ b/providers/ietfte/utils/pom.xml
@@ -37,10 +37,13 @@
</dependency>
<dependency>
<groupId>org.onosproject</groupId>
+ <artifactId>onos-restconf-client-api</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.onosproject</groupId>
<artifactId>onos-restconf-server-utils</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>
-
-
-</project>
\ No newline at end of file
+</project>
diff --git a/providers/ietfte/utils/src/main/java/org/onosproject/provider/te/utils/RestconfNotificationEventProcessor.java b/providers/ietfte/utils/src/main/java/org/onosproject/provider/te/utils/RestconfNotificationEventProcessor.java
new file mode 100644
index 0000000..7f6ea2e
--- /dev/null
+++ b/providers/ietfte/utils/src/main/java/org/onosproject/provider/te/utils/RestconfNotificationEventProcessor.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright 2017-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.provider.te.utils;
+
+/**
+ * Abstraction of the RESTCONF notification callback function. The callback
+ * is invoked by the notification listener when it receives an event.
+ */
+public interface RestconfNotificationEventProcessor<T> {
+ void processEventPayload(T event);
+}
diff --git a/providers/ietfte/utils/src/main/java/org/onosproject/provider/te/utils/TeTopologyRestconfEventListener.java b/providers/ietfte/utils/src/main/java/org/onosproject/provider/te/utils/TeTopologyRestconfEventListener.java
new file mode 100644
index 0000000..668fec6
--- /dev/null
+++ b/providers/ietfte/utils/src/main/java/org/onosproject/provider/te/utils/TeTopologyRestconfEventListener.java
@@ -0,0 +1,143 @@
+/*
+ * Copyright 2017-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.provider.te.utils;
+
+import org.onosproject.net.DeviceId;
+import org.onosproject.protocol.restconf.RestconfNotificationEventListener;
+import org.slf4j.Logger;
+
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+import static org.slf4j.LoggerFactory.getLogger;
+
+/**
+ * Implementation of the RESTCONF notification event
+ * listener for TE Topology.
+ */
+public class TeTopologyRestconfEventListener implements
+ RestconfNotificationEventListener<String> {
+ private static final String TE_TOPOLOGY_NOTIFICATION_PREFIX =
+ "{\"ietf-te-topology:ietf-te-topology\":";
+ private static final String TE_LINK_EVENT_PREFIX =
+ "{\"ietf-te-topology:te-link-event\":";
+ private static final String TE_NODE_EVENT_PREFIX =
+ "{\"ietf-te-topology:te-node-event\":";
+
+ private final Logger log = getLogger(getClass());
+
+ private Map<TeTopologyRestconfEventType, RestconfNotificationEventProcessor>
+ eventCallbackFunctionMap = new ConcurrentHashMap<>();
+
+ @Override
+ public void handleNotificationEvent(DeviceId deviceId,
+ String eventJsonString) {
+ log.debug("New notification: {} for device: {}",
+ eventJsonString, deviceId.toString());
+
+ if (!eventJsonString.startsWith(TE_TOPOLOGY_NOTIFICATION_PREFIX)) {
+ // This is not a TE topology event.
+ return;
+ }
+
+ String teEventString = removePrefixTagFromJson(eventJsonString,
+ TE_TOPOLOGY_NOTIFICATION_PREFIX);
+
+ TeTopologyRestconfEventType eventType = getEventType(teEventString);
+
+ if (eventType == TeTopologyRestconfEventType.TE_UNKNOWN_EVENT) {
+ log.error("handleNotificationEvent: unknown event: {}", eventJsonString);
+ return;
+ }
+
+ RestconfNotificationEventProcessor eventProcessor =
+ eventCallbackFunctionMap.get(eventType);
+
+ if (eventProcessor != null) {
+ eventProcessor.processEventPayload(teEventString);
+ } else {
+ log.info("Event callback not installed for event type: {}", eventType);
+ }
+ }
+
+ /**
+ * Registers an notification event callback function which is called by
+ * the listener when it receives an event.
+ *
+ * @param eventType notification event type corresponding to the
+ * callback function
+ * @param eventProcessor callback function
+ */
+ public void addCallbackFunction(TeTopologyRestconfEventType eventType,
+ RestconfNotificationEventProcessor eventProcessor) {
+ if (eventCallbackFunctionMap.containsKey(eventType)) {
+ removeCallbackFunction(eventType);
+ }
+
+ eventCallbackFunctionMap.put(eventType, eventProcessor);
+ }
+
+ /**
+ * Removes the callback function associated with the given event type.
+ *
+ * @param eventType notification event type
+ */
+ public void removeCallbackFunction(TeTopologyRestconfEventType eventType) {
+ eventCallbackFunctionMap.remove(eventType);
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+
+ TeTopologyRestconfEventListener that = (TeTopologyRestconfEventListener) o;
+
+ return eventCallbackFunctionMap != null ?
+ eventCallbackFunctionMap.equals(that.eventCallbackFunctionMap) :
+ that.eventCallbackFunctionMap == null;
+ }
+
+ @Override
+ public int hashCode() {
+ return eventCallbackFunctionMap != null ? eventCallbackFunctionMap.hashCode() : 0;
+ }
+
+ private String removePrefixTagFromJson(String jsonString, String prefixTag) {
+ if (jsonString.startsWith(prefixTag)) {
+ return jsonString.substring(prefixTag.length(), jsonString.length() - 1);
+ }
+ return jsonString;
+ }
+
+ private TeTopologyRestconfEventType getEventType(String teEventString) {
+ if (teEventString.startsWith(TE_LINK_EVENT_PREFIX)) {
+ return TeTopologyRestconfEventType.TE_TOPOLOGY_LINK_NOTIFICATION;
+ }
+
+ if (teEventString.startsWith(TE_NODE_EVENT_PREFIX)) {
+ return TeTopologyRestconfEventType.TE_TOPOLOGY_NODE_NOTIFICATION;
+ }
+
+ return TeTopologyRestconfEventType.TE_UNKNOWN_EVENT;
+ }
+}
+
diff --git a/providers/ietfte/utils/src/main/java/org/onosproject/provider/te/utils/TeTopologyRestconfEventType.java b/providers/ietfte/utils/src/main/java/org/onosproject/provider/te/utils/TeTopologyRestconfEventType.java
new file mode 100644
index 0000000..6806023
--- /dev/null
+++ b/providers/ietfte/utils/src/main/java/org/onosproject/provider/te/utils/TeTopologyRestconfEventType.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2017-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.provider.te.utils;
+
+/**
+ * Types of TE Topology RESTCONF notification events.
+ */
+public enum TeTopologyRestconfEventType {
+ /**
+ * TE topology link event type.
+ */
+ TE_TOPOLOGY_LINK_NOTIFICATION,
+
+ /**
+ * TE topology node event type.
+ */
+ TE_TOPOLOGY_NODE_NOTIFICATION,
+
+ /**
+ * Unknown or unsupported event type.
+ */
+ TE_UNKNOWN_EVENT,
+}