import static java.util.Objects.requireNonNull;
import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
import java.util.Optional;
+import org.eclipse.jdt.annotation.Nullable;
import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
import org.opendaylight.mdsal.dom.api.DOMRpcResult;
import org.opendaylight.mdsal.dom.spi.DefaultDOMRpcResult;
import org.opendaylight.restconf.common.errors.RestconfError.ErrorTag;
import org.opendaylight.restconf.common.errors.RestconfError.ErrorType;
import org.opendaylight.restconf.common.util.DataChangeScope;
-import org.opendaylight.restconf.nb.rfc8040.rests.utils.ResolveEnumUtil;
import org.opendaylight.restconf.nb.rfc8040.rests.utils.RestconfStreamsConstants;
import org.opendaylight.restconf.nb.rfc8040.streams.listeners.ListenersBroker;
import org.opendaylight.restconf.nb.rfc8040.streams.listeners.NotificationListenerAdapter;
import org.opendaylight.restconf.nb.rfc8040.utils.parser.ParserIdentifier;
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;
+import org.opendaylight.yangtools.yang.common.Revision;
+import org.opendaylight.yangtools.yang.common.XMLNamespace;
import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.AugmentationIdentifier;
import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
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.api.schema.LeafNode;
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.EffectiveModelContext;
*/
final class CreateStreamUtil {
private static final Logger LOG = LoggerFactory.getLogger(CreateStreamUtil.class);
+ private static final QNameModule SAL_REMOTE_AUGMENT = QNameModule.create(
+ XMLNamespace.of("urn:sal:restconf:event:subscription"), Revision.of("2014-07-08"));
+ private static final QName DATASTORE_QNAME =
+ QName.create(SAL_REMOTE_AUGMENT, RestconfStreamsConstants.DATASTORE_PARAM_NAME).intern();
+ private static final QName SCOPE_QNAME =
+ QName.create(SAL_REMOTE_AUGMENT, RestconfStreamsConstants.SCOPE_PARAM_NAME).intern();
+ private static final QName OUTPUT_TYPE_QNAME =
+ QName.create(SAL_REMOTE_AUGMENT, RestconfStreamsConstants.OUTPUT_TYPE_PARAM_NAME).intern();
+ private static final NodeIdentifier DATASTORE_NODEID = NodeIdentifier.create(DATASTORE_QNAME);
+ private static final NodeIdentifier SCOPE_NODEID = NodeIdentifier.create(SCOPE_QNAME);
+ private static final NodeIdentifier OUTPUT_TYPE_NODEID = NodeIdentifier.create(OUTPUT_TYPE_QNAME);
+
+ private static final AugmentationIdentifier SAL_REMOTE_AUG_IDENTIFIER = new AugmentationIdentifier(
+ ImmutableSet.of(SCOPE_QNAME, DATASTORE_QNAME, OUTPUT_TYPE_QNAME));
private CreateStreamUtil() {
throw new UnsupportedOperationException("Utility class");
* @return Parsed {@link NotificationOutputType}.
*/
private static NotificationOutputType prepareOutputType(final ContainerNode data) {
- NotificationOutputType outputType = parseEnum(
- data, NotificationOutputType.class, RestconfStreamsConstants.OUTPUT_TYPE_PARAM_NAME);
- return outputType == null ? NotificationOutputType.XML : outputType;
+ final String outputName = extractStringLeaf(data, OUTPUT_TYPE_NODEID);
+ return outputName != null ? NotificationOutputType.valueOf(outputName) : NotificationOutputType.XML;
}
/**
*/
private static String prepareDataChangeNotifiStreamName(final YangInstanceIdentifier path,
final EffectiveModelContext schemaContext, final ContainerNode data) {
- LogicalDatastoreType datastoreType = parseEnum(
- data, LogicalDatastoreType.class, RestconfStreamsConstants.DATASTORE_PARAM_NAME);
- datastoreType = datastoreType == null ? LogicalDatastoreType.CONFIGURATION : datastoreType;
+ final String datastoreName = extractStringLeaf(data, DATASTORE_NODEID);
+ final LogicalDatastoreType datastoreType = datastoreName != null ? LogicalDatastoreType.valueOf(datastoreName)
+ : LogicalDatastoreType.CONFIGURATION;
- DataChangeScope scope = parseEnum(data, DataChangeScope.class, RestconfStreamsConstants.SCOPE_PARAM_NAME);
- scope = scope == null ? DataChangeScope.BASE : scope;
+ final String scopeName = extractStringLeaf(data, SCOPE_NODEID);
+ // FIXME: this is not really used
+ final DataChangeScope scope = scopeName != null ? DataChangeScope.valueOf(scopeName) : DataChangeScope.BASE;
return RestconfStreamsConstants.DATA_SUBSCRIPTION
+ "/"
return (YangInstanceIdentifier) pathValue;
}
- /**
- * Parsing out of enumeration from RPC create-stream body.
- *
- * @param data Container with stream settings (RPC create-stream).
- * @param clazz Enum type to be parsed out from input container.
- * @param paramName Local name of the enum element.
- * @return Parsed enumeration.
- */
- private static <T> T parseEnum(final ContainerNode data, final Class<T> clazz, final String paramName) {
- final Optional<DataContainerChild> optAugNode = data.findChildByArg(
- RestconfStreamsConstants.SAL_REMOTE_AUG_IDENTIFIER);
- if (optAugNode.isEmpty()) {
- return null;
- }
- final DataContainerChild augNode = optAugNode.get();
- if (!(augNode instanceof AugmentationNode)) {
- return null;
+ private static @Nullable String extractStringLeaf(final ContainerNode data, final NodeIdentifier childName) {
+ final DataContainerChild augNode = data.childByArg(SAL_REMOTE_AUG_IDENTIFIER);
+ if (augNode instanceof AugmentationNode) {
+ final DataContainerChild enumNode = ((AugmentationNode) augNode).childByArg(childName);
+ if (enumNode instanceof LeafNode) {
+ final Object value = enumNode.body();
+ if (value instanceof String) {
+ return (String) value;
+ }
+ }
}
- final Optional<DataContainerChild> enumNode = ((AugmentationNode) augNode).findChildByArg(
- new NodeIdentifier(QName.create(RestconfStreamsConstants.SAL_REMOTE_AUGMENT, paramName)));
- if (enumNode.isEmpty()) {
- return null;
- }
- final Object value = enumNode.get().body();
- if (!(value instanceof String)) {
- return null;
- }
-
- return ResolveEnumUtil.resolveEnum(clazz, (String) value);
+ return null;
}
/**
node = readData(identifier, parameters.getContent(), instanceIdentifier.getInstanceIdentifier(), strategy,
parameters.getWithDefault(), schemaContextRef, uriInfo);
}
+ // FIXME: this is utter craziness, refactor it properly!
if (identifier != null && identifier.contains(STREAM_PATH) && identifier.contains(STREAM_ACCESS_PATH_PART)
&& identifier.contains(STREAM_LOCATION_PATH_PART)) {
final String value = (String) node.body();
*/
@Path("/")
public class RestconfInvokeOperationsServiceImpl implements RestconfInvokeOperationsService {
+ private static final XMLNamespace SAL_REMOTE_NAMESPACE =
+ XMLNamespace.of("urn:opendaylight:params:xml:ns:yang:controller:md:sal:remote");
+
private final DOMRpcService rpcService;
private final SchemaContextHandler schemaContextHandler;
final DOMRpcResult response;
final EffectiveModelContext schemaContextRef;
if (mountPoint == null) {
- if (namespace.equals(RestconfStreamsConstants.SAL_REMOTE_NAMESPACE.getNamespace())) {
+ if (SAL_REMOTE_NAMESPACE.equals(namespace)) {
if (identifier.contains(RestconfStreamsConstants.CREATE_DATA_SUBSCRIPTION)) {
response = CreateStreamUtil.createDataChangeNotifiStream(payload, refSchemaCtx);
} else {
*/
package org.opendaylight.restconf.nb.rfc8040.rests.services.impl;
-import com.google.common.base.Preconditions;
+import static com.google.common.base.Preconditions.checkState;
+
import java.net.URI;
import java.time.Instant;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
import java.time.temporal.ChronoField;
import java.time.temporal.TemporalAccessor;
-import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.opendaylight.restconf.nb.rfc8040.rests.utils.RestconfStreamsConstants;
import org.opendaylight.restconf.nb.rfc8040.streams.Configuration;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.DateAndTime;
+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.LeafNode;
-import org.opendaylight.yangtools.yang.data.api.schema.builder.NormalizedNodeBuilder;
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.DataSchemaNode;
@Path("/")
public class RestconfStreamsSubscriptionServiceImpl implements RestconfStreamsSubscriptionService {
private static final Logger LOG = LoggerFactory.getLogger(RestconfStreamsSubscriptionServiceImpl.class);
+ private static final QName LOCATION_QNAME =
+ QName.create("subscribe:to:notification", "2016-10-28", "location").intern();
+ private static final NodeIdentifier LOCATION_NODEID = NodeIdentifier.create(LOCATION_QNAME);
+ private static final QName NOTIFI_QNAME = QName.create(LOCATION_QNAME, "notifi").intern();
+ private static final YangInstanceIdentifier LOCATION_PATH =
+ YangInstanceIdentifier.create(NodeIdentifier.create(NOTIFI_QNAME), LOCATION_NODEID);
private final SubscribeToStreamUtil streamUtils;
private final HandlersHolder handlersHolder;
final URI response;
if (identifier.contains(RestconfStreamsConstants.DATA_SUBSCRIPTION)) {
- response = streamUtils.subscribeToDataStream(identifier, uriInfo, notificationQueryParams,
- this.handlersHolder);
+ response = streamUtils.subscribeToDataStream(identifier, uriInfo, notificationQueryParams, handlersHolder);
} else if (identifier.contains(RestconfStreamsConstants.NOTIFICATION_STREAM)) {
- response = streamUtils.subscribeToYangStream(identifier, uriInfo, notificationQueryParams,
- this.handlersHolder);
+ response = streamUtils.subscribeToYangStream(identifier, uriInfo, notificationQueryParams, handlersHolder);
} else {
final String msg = "Bad type of notification of sal-remote";
LOG.warn(msg);
throw new RestconfDocumentedException(msg);
}
- // prepare node with value of location
- final InstanceIdentifierContext<?> iid = prepareIIDSubsStreamOutput(this.handlersHolder.getSchemaHandler());
- final NormalizedNodeBuilder<NodeIdentifier, Object, LeafNode<Object>> builder =
- ImmutableLeafNodeBuilder.create().withValue(response.toString());
- builder.withNodeIdentifier(NodeIdentifier.create(RestconfStreamsConstants.LOCATION_QNAME));
-
// prepare new header with location
final Map<String, Object> headers = new HashMap<>();
headers.put("Location", response);
- return new NormalizedNodeContext(iid, builder.build(), headers);
+ // prepare node with value of location
+ return new NormalizedNodeContext(prepareIIDSubsStreamOutput(handlersHolder.getSchemaHandler()),
+ ImmutableLeafNodeBuilder.create()
+ .withNodeIdentifier(LOCATION_NODEID)
+ .withValue(response.toString())
+ .build(), headers);
}
/**
* @return InstanceIdentifier of Location leaf.
*/
private static InstanceIdentifierContext<?> prepareIIDSubsStreamOutput(final SchemaContextHandler schemaHandler) {
- final Optional<Module> module = schemaHandler.get()
- .findModule(RestconfStreamsConstants.NOTIFI_QNAME.getModule());
- Preconditions.checkState(module.isPresent());
- final Optional<DataSchemaNode> notify = module.get()
- .findDataChildByName(RestconfStreamsConstants.NOTIFI_QNAME);
- Preconditions.checkState(notify.isPresent());
- final Optional<DataSchemaNode> location = ((ContainerSchemaNode) notify.get())
- .findDataChildByName(RestconfStreamsConstants.LOCATION_QNAME);
- Preconditions.checkState(location.isPresent());
+ final Optional<Module> module = schemaHandler.get().findModule(NOTIFI_QNAME.getModule());
+ checkState(module.isPresent());
+ final DataSchemaNode notify = module.get().dataChildByName(NOTIFI_QNAME);
+ checkState(notify instanceof ContainerSchemaNode, "Unexpected non-container %s", notify);
+ final DataSchemaNode location = ((ContainerSchemaNode) notify).dataChildByName(LOCATION_QNAME);
+ checkState(location != null, "Missing location");
- final List<PathArgument> path = new ArrayList<>();
- path.add(NodeIdentifier.create(RestconfStreamsConstants.NOTIFI_QNAME));
- path.add(NodeIdentifier.create(RestconfStreamsConstants.LOCATION_QNAME));
- return new InstanceIdentifierContext<SchemaNode>(YangInstanceIdentifier.create(path), location.get(),
- null, schemaHandler.get());
+ return new InstanceIdentifierContext<SchemaNode>(LOCATION_PATH, location, null, schemaHandler.get());
}
/**
package org.opendaylight.restconf.nb.rfc8040.rests.services.impl;
import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Strings.isNullOrEmpty;
-import com.google.common.base.Strings;
import java.net.URI;
import java.util.HashMap;
import java.util.Map;
import org.opendaylight.restconf.common.errors.RestconfDocumentedException;
import org.opendaylight.restconf.common.errors.RestconfError.ErrorTag;
import org.opendaylight.restconf.common.errors.RestconfError.ErrorType;
-import org.opendaylight.restconf.common.util.DataChangeScope;
import org.opendaylight.restconf.nb.rfc8040.Rfc8040;
import org.opendaylight.restconf.nb.rfc8040.rests.services.impl.RestconfStreamsSubscriptionServiceImpl.HandlersHolder;
import org.opendaylight.restconf.nb.rfc8040.rests.services.impl.RestconfStreamsSubscriptionServiceImpl.NotificationQueryParams;
-import org.opendaylight.restconf.nb.rfc8040.rests.utils.ResolveEnumUtil;
import org.opendaylight.restconf.nb.rfc8040.rests.utils.RestconfStreamsConstants;
import org.opendaylight.restconf.nb.rfc8040.streams.listeners.ListenerAdapter;
import org.opendaylight.restconf.nb.rfc8040.streams.listeners.ListenersBroker;
final @NonNull URI subscribeToYangStream(final String identifier, final UriInfo uriInfo,
final NotificationQueryParams notificationQueryParams, final HandlersHolder handlersHolder) {
final String streamName = ListenersBroker.createStreamNameFromUri(identifier);
- if (Strings.isNullOrEmpty(streamName)) {
+ if (isNullOrEmpty(streamName)) {
throw new RestconfDocumentedException("Stream name is empty.", ErrorType.PROTOCOL, ErrorTag.INVALID_VALUE);
}
final URI subscribeToDataStream(final String identifier, final UriInfo uriInfo,
final NotificationQueryParams notificationQueryParams, final HandlersHolder handlersHolder) {
final Map<String, String> mapOfValues = mapValuesFromUri(identifier);
- final LogicalDatastoreType datastoreType = parseURIEnum(
- LogicalDatastoreType.class,
- mapOfValues.get(RestconfStreamsConstants.DATASTORE_PARAM_NAME));
- if (datastoreType == null) {
- final String message = "Stream name doesn't contain datastore value (pattern /datastore=)";
+
+ final String datastoreParam = mapOfValues.get(RestconfStreamsConstants.DATASTORE_PARAM_NAME);
+ if (isNullOrEmpty(datastoreParam)) {
+ final String message = "Stream name does not contain datastore value (pattern /datastore=)";
LOG.debug(message);
throw new RestconfDocumentedException(message, ErrorType.APPLICATION, ErrorTag.MISSING_ATTRIBUTE);
}
- final DataChangeScope scope = parseURIEnum(
- DataChangeScope.class,
- mapOfValues.get(RestconfStreamsConstants.SCOPE_PARAM_NAME));
- if (scope == null) {
- final String message = "Stream name doesn't contains datastore value (pattern /scope=)";
+ // FIXME: this is kept only for compatibility, we are not using this parameter
+ if (isNullOrEmpty(mapOfValues.get(RestconfStreamsConstants.SCOPE_PARAM_NAME))) {
+ final String message = "Stream name does not contain scope value (pattern /scope=)";
LOG.warn(message);
throw new RestconfDocumentedException(message, ErrorType.APPLICATION, ErrorTag.MISSING_ATTRIBUTE);
}
notificationQueryParams.getFilter().orElse(null),
false, notificationQueryParams.isSkipNotificationData());
listener.get().setCloseVars(handlersHolder.getTransactionChainHandler(), handlersHolder.getSchemaHandler());
+
+ final LogicalDatastoreType datastoreType = LogicalDatastoreType.valueOf(datastoreParam);
registration(datastoreType, listener.get(), handlersHolder.getDataBroker());
final URI uri = prepareUriByStreamName(uriInfo, streamName);
notificationService.registerNotificationListener(listener, path);
listener.setRegistration(registration);
}
-
- /**
- * Parse out enumeration from URI.
- *
- * @param clazz Target enumeration type.
- * @param value String representation of enumeration value.
- * @return Parsed enumeration type.
- */
- private static <T> T parseURIEnum(final Class<T> clazz, final String value) {
- if (value == null || value.equals("")) {
- return null;
- }
- return ResolveEnumUtil.resolveEnum(clazz, value);
- }
}
+++ /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.utils;
-
-/**
- * Common util class for resolve enum from String.
- *
- */
-public final class ResolveEnumUtil {
-
- private ResolveEnumUtil() {
- throw new UnsupportedOperationException("Util class");
- }
-
- /**
- * Resolve specific type of enum by value.
- *
- * @param clazz
- * enum
- * @param value
- * string of enum
- * @return - enum
- */
- public static <T> T resolveEnum(final Class<T> clazz, final String value) {
- for (final T t : clazz.getEnumConstants()) {
- if (((Enum<?>) t).name().equals(value)) {
- return t;
- }
- }
- return null;
- }
-}
*/
package org.opendaylight.restconf.nb.rfc8040.rests.utils;
-import com.google.common.collect.ImmutableSet;
-import org.opendaylight.yangtools.yang.common.QName;
-import org.opendaylight.yangtools.yang.common.QNameModule;
-import org.opendaylight.yangtools.yang.common.Revision;
-import org.opendaylight.yangtools.yang.common.XMLNamespace;
-import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.AugmentationIdentifier;
-
/**
* Constants for streams.
*/
public final class RestconfStreamsConstants {
-
- public static final QNameModule SAL_REMOTE_AUGMENT = QNameModule.create(
- XMLNamespace.of("urn:sal:restconf:event:subscription"), Revision.of("2014-07-08"));
- public static final QNameModule SUBSCRIBE_TO_NOTIFICATION = QNameModule.create(
- XMLNamespace.of("subscribe:to:notification"), Revision.of("2016-10-28"));
-
- public static final QName SAL_REMOTE_NAMESPACE = QName.create(
- "urn:opendaylight:params:xml:ns:yang:controller:md:sal:remote",
- "2014-01-14",
- "sal-remote");
-
public static final String STREAM_PATH_PARAM_NAME = "path";
public static final String DATASTORE_PARAM_NAME = "datastore";
public static final String SCOPE_PARAM_NAME = "scope";
public static final String OUTPUT_TYPE_PARAM_NAME = "notification-output-type";
- public static final AugmentationIdentifier SAL_REMOTE_AUG_IDENTIFIER = new AugmentationIdentifier(ImmutableSet.of(
- QName.create(SAL_REMOTE_AUGMENT, SCOPE_PARAM_NAME),
- QName.create(SAL_REMOTE_AUGMENT, DATASTORE_PARAM_NAME),
- QName.create(SAL_REMOTE_AUGMENT, OUTPUT_TYPE_PARAM_NAME)));
-
- public static final QName LOCATION_QNAME = QName.create(SUBSCRIBE_TO_NOTIFICATION, "location");
- public static final QName NOTIFI_QNAME = QName.create(SUBSCRIBE_TO_NOTIFICATION, "notifi");
-
public static final String DS_URI = '/' + DATASTORE_PARAM_NAME + '=';
public static final String SCOPE_URI = '/' + SCOPE_PARAM_NAME + '=';