import org.opendaylight.restconf.nb.rfc8040.rests.services.impl.RestconfInvokeOperationsServiceImpl;
import org.opendaylight.restconf.nb.rfc8040.rests.services.impl.RestconfOperationsServiceImpl;
import org.opendaylight.restconf.nb.rfc8040.rests.services.impl.RestconfSchemaServiceImpl;
-import org.opendaylight.restconf.nb.rfc8040.rests.services.impl.RestconfStreamsSubscriptionServiceImpl;
import org.opendaylight.restconf.nb.rfc8040.streams.ListenersBroker;
final class RestconfApplication extends Application {
final DOMSchemaService domSchemaService, final ListenersBroker listenersBroker) {
singletons = Set.of(
new RestconfDocumentedExceptionMapper(databindProvider),
- // FIXME: NETCONF:1102: do not instantiate this service
- new RestconfStreamsSubscriptionServiceImpl(dataBroker, notificationService, databindProvider,
- listenersBroker),
new RestconfDataServiceImpl(databindProvider, server, actionService),
new RestconfInvokeOperationsServiceImpl(databindProvider, server, mountPointService, listenersBroker),
new RestconfOperationsServiceImpl(databindProvider, server),
+++ /dev/null
-/*
- * Copyright (c) 2016 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.restconf.nb.rfc8040.rests.services.api;
-
-import javax.ws.rs.Encoded;
-import javax.ws.rs.GET;
-import javax.ws.rs.Path;
-import javax.ws.rs.PathParam;
-import javax.ws.rs.core.Context;
-import javax.ws.rs.core.Response;
-import javax.ws.rs.core.UriInfo;
-import org.opendaylight.restconf.nb.rfc8040.legacy.NormalizedNodePayload;
-import org.opendaylight.restconf.nb.rfc8040.streams.RestconfStreamsConstants;
-
-/**
- * Subscribing to streams.
- */
-public interface RestconfStreamsSubscriptionService {
- /**
- * Subscribing to receive notification from stream support.
- *
- * @param identifier name of stream
- * @param uriInfo URI info
- * @return a response containing {@link NormalizedNodePayload}
- */
- // FIXME: this is a REST violation: GET does not transfer state! This should work in terms of
- // https://www.rfc-editor.org/rfc/rfc8639#section-2.4, i.e. when we have that, aggressively deprecate
- // and remove this special case. Besides it routes to a very bad thing in RestconfDataServiceImpl
- @GET
- @Path("data/" + RestconfStreamsConstants.STREAMS_PATH + "/stream/{identifier:.+}")
- Response subscribeToStream(@Encoded @PathParam("identifier") String identifier, @Context UriInfo uriInfo);
-}
+++ /dev/null
-/*
- * Copyright (c) 2016 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.restconf.nb.rfc8040.rests.services.impl;
-
-import static java.util.Objects.requireNonNull;
-
-import java.net.URI;
-import javax.ws.rs.Path;
-import javax.ws.rs.core.Response;
-import javax.ws.rs.core.UriInfo;
-import org.eclipse.jdt.annotation.NonNull;
-import org.opendaylight.mdsal.dom.api.DOMDataBroker;
-import org.opendaylight.mdsal.dom.api.DOMNotificationService;
-import org.opendaylight.restconf.common.errors.RestconfDocumentedException;
-import org.opendaylight.restconf.nb.rfc8040.databind.DatabindProvider;
-import org.opendaylight.restconf.nb.rfc8040.databind.jaxrs.QueryParams;
-import org.opendaylight.restconf.nb.rfc8040.legacy.NormalizedNodePayload;
-import org.opendaylight.restconf.nb.rfc8040.rests.services.api.RestconfStreamsSubscriptionService;
-import org.opendaylight.restconf.nb.rfc8040.streams.ListenersBroker;
-import org.opendaylight.restconf.nb.rfc8040.streams.RestconfStreamsConstants;
-import org.opendaylight.yang.gen.v1.subscribe.to.notification.rev161028.Notifi;
-import org.opendaylight.yangtools.yang.common.QName;
-import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
-import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
-import org.opendaylight.yangtools.yang.model.util.SchemaInferenceStack.Inference;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * Implementation of {@link RestconfStreamsSubscriptionService}.
- */
-@Path("/")
-public class RestconfStreamsSubscriptionServiceImpl implements RestconfStreamsSubscriptionService {
- private static final Logger LOG = LoggerFactory.getLogger(RestconfStreamsSubscriptionServiceImpl.class);
- private static final QName LOCATION_QNAME = QName.create(Notifi.QNAME, "location").intern();
- private static final NodeIdentifier LOCATION_NODEID = NodeIdentifier.create(LOCATION_QNAME);
-
- private final ListenersBroker listenersBroker;
- private final HandlersHolder handlersHolder;
-
- /**
- * Initialize holder of handlers with holders as parameters.
- *
- * @param dataBroker {@link DOMDataBroker}
- * @param notificationService {@link DOMNotificationService}
- * @param databindProvider a {@link DatabindProvider}
- * @param listenersBroker a {@link ListenersBroker}
- */
- public RestconfStreamsSubscriptionServiceImpl(final DOMDataBroker dataBroker,
- final DOMNotificationService notificationService, final DatabindProvider databindProvider,
- final ListenersBroker listenersBroker) {
- handlersHolder = new HandlersHolder(dataBroker, notificationService, databindProvider);
- this.listenersBroker = requireNonNull(listenersBroker);
- }
-
- @Override
- public Response subscribeToStream(final String identifier, final UriInfo uriInfo) {
- final var params = QueryParams.newReceiveEventsParams(uriInfo);
-
- final URI location;
- if (identifier.contains(RestconfStreamsConstants.DATA_SUBSCRIPTION)) {
- location = listenersBroker.subscribeToDataStream(identifier, uriInfo, params, handlersHolder);
- } else if (identifier.contains(RestconfStreamsConstants.NOTIFICATION_STREAM)) {
- location = listenersBroker.subscribeToYangStream(identifier, uriInfo, params, handlersHolder);
- } else {
- final String msg = "Bad type of notification of sal-remote";
- LOG.warn(msg);
- throw new RestconfDocumentedException(msg);
- }
-
- return Response.ok()
- .location(location)
- .entity(new NormalizedNodePayload(
- Inference.ofDataTreePath(handlersHolder.databindProvider().currentContext().modelContext(),
- Notifi.QNAME, LOCATION_QNAME),
- ImmutableNodes.leafNode(LOCATION_NODEID, location.toString())))
- .build();
- }
-
- /**
- * Holder of all handlers for notifications.
- */
- // FIXME: why do we even need this class?!
- public record HandlersHolder(
- @NonNull DOMDataBroker dataBroker,
- @NonNull DOMNotificationService notificationService,
- @NonNull DatabindProvider databindProvider) {
-
- public HandlersHolder {
- requireNonNull(dataBroker);
- requireNonNull(notificationService);
- requireNonNull(databindProvider);
- }
- }
-}
import org.opendaylight.mdsal.dom.api.DOMDataTreeWriteOperations;
import org.opendaylight.mdsal.dom.api.DOMDataTreeWriteTransaction;
import org.opendaylight.mdsal.dom.api.DOMMountPointService;
+import org.opendaylight.mdsal.dom.api.DOMNotificationService;
import org.opendaylight.restconf.common.errors.RestconfDocumentedException;
import org.opendaylight.restconf.nb.rfc8040.ReceiveEventsParams;
import org.opendaylight.restconf.nb.rfc8040.URLConstants;
-import org.opendaylight.restconf.nb.rfc8040.rests.services.impl.RestconfStreamsSubscriptionServiceImpl.HandlersHolder;
+import org.opendaylight.restconf.nb.rfc8040.databind.DatabindProvider;
import org.opendaylight.restconf.nb.rfc8040.utils.parser.IdentifierCodec;
import org.opendaylight.yang.gen.v1.urn.sal.restconf.event.subscription.rev140708.CreateDataChangeEventSubscriptionInput1.Scope;
import org.opendaylight.yang.gen.v1.urn.sal.restconf.event.subscription.rev140708.NotificationOutputTypeGrouping.NotificationOutputType;
}
}
+ /**
+ * Holder of all handlers for notifications.
+ */
+ // FIXME: why do we even need this class?!
+ private record HandlersHolder(
+ @NonNull DOMDataBroker dataBroker,
+ @NonNull DOMNotificationService notificationService,
+ @NonNull DatabindProvider databindProvider) {
+
+ HandlersHolder {
+ requireNonNull(dataBroker);
+ requireNonNull(notificationService);
+ requireNonNull(databindProvider);
+ }
+ }
+
+// private static final QName LOCATION_QNAME = QName.create(Notifi.QNAME, "location").intern();
+// private static final NodeIdentifier LOCATION_NODEID = NodeIdentifier.create(LOCATION_QNAME);
+// private static final String STREAMS_PATH = "ietf-restconf-monitoring:restconf-state/streams";
+// private static final String STREAM_PATH_PART = "/stream=";
+// private static final String STREAM_PATH = STREAMS_PATH + STREAM_PATH_PART;
+// private static final String STREAM_ACCESS_PATH_PART = "/access=";
+// private static final String STREAM_LOCATION_PATH_PART = "/location";
+//
+// private final ListenersBroker listenersBroker;
+// private final HandlersHolder handlersHolder;
+//
+// // FIXME: NETCONF:1102: do not instantiate this service
+// new RestconfStreamsSubscriptionServiceImpl(dataBroker, notificationService, databindProvider,
+// listenersBroker),
+//
+// /**
+// * Initialize holder of handlers with holders as parameters.
+// *
+// * @param dataBroker {@link DOMDataBroker}
+// * @param notificationService {@link DOMNotificationService}
+// * @param databindProvider a {@link DatabindProvider}
+// * @param listenersBroker a {@link ListenersBroker}
+// */
+// public RestconfStreamsSubscriptionServiceImpl(final DOMDataBroker dataBroker,
+// final DOMNotificationService notificationService, final DatabindProvider databindProvider,
+// final ListenersBroker listenersBroker) {
+// handlersHolder = new HandlersHolder(dataBroker, notificationService, databindProvider);
+// this.listenersBroker = requireNonNull(listenersBroker);
+// }
+//
+// @Override
+// public Response subscribeToStream(final String identifier, final UriInfo uriInfo) {
+// final var params = QueryParams.newReceiveEventsParams(uriInfo);
+//
+// final URI location;
+// if (identifier.contains(RestconfStreamsConstants.DATA_SUBSCRIPTION)) {
+// location = listenersBroker.subscribeToDataStream(identifier, uriInfo, params, handlersHolder);
+// } else if (identifier.contains(RestconfStreamsConstants.NOTIFICATION_STREAM)) {
+// location = listenersBroker.subscribeToYangStream(identifier, uriInfo, params, handlersHolder);
+// } else {
+// final String msg = "Bad type of notification of sal-remote";
+// LOG.warn(msg);
+// throw new RestconfDocumentedException(msg);
+// }
+//
+// return Response.ok()
+// .location(location)
+// .entity(new NormalizedNodePayload(
+// Inference.ofDataTreePath(handlersHolder.databindProvider().currentContext().modelContext(),
+// Notifi.QNAME, LOCATION_QNAME),
+// ImmutableNodes.leafNode(LOCATION_NODEID, location.toString())))
+// .build();
+// }
+
private static final Logger LOG = LoggerFactory.getLogger(ListenersBroker.class);
+ // Prefixes for stream names
+ private static final String DATA_SUBSCRIPTION = "data-change-event-subscription";
+ private static final String NOTIFICATION_STREAM = "notification-stream";
+ private static final String DEVICE_NOTIFICATION_STREAM = "device-notification-stream";
+
private final StampedLock dataChangeListenersLock = new StampedLock();
private final StampedLock notificationListenersLock = new StampedLock();
private final StampedLock deviceNotificationListenersLock = new StampedLock();
* or {@link Optional#empty()} if listener with specified stream name doesn't exist.
*/
public final @Nullable AbstractStream<?> listenerFor(final String streamName) {
- if (streamName.startsWith(RestconfStreamsConstants.NOTIFICATION_STREAM)) {
+ if (streamName.startsWith(NOTIFICATION_STREAM)) {
return notificationListenerFor(streamName);
- } else if (streamName.startsWith(RestconfStreamsConstants.DATA_SUBSCRIPTION)) {
+ } else if (streamName.startsWith(DATA_SUBSCRIPTION)) {
return dataChangeListenerFor(streamName);
- } else if (streamName.startsWith(RestconfStreamsConstants.DEVICE_NOTIFICATION_STREAM)) {
+ } else if (streamName.startsWith(DEVICE_NOTIFICATION_STREAM)) {
return deviceNotificationListenerFor(streamName);
} else {
return null;
public final ListenerAdapter registerDataChangeListener(final EffectiveModelContext modelContext,
final LogicalDatastoreType datastore, final YangInstanceIdentifier path, final Scope scope,
final NotificationOutputType outputType) {
- final var sb = new StringBuilder(RestconfStreamsConstants.DATA_SUBSCRIPTION)
+ final var sb = new StringBuilder(DATA_SUBSCRIPTION)
.append('/').append(createStreamNameFromUri(IdentifierCodec.serialize(path, modelContext)))
.append('/').append(RestconfStreamsConstants.DATASTORE_PARAM_NAME).append('=').append(datastore)
.append('/').append(RestconfStreamsConstants.SCOPE_PARAM_NAME).append('=').append(scope);
*/
public final NotificationListenerAdapter registerNotificationListener(final EffectiveModelContext refSchemaCtx,
final ImmutableSet<QName> notifications, final NotificationOutputType outputType) {
- final var sb = new StringBuilder(RestconfStreamsConstants.NOTIFICATION_STREAM).append('/');
+ final var sb = new StringBuilder(NOTIFICATION_STREAM).append('/');
var haveFirst = false;
for (var qname : notifications) {
final var module = refSchemaCtx.findModuleStatement(qname.getModule())
public final DeviceNotificationListenerAdaptor registerDeviceNotificationListener(final String deviceName,
final NotificationOutputType outputType, final EffectiveModelContext refSchemaCtx,
final DOMMountPointService mountPointService, final YangInstanceIdentifier path) {
- final var sb = new StringBuilder(RestconfStreamsConstants.DEVICE_NOTIFICATION_STREAM).append('/')
+ final var sb = new StringBuilder(DEVICE_NOTIFICATION_STREAM).append('/')
.append(deviceName);
final long stamp = deviceNotificationListenersLock.writeLock();
public static final String DATASTORE_PARAM_NAME = "datastore";
public static final String SCOPE_PARAM_NAME = "scope";
- // Prefixes for stream names
- public static final String DATA_SUBSCRIPTION = "data-change-event-subscription";
- public static final String NOTIFICATION_STREAM = "notification-stream";
- static final String DEVICE_NOTIFICATION_STREAM = "device-notification-stream";
-
- public static final String STREAMS_PATH = "ietf-restconf-monitoring:restconf-state/streams";
- public static final String STREAM_PATH_PART = "/stream=";
- public static final String STREAM_PATH = STREAMS_PATH + STREAM_PATH_PART;
- public static final String STREAM_ACCESS_PATH_PART = "/access=";
- public static final String STREAM_LOCATION_PATH_PART = "/location";
-
private RestconfStreamsConstants() {
// Hidden on purpose
}
+++ /dev/null
-/*
- * Copyright (c) 2016 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.restconf.nb.rfc8040.rests.services.impl;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertThrows;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.mock;
-
-import com.google.common.collect.ImmutableClassToInstanceMap;
-import java.net.URI;
-import javax.ws.rs.core.MultivaluedHashMap;
-import javax.ws.rs.core.UriBuilder;
-import javax.ws.rs.core.UriInfo;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.junit.MockitoJUnitRunner;
-import org.opendaylight.mdsal.common.api.CommitInfo;
-import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
-import org.opendaylight.mdsal.dom.api.DOMDataBroker;
-import org.opendaylight.mdsal.dom.api.DOMDataTreeChangeService;
-import org.opendaylight.mdsal.dom.api.DOMDataTreeWriteTransaction;
-import org.opendaylight.mdsal.dom.api.DOMNotificationService;
-import org.opendaylight.restconf.common.errors.RestconfDocumentedException;
-import org.opendaylight.restconf.nb.rfc8040.databind.DatabindContext;
-import org.opendaylight.restconf.nb.rfc8040.databind.DatabindProvider;
-import org.opendaylight.restconf.nb.rfc8040.streams.AbstractNotificationListenerTest;
-import org.opendaylight.restconf.nb.rfc8040.streams.ListenersBroker;
-import org.opendaylight.restconf.nb.rfc8040.utils.parser.IdentifierCodec;
-import org.opendaylight.yang.gen.v1.urn.sal.restconf.event.subscription.rev140708.CreateDataChangeEventSubscriptionInput1.Scope;
-import org.opendaylight.yang.gen.v1.urn.sal.restconf.event.subscription.rev140708.NotificationOutputTypeGrouping.NotificationOutputType;
-import org.opendaylight.yangtools.concepts.ListenerRegistration;
-import org.opendaylight.yangtools.yang.common.ErrorTag;
-import org.opendaylight.yangtools.yang.common.ErrorType;
-
-@RunWith(MockitoJUnitRunner.StrictStubs.class)
-public class RestconfStreamsSubscriptionServiceImplTest extends AbstractNotificationListenerTest {
- private static final String URI = "/rests/data/ietf-restconf-monitoring:restconf-state/streams/stream/"
- + "toaster:toaster/toasterStatus/datastore=OPERATIONAL/scope=ONE";
-
- @Mock
- private DOMDataBroker dataBroker;
- @Mock
- private UriInfo uriInfo;
- @Mock
- private DOMNotificationService notificationService;
-
- private final DatabindProvider databindProvider = () -> DatabindContext.ofModel(MODEL_CONTEXT);
-
- @Before
- public void setUp() throws Exception {
- final var wTx = mock(DOMDataTreeWriteTransaction.class);
- doReturn(wTx).when(dataBroker).newWriteOnlyTransaction();
- doReturn(CommitInfo.emptyFluentFuture()).when(wTx).commit();
-
- final var dataTreeChangeService = mock(DOMDataTreeChangeService.class);
- doReturn(mock(ListenerRegistration.class)).when(dataTreeChangeService)
- .registerDataTreeChangeListener(any(), any());
-
- doReturn(ImmutableClassToInstanceMap.of(DOMDataTreeChangeService.class, dataTreeChangeService))
- .when(dataBroker).getExtensions();
-
- doReturn(new MultivaluedHashMap<>()).when(uriInfo).getQueryParameters();
- doReturn(UriBuilder.fromUri("http://localhost:8181")).when(uriInfo).getBaseUriBuilder();
- doReturn(new URI("http://127.0.0.1/" + URI)).when(uriInfo).getAbsolutePath();
- }
-
- @Test
- public void testSubscribeToStreamSSE() {
- final var listenersBroker = new ListenersBroker.ServerSentEvents();
- listenersBroker.registerDataChangeListener(MODEL_CONTEXT, LogicalDatastoreType.OPERATIONAL,
- IdentifierCodec.deserialize("toaster:toaster/toasterStatus", MODEL_CONTEXT), Scope.ONE,
- NotificationOutputType.XML);
- final var streamsSubscriptionService = new RestconfStreamsSubscriptionServiceImpl(dataBroker,
- notificationService, databindProvider,listenersBroker);
- final var response = streamsSubscriptionService.subscribeToStream(
- "data-change-event-subscription/toaster:toaster/toasterStatus/datastore=OPERATIONAL/scope=ONE", uriInfo);
- assertEquals("http://localhost:8181/rests/streams"
- + "/data-change-event-subscription/toaster:toaster/toasterStatus/datastore=OPERATIONAL/scope=ONE",
- response.getLocation().toString());
- }
-
- @Test
- public void testSubscribeToStreamWS() {
- final var listenersBroker = new ListenersBroker.WebSockets();
- listenersBroker.registerDataChangeListener(MODEL_CONTEXT, LogicalDatastoreType.OPERATIONAL,
- IdentifierCodec.deserialize("toaster:toaster/toasterStatus", MODEL_CONTEXT), Scope.ONE,
- NotificationOutputType.XML);
- final var streamsSubscriptionService = new RestconfStreamsSubscriptionServiceImpl(dataBroker,
- notificationService, databindProvider, listenersBroker);
- final var response = streamsSubscriptionService.subscribeToStream(
- "data-change-event-subscription/toaster:toaster/toasterStatus/datastore=OPERATIONAL/scope=ONE", uriInfo);
- assertEquals("ws://localhost:8181/rests/streams"
- + "/data-change-event-subscription/toaster:toaster/toasterStatus/datastore=OPERATIONAL/scope=ONE",
- response.getLocation().toString());
- }
-
- @Test
- public void testSubscribeToStreamMissingDatastoreInPath() {
- final var listenersBroker = new ListenersBroker.WebSockets();
- final var streamsSubscriptionService = new RestconfStreamsSubscriptionServiceImpl(dataBroker,
- notificationService, databindProvider, listenersBroker);
- final var errors = assertThrows(RestconfDocumentedException.class,
- () -> streamsSubscriptionService.subscribeToStream("toaster:toaster/toasterStatus/scope=ONE", uriInfo))
- .getErrors();
- assertEquals(1, errors.size());
- final var error = errors.get(0);
- assertEquals(ErrorType.APPLICATION, error.getErrorType());
- assertEquals(ErrorTag.OPERATION_FAILED, error.getErrorTag());
- assertEquals("Bad type of notification of sal-remote", error.getErrorMessage());
- }
-
- @Test
- public void testSubscribeToStreamMissingScopeInPath() {
- final var listenersBroker = new ListenersBroker.WebSockets();
- final var streamsSubscriptionService = new RestconfStreamsSubscriptionServiceImpl(dataBroker,
- notificationService, databindProvider, listenersBroker);
- final var errors = assertThrows(RestconfDocumentedException.class,
- () -> streamsSubscriptionService.subscribeToStream("toaster:toaster/toasterStatus/datastore=OPERATIONAL",
- uriInfo)).getErrors();
- assertEquals(1, errors.size());
- final var error = errors.get(0);
- assertEquals(ErrorType.APPLICATION, error.getErrorType());
- assertEquals(ErrorTag.OPERATION_FAILED, error.getErrorTag());
- assertEquals("Bad type of notification of sal-remote", error.getErrorMessage());
- }
-}
--- /dev/null
+/*
+ * Copyright (c) 2016 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.restconf.nb.rfc8040.streams;
+
+//import static org.junit.Assert.assertEquals;
+//import static org.junit.Assert.assertThrows;
+//import static org.mockito.ArgumentMatchers.any;
+//import static org.mockito.Mockito.doReturn;
+//import static org.mockito.Mockito.mock;
+//
+//import com.google.common.collect.ImmutableClassToInstanceMap;
+//import java.net.URI;
+//import javax.ws.rs.core.MultivaluedHashMap;
+//import javax.ws.rs.core.UriBuilder;
+//import javax.ws.rs.core.UriInfo;
+//import org.junit.Before;
+//import org.junit.Test;
+//import org.junit.runner.RunWith;
+//import org.mockito.Mock;
+//import org.mockito.junit.MockitoJUnitRunner;
+//import org.opendaylight.mdsal.common.api.CommitInfo;
+//import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
+//import org.opendaylight.mdsal.dom.api.DOMDataBroker;
+//import org.opendaylight.mdsal.dom.api.DOMDataTreeChangeService;
+//import org.opendaylight.mdsal.dom.api.DOMDataTreeWriteTransaction;
+//import org.opendaylight.mdsal.dom.api.DOMNotificationService;
+//import org.opendaylight.restconf.common.errors.RestconfDocumentedException;
+//import org.opendaylight.restconf.nb.rfc8040.databind.DatabindContext;
+//import org.opendaylight.restconf.nb.rfc8040.databind.DatabindProvider;
+//import org.opendaylight.restconf.nb.rfc8040.streams.ListenersBroker;
+//import org.opendaylight.restconf.nb.rfc8040.utils.parser.IdentifierCodec;
+//import org.opendaylight.yang.gen.v1.urn.sal.restconf.event.subscription.rev140708
+// .CreateDataChangeEventSubscriptionInput1.Scope;
+//import org.opendaylight.yang.gen.v1.urn.sal.restconf.event.subscription.rev140708.NotificationOutputTypeGrouping
+// .NotificationOutputType;
+//import org.opendaylight.yangtools.concepts.ListenerRegistration;
+//import org.opendaylight.yangtools.yang.common.ErrorTag;
+//import org.opendaylight.yangtools.yang.common.ErrorType;
+
+//@RunWith(MockitoJUnitRunner.StrictStubs.class)
+public class RestconfStreamsSubscriptionServiceImplTest extends AbstractNotificationListenerTest {
+// private static final String URI = "/rests/data/ietf-restconf-monitoring:restconf-state/streams/stream/"
+// + "toaster:toaster/toasterStatus/datastore=OPERATIONAL/scope=ONE";
+//
+// @Mock
+// private DOMDataBroker dataBroker;
+// @Mock
+// private UriInfo uriInfo;
+// @Mock
+// private DOMNotificationService notificationService;
+//
+// private final DatabindProvider databindProvider = () -> DatabindContext.ofModel(MODEL_CONTEXT);
+//
+// @Before
+// public void setUp() throws Exception {
+// final var wTx = mock(DOMDataTreeWriteTransaction.class);
+// doReturn(wTx).when(dataBroker).newWriteOnlyTransaction();
+// doReturn(CommitInfo.emptyFluentFuture()).when(wTx).commit();
+//
+// final var dataTreeChangeService = mock(DOMDataTreeChangeService.class);
+// doReturn(mock(ListenerRegistration.class)).when(dataTreeChangeService)
+// .registerDataTreeChangeListener(any(), any());
+//
+// doReturn(ImmutableClassToInstanceMap.of(DOMDataTreeChangeService.class, dataTreeChangeService))
+// .when(dataBroker).getExtensions();
+//
+// doReturn(new MultivaluedHashMap<>()).when(uriInfo).getQueryParameters();
+// doReturn(UriBuilder.fromUri("http://localhost:8181")).when(uriInfo).getBaseUriBuilder();
+// doReturn(new URI("http://127.0.0.1/" + URI)).when(uriInfo).getAbsolutePath();
+// }
+//
+// @Test
+// public void testSubscribeToStreamSSE() {
+// final var listenersBroker = new ListenersBroker.ServerSentEvents();
+// listenersBroker.registerDataChangeListener(MODEL_CONTEXT, LogicalDatastoreType.OPERATIONAL,
+// IdentifierCodec.deserialize("toaster:toaster/toasterStatus", MODEL_CONTEXT), Scope.ONE,
+// NotificationOutputType.XML);
+// final var streamsSubscriptionService = new RestconfStreamsSubscriptionServiceImpl(dataBroker,
+// notificationService, databindProvider,listenersBroker);
+// final var response = streamsSubscriptionService.subscribeToStream(
+// "data-change-event-subscription/toaster:toaster/toasterStatus/datastore=OPERATIONAL/scope=ONE", uriInfo);
+// assertEquals("http://localhost:8181/rests/streams"
+// + "/data-change-event-subscription/toaster:toaster/toasterStatus/datastore=OPERATIONAL/scope=ONE",
+// response.getLocation().toString());
+// }
+//
+// @Test
+// public void testSubscribeToStreamWS() {
+// final var listenersBroker = new ListenersBroker.WebSockets();
+// listenersBroker.registerDataChangeListener(MODEL_CONTEXT, LogicalDatastoreType.OPERATIONAL,
+// IdentifierCodec.deserialize("toaster:toaster/toasterStatus", MODEL_CONTEXT), Scope.ONE,
+// NotificationOutputType.XML);
+// final var streamsSubscriptionService = new RestconfStreamsSubscriptionServiceImpl(dataBroker,
+// notificationService, databindProvider, listenersBroker);
+// final var response = streamsSubscriptionService.subscribeToStream(
+// "data-change-event-subscription/toaster:toaster/toasterStatus/datastore=OPERATIONAL/scope=ONE", uriInfo);
+// assertEquals("ws://localhost:8181/rests/streams"
+// + "/data-change-event-subscription/toaster:toaster/toasterStatus/datastore=OPERATIONAL/scope=ONE",
+// response.getLocation().toString());
+// }
+//
+// @Test
+// public void testSubscribeToStreamMissingDatastoreInPath() {
+// final var listenersBroker = new ListenersBroker.WebSockets();
+// final var streamsSubscriptionService = new RestconfStreamsSubscriptionServiceImpl(dataBroker,
+// notificationService, databindProvider, listenersBroker);
+// final var errors = assertThrows(RestconfDocumentedException.class,
+// () -> streamsSubscriptionService.subscribeToStream("toaster:toaster/toasterStatus/scope=ONE", uriInfo))
+// .getErrors();
+// assertEquals(1, errors.size());
+// final var error = errors.get(0);
+// assertEquals(ErrorType.APPLICATION, error.getErrorType());
+// assertEquals(ErrorTag.OPERATION_FAILED, error.getErrorTag());
+// assertEquals("Bad type of notification of sal-remote", error.getErrorMessage());
+// }
+//
+// @Test
+// public void testSubscribeToStreamMissingScopeInPath() {
+// final var listenersBroker = new ListenersBroker.WebSockets();
+// final var streamsSubscriptionService = new RestconfStreamsSubscriptionServiceImpl(dataBroker,
+// notificationService, databindProvider, listenersBroker);
+// final var errors = assertThrows(RestconfDocumentedException.class,
+// () -> streamsSubscriptionService.subscribeToStream("toaster:toaster/toasterStatus/datastore=OPERATIONAL",
+// uriInfo)).getErrors();
+// assertEquals(1, errors.size());
+// final var error = errors.get(0);
+// assertEquals(ErrorType.APPLICATION, error.getErrorType());
+// assertEquals(ErrorTag.OPERATION_FAILED, error.getErrorTag());
+// assertEquals("Bad type of notification of sal-remote", error.getErrorMessage());
+// }
+}