From: Jakub Toth Date: Wed, 8 Jun 2016 16:37:16 +0000 (+0200) Subject: Bug 5528 - Create stream for DS X-Git-Tag: release/boron~45 X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=commitdiff_plain;h=19dca3cb0bb1bccc68ddbda6e8b7721d4b2023a7;p=netconf.git Bug 5528 - Create stream for DS Change-Id: I2bdd16302aebd70c8929bbedfa99672358a96c91 Signed-off-by: Jakub Toth --- diff --git a/restconf/sal-rest-connector/src/main/java/org/opendaylight/restconf/restful/services/impl/RestconfInvokeOperationsServiceImpl.java b/restconf/sal-rest-connector/src/main/java/org/opendaylight/restconf/restful/services/impl/RestconfInvokeOperationsServiceImpl.java index e31939323d..1322e73ea9 100644 --- a/restconf/sal-rest-connector/src/main/java/org/opendaylight/restconf/restful/services/impl/RestconfInvokeOperationsServiceImpl.java +++ b/restconf/sal-rest-connector/src/main/java/org/opendaylight/restconf/restful/services/impl/RestconfInvokeOperationsServiceImpl.java @@ -7,6 +7,7 @@ */ package org.opendaylight.restconf.restful.services.impl; +import java.net.URI; import javax.ws.rs.core.UriInfo; import org.opendaylight.controller.md.sal.dom.api.DOMMountPoint; import org.opendaylight.controller.md.sal.dom.api.DOMRpcResult; @@ -16,7 +17,9 @@ import org.opendaylight.restconf.common.references.SchemaContextRef; import org.opendaylight.restconf.handlers.RpcServiceHandler; import org.opendaylight.restconf.handlers.SchemaContextHandler; import org.opendaylight.restconf.restful.services.api.RestconfInvokeOperationsService; +import org.opendaylight.restconf.restful.utils.CreateStreamUtil; import org.opendaylight.restconf.restful.utils.RestconfInvokeOperationsUtil; +import org.opendaylight.restconf.restful.utils.RestconfStreamsConstants; import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; import org.opendaylight.yangtools.yang.model.api.RpcDefinition; import org.opendaylight.yangtools.yang.model.api.SchemaPath; @@ -32,17 +35,27 @@ public class RestconfInvokeOperationsServiceImpl implements RestconfInvokeOperat @Override public NormalizedNodeContext invokeRpc(final String identifier, final NormalizedNodeContext payload, final UriInfo uriInfo) { + final SchemaContextRef refSchemaCtx = new SchemaContextRef(this.schemaContextHandler.get()); final SchemaPath schemaPath = payload.getInstanceIdentifierContext().getSchemaNode().getPath(); final DOMMountPoint mountPoint = payload.getInstanceIdentifierContext().getMountPoint(); + final URI namespace = payload.getInstanceIdentifierContext().getSchemaNode().getQName().getNamespace(); DOMRpcResult response; + SchemaContextRef schemaContextRef; + if (mountPoint == null) { - response = RestconfInvokeOperationsUtil.invokeRpc(payload.getData(), schemaPath, this.rpcServiceHandler); + if (namespace.toString().equals(RestconfStreamsConstants.SAL_REMOTE_NAMESPACE)) { + response = CreateStreamUtil.createStream(payload, refSchemaCtx); + } else { + response = RestconfInvokeOperationsUtil.invokeRpc(payload.getData(), schemaPath, + this.rpcServiceHandler); + } schemaContextRef = new SchemaContextRef(this.schemaContextHandler.get()); } else { response = RestconfInvokeOperationsUtil.invokeRpcViaMountPoint(mountPoint, payload.getData(), schemaPath); schemaContextRef = new SchemaContextRef(mountPoint.getSchemaContext()); } + final DOMRpcResult result = RestconfInvokeOperationsUtil.checkResponse(response); RpcDefinition resultNodeSchema = null; diff --git a/restconf/sal-rest-connector/src/main/java/org/opendaylight/restconf/restful/utils/CreateStreamUtil.java b/restconf/sal-rest-connector/src/main/java/org/opendaylight/restconf/restful/utils/CreateStreamUtil.java new file mode 100644 index 0000000000..2a6cd37d2f --- /dev/null +++ b/restconf/sal-rest-connector/src/main/java/org/opendaylight/restconf/restful/utils/CreateStreamUtil.java @@ -0,0 +1,173 @@ +/* + * 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.restful.utils; + +import com.google.common.base.Optional; +import com.google.common.util.concurrent.CheckedFuture; +import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope; +import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; +import org.opendaylight.controller.md.sal.dom.api.DOMRpcResult; +import org.opendaylight.controller.md.sal.dom.spi.DefaultDOMRpcResult; +import org.opendaylight.netconf.sal.restconf.impl.NormalizedNodeContext; +import org.opendaylight.netconf.sal.restconf.impl.RestconfDocumentedException; +import org.opendaylight.netconf.sal.restconf.impl.RestconfError.ErrorTag; +import org.opendaylight.netconf.sal.restconf.impl.RestconfError.ErrorType; +import org.opendaylight.netconf.sal.streams.listeners.Notificator; +import org.opendaylight.restconf.common.references.SchemaContextRef; +import org.opendaylight.restconf.utils.parser.ParserIdentifier; +import org.opendaylight.yangtools.yang.common.QName; +import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; +import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier; +import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument; +import org.opendaylight.yangtools.yang.data.api.schema.AugmentationNode; +import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode; +import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild; +import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes; +import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableContainerNodeBuilder; +import org.opendaylight.yangtools.yang.model.api.SchemaContext; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Util class for streams + * + * + * + */ +public final class CreateStreamUtil { + + private static final Logger LOG = LoggerFactory.getLogger(CreateStreamUtil.class); + + private CreateStreamUtil() { + throw new UnsupportedOperationException("Util class"); + } + + /** + * Create stream with POST operation via RPC + * + * @param payload + * - input of rpc - example in JSON: + * + *
+     *            {@code
+     *            {
+     *                "input": {
+     *                    "path": "/toaster:toaster/toaster:toasterStatus",
+     *                    "sal-remote-augment:datastore": "OPERATIONAL",
+     *                    "sal-remote-augment:scope": "ONE"
+     *                }
+     *            }
+     *            }
+     *            
+ * + * @param refSchemaCtx + * - reference to {@link SchemaContext} - + * {@link SchemaContextRef} + * @return {@link CheckedFuture} with {@link DOMRpcResult} - This mean + * output of RPC - example in JSON: + * + *
+     *         {@code
+     *         {
+     *             "output": {
+     *                 "stream-name": "toaster:toaster/toaster:toasterStatus/datastore=OPERATIONAL/scope=ONE"
+     *             }
+     *         }
+     *         }
+     *         
+ * + */ + public static DOMRpcResult createStream(final NormalizedNodeContext payload, + final SchemaContextRef refSchemaCtx) { + final ContainerNode data = (ContainerNode) payload.getData(); + final QName qname = payload.getInstanceIdentifierContext().getSchemaNode().getQName(); + final YangInstanceIdentifier path = preparePath(payload, data, qname); + final String streamName = prepareStream(path, refSchemaCtx.get(), data); + + final QName outputQname = QName.create(qname, "output"); + final QName streamNameQname = QName.create(qname, "stream-name"); + + final ContainerNode output = ImmutableContainerNodeBuilder.create() + .withNodeIdentifier(new NodeIdentifier(outputQname)) + .withChild(ImmutableNodes.leafNode(streamNameQname, streamName)).build(); + + if (!Notificator.existListenerFor(streamName)) { + Notificator.createListener(path, streamName); + } + + return new DefaultDOMRpcResult(output); + } + + private static String prepareStream(final YangInstanceIdentifier path, final SchemaContext schemaContext, + final ContainerNode data) { + LogicalDatastoreType ds = parseEnum(data, LogicalDatastoreType.class, + RestconfStreamsConstants.DATASTORE_PARAM_NAME); + ds = ds == null ? RestconfStreamsConstants.DEFAULT_DS : ds; + + DataChangeScope scope = parseEnum(data, DataChangeScope.class, RestconfStreamsConstants.SCOPE_PARAM_NAME); + scope = scope == null ? RestconfStreamsConstants.DEFAULT_SCOPE : scope; + + final String streamName = Notificator + .createStreamNameFromUri(ParserIdentifier.stringFromYangInstanceIdentifier(path, schemaContext) + + RestconfStreamsConstants.DS_URI + ds + RestconfStreamsConstants.SCOPE_URI + scope); + if((streamName == null) || streamName.equals("")){ + final String errMsg = "Path is empty or contains value node which is not Container or List build-in type."; + LOG.debug(errMsg + path); + throw new RestconfDocumentedException(errMsg, ErrorType.PROTOCOL, ErrorTag.INVALID_VALUE); + } + return streamName; + } + + private static T parseEnum(final ContainerNode data, final Class clazz, final String paramName) { + final Optional> augNode = data + .getChild(RestconfStreamsConstants.SAL_REMOTE_AUG_IDENTIFIER); + if (!augNode.isPresent() && !(augNode instanceof AugmentationNode)) { + return null; + } + final Optional> enumNode = + ((AugmentationNode) augNode.get()).getChild( + new NodeIdentifier(QName.create(RestconfStreamsConstants.SAL_REMOTE_AUGMENT, paramName))); + if (!enumNode.isPresent()) { + return null; + } + final Object value = enumNode.get().getValue(); + if (!(value instanceof String)) { + return null; + } + + return resolveEnum(clazz, (String) value); + } + + private static T resolveEnum(final Class clazz, final String value) { + for (final T t : clazz.getEnumConstants()) { + if (((Enum) t).name().equals(value)) { + return t; + } + } + return null; + } + + private static YangInstanceIdentifier preparePath(final NormalizedNodeContext payload, final ContainerNode data, + final QName qName) { + final Optional> path = data + .getChild(new YangInstanceIdentifier.NodeIdentifier(QName.create(qName, "path"))); + Object pathValue = null; + if (path.isPresent()) { + pathValue = path.get().getValue(); + } + if (!(pathValue instanceof YangInstanceIdentifier)) { + final String errMsg = "Instance identifier was not normalized correctly "; + LOG.debug(errMsg + qName); + throw new RestconfDocumentedException(errMsg, ErrorType.APPLICATION, ErrorTag.OPERATION_FAILED); + } + return (YangInstanceIdentifier) pathValue; + } +} diff --git a/restconf/sal-rest-connector/src/main/java/org/opendaylight/restconf/restful/utils/RestconfStreamsConstants.java b/restconf/sal-rest-connector/src/main/java/org/opendaylight/restconf/restful/utils/RestconfStreamsConstants.java new file mode 100644 index 0000000000..3cab59b69d --- /dev/null +++ b/restconf/sal-rest-connector/src/main/java/org/opendaylight/restconf/restful/utils/RestconfStreamsConstants.java @@ -0,0 +1,76 @@ +/* + * 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.restful.utils; + +import com.google.common.collect.Sets; +import java.net.URI; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Date; +import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope; +import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; +import org.opendaylight.netconf.sal.restconf.impl.RestconfDocumentedException; +import org.opendaylight.netconf.sal.restconf.impl.RestconfError.ErrorTag; +import org.opendaylight.netconf.sal.restconf.impl.RestconfError.ErrorType; +import org.opendaylight.restconf.utils.RestconfConstants; +import org.opendaylight.restconf.utils.parser.builder.ParserBuilderConstants; +import org.opendaylight.yangtools.yang.common.QName; +import org.opendaylight.yangtools.yang.common.QNameModule; +import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Constants for streams + * + */ +public final class RestconfStreamsConstants { + + private static final Logger LOG = LoggerFactory.getLogger(RestconfStreamsConstants.class); + + public static final String SAL_REMOTE_NAMESPACE = "urn:opendaylight:params:xml:ns:yang:controller:md:sal:remote"; + + public static final String DATASTORE_PARAM_NAME = "datastore"; + + private static final URI NAMESPACE_EVENT_SUBSCRIPTION_AUGMENT = URI.create("urn:sal:restconf:event:subscription"); + + public static final QNameModule SAL_REMOTE_AUGMENT; + + public static final YangInstanceIdentifier.AugmentationIdentifier SAL_REMOTE_AUG_IDENTIFIER; + + public static final DataChangeScope DEFAULT_SCOPE = DataChangeScope.BASE; + + public static final LogicalDatastoreType DEFAULT_DS = LogicalDatastoreType.CONFIGURATION; + + public static final String SCOPE_PARAM_NAME = "scope"; + + public static final String DS_URI = RestconfConstants.SLASH + DATASTORE_PARAM_NAME + + ParserBuilderConstants.Deserializer.EQUAL; + + public static final String SCOPE_URI = RestconfConstants.SLASH + SCOPE_PARAM_NAME + + ParserBuilderConstants.Deserializer.EQUAL; + + static { + Date eventSubscriptionAugRevision; + try { + eventSubscriptionAugRevision = new SimpleDateFormat("yyyy-MM-dd").parse("2014-07-08"); + } catch (final ParseException e) { + final String errMsg = "It wasn't possible to convert revision date of sal-remote-augment to date"; + LOG.debug(errMsg); + throw new RestconfDocumentedException(errMsg, ErrorType.APPLICATION, ErrorTag.OPERATION_FAILED); + } + SAL_REMOTE_AUGMENT = QNameModule.create(NAMESPACE_EVENT_SUBSCRIPTION_AUGMENT, eventSubscriptionAugRevision); + SAL_REMOTE_AUG_IDENTIFIER = new YangInstanceIdentifier.AugmentationIdentifier(Sets + .newHashSet(QName.create(SAL_REMOTE_AUGMENT, "scope"), QName.create(SAL_REMOTE_AUGMENT, "datastore"))); + } + + private RestconfStreamsConstants() { + throw new UnsupportedOperationException("Util class."); + } + +}