X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=blobdiff_plain;ds=sidebyside;f=restconf%2Fsal-rest-connector%2Fsrc%2Fmain%2Fjava%2Forg%2Fopendaylight%2Fnetconf%2Fsal%2Frestconf%2Fimpl%2FRestconfImpl.java;h=eff4885f630de665ee3029c7cf9ee4fe06c220a7;hb=ddc71443d58ac78f8a593be88e181310f1e4b9c8;hp=25d081d73c2e145609ed49c3462a6a0f5d1e302c;hpb=04b98cadf3669bcce59df63268c06c94514ac919;p=netconf.git diff --git a/restconf/sal-rest-connector/src/main/java/org/opendaylight/netconf/sal/restconf/impl/RestconfImpl.java b/restconf/sal-rest-connector/src/main/java/org/opendaylight/netconf/sal/restconf/impl/RestconfImpl.java index 25d081d73c..eff4885f63 100644 --- a/restconf/sal-rest-connector/src/main/java/org/opendaylight/netconf/sal/restconf/impl/RestconfImpl.java +++ b/restconf/sal-rest-connector/src/main/java/org/opendaylight/netconf/sal/restconf/impl/RestconfImpl.java @@ -22,6 +22,7 @@ import com.google.common.util.concurrent.FutureCallback; import com.google.common.util.concurrent.Futures; import java.net.URI; import java.net.URISyntaxException; +import java.text.DateFormat; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.ArrayList; @@ -33,6 +34,7 @@ import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; +import java.util.Map.Entry; import java.util.Set; import java.util.concurrent.CancellationException; import java.util.concurrent.CountDownLatch; @@ -62,6 +64,7 @@ import org.opendaylight.netconf.sal.streams.listeners.ListenerAdapter; import org.opendaylight.netconf.sal.streams.listeners.NotificationListenerAdapter; import org.opendaylight.netconf.sal.streams.listeners.Notificator; import org.opendaylight.netconf.sal.streams.websockets.WebSocketServer; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.DateAndTime; import org.opendaylight.yang.gen.v1.urn.sal.restconf.event.subscription.rev140708.NotificationOutputTypeGrouping.NotificationOutputType; import org.opendaylight.yangtools.yang.common.QName; import org.opendaylight.yangtools.yang.common.QNameModule; @@ -83,7 +86,9 @@ import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes; import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.CollectionNodeBuilder; import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContainerNodeAttrBuilder; import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.ListNodeBuilder; +import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.NormalizedNodeAttrBuilder; import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableContainerNodeBuilder; +import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableLeafNodeBuilder; import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode; import org.opendaylight.yangtools.yang.model.api.DataNodeContainer; import org.opendaylight.yangtools.yang.model.api.DataSchemaNode; @@ -1043,17 +1048,118 @@ public class RestconfImpl implements RestconfService { * */ @Override - public Response subscribeToStream(final String identifier, final UriInfo uriInfo) { + public NormalizedNodeContext subscribeToStream(final String identifier, final UriInfo uriInfo) { + boolean startTime_used = false; + boolean stopTime_used = false; + boolean filter_used = false; + Date start = null; + Date stop = null; + String filter = null; + + for (final Entry> entry : uriInfo.getQueryParameters().entrySet()) { + switch (entry.getKey()) { + case "start-time": + if (!startTime_used) { + startTime_used = true; + start = parseDateFromQueryParam(entry); + } else { + throw new RestconfDocumentedException("Start-time parameter can be used only once."); + } + break; + case "stop-time": + if (!stopTime_used) { + stopTime_used = true; + stop = parseDateFromQueryParam(entry); + } else { + throw new RestconfDocumentedException("Stop-time parameter can be used only once."); + } + break; + case "filter": + if (!filter_used) { + filter_used = true; + filter = entry.getValue().iterator().next(); + } else { + throw new RestconfDocumentedException("Filter parameter can be used only once."); + } + break; + default: + throw new RestconfDocumentedException("Bad parameter used with notifications: " + entry.getKey()); + } + } + if(!startTime_used && stopTime_used){ + throw new RestconfDocumentedException("Stop-time parameter has to be used with start-time parameter."); + } + URI response = null; if (identifier.contains(DATA_SUBSCR)) { - return dataSubs(identifier, uriInfo); + response = dataSubs(identifier, uriInfo, start, stop, filter); } else if (identifier.contains(NOTIFICATION_STREAM)) { - return notifStream(identifier, uriInfo); + response = notifStream(identifier, uriInfo, start, stop, filter); } + + if(response != null){ + // prepare node with value of location + final InstanceIdentifierContext iid = prepareIIDSubsStreamOutput(); + final NormalizedNodeAttrBuilder> builder = ImmutableLeafNodeBuilder + .create().withValue(response.toString()); + builder.withNodeIdentifier( + NodeIdentifier.create(QName.create("subscribe:to:notification", "2016-10-28", "location"))); + + // prepare new header with location + final Map headers = new HashMap<>(); + headers.put("Location", response); + + return new NormalizedNodeContext(iid, builder.build(), headers); + } + final String msg = "Bad type of notification of sal-remote"; LOG.warn(msg); throw new RestconfDocumentedException(msg); } + private Date parseDateFromQueryParam(final Entry> entry) { + final DateAndTime event = new DateAndTime(entry.getValue().iterator().next()); + String numOf_ms = ""; + final String value = event.getValue(); + if (value.contains(".")) { + numOf_ms = numOf_ms + "."; + final int lastChar = value.contains("Z") ? value.indexOf("Z") : (value.contains("+") ? value.indexOf("+") + : (value.contains("-") ? value.indexOf("-") : value.length())); + for (int i = 0; i < (lastChar - value.indexOf(".") - 1); i++) { + numOf_ms = numOf_ms + "S"; + } + } + String zone = ""; + if (!value.contains("Z")) { + zone = zone + "XXX"; + } + final DateFormat dateFormatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss" + numOf_ms + zone); + + try { + return dateFormatter.parse(value.contains("Z") ? value.replace('T', ' ').substring(0, value.indexOf("Z")) + : value.replace('T', ' ')); + } catch (final ParseException e) { + throw new RestconfDocumentedException("Cannot parse of value in date: " + value + e); + } + } + + /** + * @return {@link InstanceIdentifierContext} of location leaf for + * notification + */ + private InstanceIdentifierContext prepareIIDSubsStreamOutput() { + final QName qnameBase = QName.create("subscribe:to:notification", "2016-10-28", "notifi"); + final SchemaContext schemaCtx = ControllerContext.getInstance().getGlobalSchema(); + final DataSchemaNode location = ((ContainerSchemaNode) schemaCtx + .findModuleByNamespaceAndRevision(qnameBase.getNamespace(), qnameBase.getRevision()) + .getDataChildByName(qnameBase)).getDataChildByName(QName.create(qnameBase, "location")); + final List path = new ArrayList<>(); + path.add(NodeIdentifier.create(qnameBase)); + path.add(NodeIdentifier.create(QName.create(qnameBase, "location"))); + + return new InstanceIdentifierContext(YangInstanceIdentifier.create(path), location, null, + schemaCtx); + } + /** * Register notification listener by stream name * @@ -1061,9 +1167,16 @@ public class RestconfImpl implements RestconfService { * - stream name * @param uriInfo * - uriInfo - * @return {@link Response} + * @param stop + * - stop-time of getting notification + * @param start + * - start-time of getting notification + * @param filter + * - indicate wh ich subset of allpossible events are of interest + * @return {@link URI} of location */ - private Response notifStream(final String identifier, final UriInfo uriInfo) { + private URI notifStream(final String identifier, final UriInfo uriInfo, final Date start, final Date stop, + final String filter) { final String streamName = Notificator.createStreamNameFromUri(identifier); if (Strings.isNullOrEmpty(streamName)) { throw new RestconfDocumentedException("Stream name is empty.", ErrorType.PROTOCOL, ErrorTag.INVALID_VALUE); @@ -1076,6 +1189,7 @@ public class RestconfImpl implements RestconfService { for (final NotificationListenerAdapter listener : listeners) { this.broker.registerToListenNotification(listener); + listener.setQueryParams(start, stop, filter); } final UriBuilder uriBuilder = uriInfo.getAbsolutePathBuilder(); @@ -1089,7 +1203,7 @@ public class RestconfImpl implements RestconfService { final UriBuilder uriToWebsocketServerBuilder = uriBuilder.port(notificationPort).scheme("ws"); final URI uriToWebsocketServer = uriToWebsocketServerBuilder.replacePath(streamName).build(); - return Response.status(Status.OK).location(uriToWebsocketServer).build(); + return uriToWebsocketServer; } /** @@ -1099,9 +1213,16 @@ public class RestconfImpl implements RestconfService { * - stream name * @param uriInfo * - uri info - * @return {@link Response} + * @param stop + * - start-time of getting notification + * @param start + * - stop-time of getting notification + * @param filter + * - indicate which subset of all possible events are of interest + * @return {@link URI} of location */ - private Response dataSubs(final String identifier, final UriInfo uriInfo) { + private URI dataSubs(final String identifier, final UriInfo uriInfo, final Date start, final Date stop, + final String filter) { final String streamName = Notificator.createStreamNameFromUri(identifier); if (Strings.isNullOrEmpty(streamName)) { throw new RestconfDocumentedException("Stream name is empty.", ErrorType.PROTOCOL, ErrorTag.INVALID_VALUE); @@ -1111,6 +1232,7 @@ public class RestconfImpl implements RestconfService { if (listener == null) { throw new RestconfDocumentedException("Stream was not found.", ErrorType.PROTOCOL, ErrorTag.UNKNOWN_ELEMENT); } + listener.setQueryParams(start, stop, filter); final Map paramToValues = resolveValuesFromUri(identifier); final LogicalDatastoreType datastore = parserURIEnumParameter(LogicalDatastoreType.class, @@ -1138,7 +1260,7 @@ public class RestconfImpl implements RestconfService { final UriBuilder uriToWebsocketServerBuilder = uriBuilder.port(notificationPort).scheme("ws"); final URI uriToWebsocketServer = uriToWebsocketServerBuilder.replacePath(streamName).build(); - return Response.status(Status.OK).location(uriToWebsocketServer).build(); + return uriToWebsocketServer; } @Override