2 * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
8 package org.opendaylight.restconf.nb.rfc8040.legacy;
10 import static com.google.common.base.Verify.verify;
11 import static java.util.Objects.requireNonNull;
13 import com.google.common.annotations.VisibleForTesting;
14 import com.google.common.collect.ImmutableList;
15 import org.eclipse.jdt.annotation.NonNull;
16 import org.eclipse.jdt.annotation.Nullable;
17 import org.opendaylight.mdsal.dom.api.DOMMountPoint;
18 import org.opendaylight.mdsal.dom.api.DOMMountPointService;
19 import org.opendaylight.mdsal.dom.api.DOMSchemaService;
20 import org.opendaylight.restconf.api.ApiPath;
21 import org.opendaylight.restconf.api.ApiPath.Step;
22 import org.opendaylight.restconf.common.errors.RestconfDocumentedException;
23 import org.opendaylight.restconf.nb.rfc8040.utils.parser.IdentifierCodec;
24 import org.opendaylight.restconf.nb.rfc8040.utils.parser.YangInstanceIdentifierDeserializer;
25 import org.opendaylight.yangtools.yang.common.ErrorTag;
26 import org.opendaylight.yangtools.yang.common.ErrorType;
27 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
28 import org.opendaylight.yangtools.yang.data.util.DataSchemaContextTree;
29 import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
30 import org.opendaylight.yangtools.yang.model.api.SchemaNode;
31 import org.opendaylight.yangtools.yang.model.util.SchemaInferenceStack;
32 import org.opendaylight.yangtools.yang.model.util.SchemaInferenceStack.Inference;
34 public abstract class InstanceIdentifierContext {
35 private static final class Root extends InstanceIdentifierContext {
36 private final @NonNull EffectiveModelContext context;
38 Root(final EffectiveModelContext context, final DOMMountPoint mountPoint) {
39 super(context, mountPoint);
40 this.context = requireNonNull(context);
44 public EffectiveModelContext getSchemaContext() {
49 public YangInstanceIdentifier getInstanceIdentifier() {
50 return YangInstanceIdentifier.of();
54 public Inference inference() {
55 return SchemaInferenceStack.of(context).toInference();
59 private static final class DataPath extends InstanceIdentifierContext {
60 private final @NonNull YangInstanceIdentifier path;
61 private final @NonNull SchemaInferenceStack stack;
63 private DataPath(final SchemaNode schemaNode, final DOMMountPoint mountPoint,
64 final SchemaInferenceStack stack, final YangInstanceIdentifier path) {
65 super(schemaNode, mountPoint);
66 this.stack = requireNonNull(stack);
67 this.path = requireNonNull(path);
70 static @NonNull DataPath of(final EffectiveModelContext context, final YangInstanceIdentifier path,
71 final DOMMountPoint mountPoint) {
72 final var nodeAndStack = DataSchemaContextTree.from(context).enterPath(path).orElseThrow();
73 return new DataPath(nodeAndStack.node().dataSchemaNode(), mountPoint, nodeAndStack.stack(), path);
77 public YangInstanceIdentifier getInstanceIdentifier() {
82 public Inference inference() {
83 return stack.toInference();
87 private static final class WithoutDataPath extends InstanceIdentifierContext {
88 private final @NonNull SchemaInferenceStack stack;
90 private WithoutDataPath(final SchemaNode schemaNode, final DOMMountPoint mountPoint,
91 final SchemaInferenceStack stack) {
92 super(schemaNode, mountPoint);
93 this.stack = requireNonNull(stack);
97 public Inference inference() {
98 return stack.toInference();
102 public @Nullable YangInstanceIdentifier getInstanceIdentifier() {
107 private final @NonNull SchemaNode schemaNode;
108 private final @Nullable DOMMountPoint mountPoint;
110 InstanceIdentifierContext(final SchemaNode schemaNode, final DOMMountPoint mountPoint) {
111 this.schemaNode = requireNonNull(schemaNode);
112 this.mountPoint = mountPoint;
115 // FIXME: NETCONF-773: this recursion should really live in MdsalRestconfServer
116 public static @NonNull InstanceIdentifierContext ofApiPath(final ApiPath path,
117 final EffectiveModelContext modelContext, final DOMMountPointService mountPointService) {
118 final var steps = path.steps();
119 final var limit = steps.size() - 1;
122 DOMMountPoint currentMountPoint = null;
123 var currentModelContext = modelContext;
124 while (prefix <= limit) {
125 final var mount = indexOfMount(steps, prefix, limit);
130 final var mountService = currentMountPoint == null ? mountPointService
131 : currentMountPoint.getService(DOMMountPointService.class).orElse(null);
132 if (mountService == null) {
133 throw new RestconfDocumentedException("Mount point service is not available",
134 ErrorType.APPLICATION, ErrorTag.OPERATION_FAILED);
137 final var mountPath = IdentifierCodec.deserialize(path.subPath(prefix, mount), modelContext);
138 final var userPath = path.subPath(0, mount);
139 final var nextMountPoint = mountService.getMountPoint(mountPath)
140 .orElseThrow(() -> new RestconfDocumentedException("Mount point '" + userPath + "' does not exist",
141 ErrorType.PROTOCOL, ErrorTags.RESOURCE_DENIED_TRANSPORT));
142 final var nextModelContext = nextMountPoint.getService(DOMSchemaService.class)
143 .orElseThrow(() -> new RestconfDocumentedException(
144 "Mount point '" + userPath + "' does not expose DOMSchemaService",
145 ErrorType.PROTOCOL, ErrorTags.RESOURCE_DENIED_TRANSPORT))
147 if (nextModelContext == null) {
148 throw new RestconfDocumentedException("Mount point '" + userPath + "' does not have any models",
149 ErrorType.PROTOCOL, ErrorTags.RESOURCE_DENIED_TRANSPORT);
153 currentModelContext = nextModelContext;
154 currentMountPoint = nextMountPoint;
157 final var result = YangInstanceIdentifierDeserializer.create(currentModelContext, path.subPath(prefix));
158 return InstanceIdentifierContext.ofPath(result.stack, result.node, result.path, currentMountPoint);
161 private static int indexOfMount(final ImmutableList<Step> steps, final int fromIndex, final int limit) {
162 for (int i = fromIndex; i <= limit; ++ i) {
163 final var step = steps.get(i);
164 if ("yang-ext".equals(step.module()) && "mount".equals(step.identifier().getLocalName())) {
171 public static @NonNull InstanceIdentifierContext ofLocalRoot(final EffectiveModelContext context) {
172 return new Root(context, null);
176 public static @NonNull InstanceIdentifierContext ofLocalPath(final EffectiveModelContext context,
177 final YangInstanceIdentifier path) {
178 return DataPath.of(context, path, null);
181 // Invocations of various identifier-less details
182 public static @NonNull InstanceIdentifierContext ofStack(final SchemaInferenceStack stack) {
183 return ofStack(stack, null);
186 // Invocations of various identifier-less details, potentially having a mount point
187 public static @NonNull InstanceIdentifierContext ofStack(final SchemaInferenceStack stack,
188 final @Nullable DOMMountPoint mountPoint) {
189 final SchemaNode schemaNode;
190 if (!stack.isEmpty()) {
191 final var stmt = stack.currentStatement();
192 verify(stmt instanceof SchemaNode, "Unexpected statement %s", stmt);
193 schemaNode = (SchemaNode) stmt;
195 schemaNode = stack.getEffectiveModelContext();
198 return new WithoutDataPath(schemaNode, mountPoint, stack);
201 public static @NonNull InstanceIdentifierContext ofPath(final SchemaInferenceStack stack,
202 final SchemaNode schemaNode, final YangInstanceIdentifier path,
203 final @Nullable DOMMountPoint mountPoint) {
204 return new DataPath(schemaNode, mountPoint, stack, path);
207 public static @NonNull InstanceIdentifierContext ofMountPointRoot(final DOMMountPoint mountPoint,
208 final EffectiveModelContext mountContext) {
209 return new Root(mountContext, requireNonNull(mountPoint));
213 public static @NonNull InstanceIdentifierContext ofMountPointPath(final DOMMountPoint mountPoint,
214 final EffectiveModelContext context, final YangInstanceIdentifier path) {
215 return DataPath.of(context, path, requireNonNull(mountPoint));
218 public final @NonNull SchemaNode getSchemaNode() {
222 public final @Nullable DOMMountPoint getMountPoint() {
226 public @NonNull EffectiveModelContext getSchemaContext() {
227 return inference().getEffectiveModelContext();
230 public abstract @NonNull Inference inference();
232 public abstract @Nullable YangInstanceIdentifier getInstanceIdentifier();