InstanceIdentifierContext does not take generics
[netconf.git] / restconf / restconf-nb-rfc8040 / src / main / java / org / opendaylight / restconf / nb / rfc8040 / utils / parser / ParserIdentifier.java
index a913a5079fd4ccede7b32c928c8d9dfb0f2433bf..4fc681c6c1a43ed568bac26725aacc78c57eda60 100644 (file)
@@ -26,14 +26,16 @@ import org.opendaylight.mdsal.dom.api.DOMMountPoint;
 import org.opendaylight.mdsal.dom.api.DOMMountPointService;
 import org.opendaylight.mdsal.dom.api.DOMSchemaService;
 import org.opendaylight.mdsal.dom.api.DOMYangTextSourceProvider;
+import org.opendaylight.restconf.common.ErrorTags;
 import org.opendaylight.restconf.common.context.InstanceIdentifierContext;
 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.schema.SchemaExportContext;
 import org.opendaylight.restconf.nb.rfc8040.utils.RestconfConstants;
+import org.opendaylight.yangtools.yang.common.ErrorTag;
+import org.opendaylight.yangtools.yang.common.ErrorType;
 import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.common.Revision;
+import org.opendaylight.yangtools.yang.common.YangNames;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
 import org.opendaylight.yangtools.yang.data.util.DataSchemaContextNode;
 import org.opendaylight.yangtools.yang.data.util.DataSchemaContextTree;
@@ -52,12 +54,11 @@ import org.slf4j.LoggerFactory;
  * Util class for parsing identifier.
  */
 public final class ParserIdentifier {
-
     private static final Logger LOG = LoggerFactory.getLogger(ParserIdentifier.class);
     private static final Splitter MP_SPLITTER = Splitter.on("/" + RestconfConstants.MOUNT);
 
     private ParserIdentifier() {
-        throw new UnsupportedOperationException("Util class.");
+        // Hidden on purpose
     }
 
     /**
@@ -79,7 +80,11 @@ public final class ParserIdentifier {
      *           - mount point service
      * @return {@link InstanceIdentifierContext}
      */
-    public static InstanceIdentifierContext<?> toInstanceIdentifier(final String identifier,
+    // FIXME: NETCONF-631: this method should not be here, it should be a static factory in InstanceIdentifierContext:
+    //
+    //        @NonNull InstanceIdentifierContext forUrl(identifier, schemaContexxt, mountPointService)
+    //
+    public static InstanceIdentifierContext toInstanceIdentifier(final String identifier,
             final EffectiveModelContext schemaContext, final Optional<DOMMountPointService> mountPointService) {
         if (identifier == null || !identifier.contains(RestconfConstants.MOUNT)) {
             return createIIdContext(schemaContext, identifier, null);
@@ -93,7 +98,7 @@ public final class ParserIdentifier {
         final YangInstanceIdentifier mountPath = IdentifierCodec.deserialize(mountPointId, schemaContext);
         final DOMMountPoint mountPoint = mountPointService.get().getMountPoint(mountPath)
                 .orElseThrow(() -> new RestconfDocumentedException("Mount point does not exist.",
-                    ErrorType.PROTOCOL, ErrorTag.RESOURCE_DENIED_TRANSPORT));
+                    ErrorType.PROTOCOL, ErrorTags.RESOURCE_DENIED_TRANSPORT));
 
         final EffectiveModelContext mountSchemaContext = coerceModelContext(mountPoint);
         final String pathId = pathsIt.next().replaceFirst("/", "");
@@ -110,11 +115,10 @@ public final class ParserIdentifier {
      * @return {@link InstanceIdentifierContext}
      * @throws RestconfDocumentedException if the path cannot be resolved
      */
-    private static InstanceIdentifierContext<?> createIIdContext(final EffectiveModelContext schemaContext,
+    private static InstanceIdentifierContext createIIdContext(final EffectiveModelContext schemaContext,
             final String url, final @Nullable DOMMountPoint mountPoint) {
         final YangInstanceIdentifier urlPath = IdentifierCodec.deserialize(url, schemaContext);
-        return new InstanceIdentifierContext<>(urlPath, getPathSchema(schemaContext, urlPath), mountPoint,
-                schemaContext);
+        return new InstanceIdentifierContext(urlPath, getPathSchema(schemaContext, urlPath), mountPoint, schemaContext);
     }
 
     private static SchemaNode getPathSchema(final EffectiveModelContext schemaContext,
@@ -163,18 +167,6 @@ public final class ParserIdentifier {
             ErrorTag.INVALID_VALUE);
     }
 
-    /**
-     * Make {@link String} from {@link YangInstanceIdentifier}.
-     *
-     * @param instanceIdentifier    Instance identifier
-     * @param schemaContext         Schema context
-     * @return                      Yang instance identifier serialized to String
-     */
-    public static String stringFromYangInstanceIdentifier(final YangInstanceIdentifier instanceIdentifier,
-            final EffectiveModelContext schemaContext) {
-        return IdentifierCodec.serialize(instanceIdentifier, schemaContext);
-    }
-
     /**
      * Make a moduleName/Revision pair from identifier.
      *
@@ -182,7 +174,8 @@ public final class ParserIdentifier {
      *             path parameter
      * @return {@link QName}
      */
-    public static Entry<String, Revision> makeQNameFromIdentifier(final String identifier) {
+    @VisibleForTesting
+    static Entry<String, Revision> makeQNameFromIdentifier(final String identifier) {
         // check if more than one slash is not used as path separator
         if (identifier.contains("//")) {
             LOG.debug("URI has bad format. It should be \'moduleName/yyyy-MM-dd\' {}", identifier);
@@ -259,7 +252,7 @@ public final class ParserIdentifier {
 
                 pathBuilder.append(current);
             }
-            final InstanceIdentifierContext<?> point = toInstanceIdentifier(pathBuilder.toString(), schemaContext,
+            final InstanceIdentifierContext point = toInstanceIdentifier(pathBuilder.toString(), schemaContext,
                 Optional.of(domMountPointService));
             final String moduleName = validateAndGetModulName(componentIter);
             final Revision revision = validateAndGetRevision(componentIter);
@@ -269,6 +262,20 @@ public final class ParserIdentifier {
         }
     }
 
+    public static YangInstanceIdentifier parserPatchTarget(final InstanceIdentifierContext context,
+            final String target) {
+        final var schemaContext = context.getSchemaContext();
+        final var urlPath = context.getInstanceIdentifier();
+        final String targetUrl;
+        if (urlPath.isEmpty()) {
+            targetUrl = target.startsWith("/") ? target.substring(1) : target;
+        } else {
+            targetUrl = IdentifierCodec.serialize(urlPath, schemaContext) + target;
+        }
+
+        return toInstanceIdentifier(targetUrl, schemaContext, Optional.empty()).getInstanceIdentifier();
+    }
+
     /**
      * Validation and parsing of revision.
      *
@@ -299,12 +306,12 @@ public final class ParserIdentifier {
         final String name = moduleName.next();
 
         RestconfDocumentedException.throwIf(
-            name.isEmpty() || !ParserConstants.YANG_IDENTIFIER_START.matches(name.charAt(0)),
+            name.isEmpty() || !YangNames.IDENTIFIER_START.matches(name.charAt(0)),
             "Identifier must start with character from set 'a-zA-Z_", ErrorType.PROTOCOL, ErrorTag.INVALID_VALUE);
         RestconfDocumentedException.throwIf(name.toUpperCase(Locale.ROOT).startsWith("XML"),
             "Identifier must NOT start with XML ignore case.", ErrorType.PROTOCOL, ErrorTag.INVALID_VALUE);
         RestconfDocumentedException.throwIf(
-            !ParserConstants.YANG_IDENTIFIER_PART.matchesAllOf(name.substring(1)),
+            YangNames.NOT_IDENTIFIER_PART.matchesAnyOf(name.substring(1)),
             "Supplied name has not expected identifier format.", ErrorType.PROTOCOL, ErrorTag.INVALID_VALUE);
 
         return name;