Force subclasses to implement deserializeKeyValue()
[yangtools.git] / codec / yang-data-codec-xml / src / main / java / org / opendaylight / yangtools / yang / data / codec / xml / XMLStreamNormalizedNodeStreamWriter.java
index 3cb9b3865c94053cee2ddf962cc48d75e640fe17..e8f9149dd9119df4765c9c7a558a970a2554f1db 100644 (file)
@@ -9,10 +9,9 @@ package org.opendaylight.yangtools.yang.data.codec.xml;
 
 import static java.util.Objects.requireNonNull;
 
-import com.google.common.collect.ClassToInstanceMap;
-import com.google.common.collect.ImmutableClassToInstanceMap;
 import com.google.common.collect.ImmutableMap;
 import java.io.IOException;
+import java.util.List;
 import java.util.Map.Entry;
 import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
@@ -20,19 +19,19 @@ import javax.xml.stream.XMLStreamException;
 import javax.xml.stream.XMLStreamWriter;
 import javax.xml.transform.dom.DOMSource;
 import org.eclipse.jdt.annotation.NonNull;
-import org.opendaylight.yangtools.rfc7952.data.api.StreamWriterMetadataExtension;
+import org.eclipse.jdt.annotation.Nullable;
 import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.common.YangConstants;
+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.NodeIdentifierWithPredicates;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedAnydata;
 import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter;
-import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriterExtension;
+import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter.MetadataExtension;
 import org.opendaylight.yangtools.yang.data.util.NormalizedNodeStreamWriterStack;
 import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
 import org.opendaylight.yangtools.yang.model.api.EffectiveStatementInference;
-import org.opendaylight.yangtools.yang.model.api.SchemaPath;
 import org.opendaylight.yangtools.yang.model.api.stmt.SchemaNodeIdentifier.Absolute;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -51,15 +50,16 @@ import org.w3c.dom.Node;
  * attributes, which uses the proper namespace, but will not bind to a proper module revision. This caveat will be
  * removed in a future version.
  */
-public abstract class XMLStreamNormalizedNodeStreamWriter<T> implements NormalizedNodeStreamWriter,
-        StreamWriterMetadataExtension {
+public abstract sealed class XMLStreamNormalizedNodeStreamWriter<T>
+        implements NormalizedNodeStreamWriter, MetadataExtension
+        permits SchemaAwareXMLStreamNormalizedNodeStreamWriter, SchemalessXMLStreamNormalizedNodeStreamWriter {
     private static final Logger LOG = LoggerFactory.getLogger(XMLStreamNormalizedNodeStreamWriter.class);
     private static final Set<String> BROKEN_ATTRIBUTES = ConcurrentHashMap.newKeySet();
 
     private final @NonNull StreamWriterFacade facade;
 
-    XMLStreamNormalizedNodeStreamWriter(final XMLStreamWriter writer) {
-        facade = new StreamWriterFacade(writer);
+    XMLStreamNormalizedNodeStreamWriter(final XMLStreamWriter writer, final @Nullable PreferredPrefixes pref) {
+        facade = new StreamWriterFacade(writer, pref);
     }
 
     /**
@@ -71,8 +71,21 @@ public abstract class XMLStreamNormalizedNodeStreamWriter<T> implements Normaliz
      */
     public static @NonNull NormalizedNodeStreamWriter create(final XMLStreamWriter writer,
             final EffectiveModelContext context) {
+        return create(writer, context, false);
+    }
+
+    /**
+     * Create a new writer with the specified context as its root.
+     *
+     * @param writer Output {@link XMLStreamWriter}
+     * @param context Associated {@link EffectiveModelContext}.
+     * @param preferPrefixes prefer prefixes known to {@code context}
+     * @return A new {@link NormalizedNodeStreamWriter}
+     */
+    public static @NonNull NormalizedNodeStreamWriter create(final XMLStreamWriter writer,
+            final EffectiveModelContext context, final boolean preferPrefixes) {
         return new SchemaAwareXMLStreamNormalizedNodeStreamWriter(writer, context,
-            NormalizedNodeStreamWriterStack.of(context));
+            NormalizedNodeStreamWriterStack.of(context), preferPrefixes);
     }
 
     /**
@@ -84,8 +97,21 @@ public abstract class XMLStreamNormalizedNodeStreamWriter<T> implements Normaliz
      */
     public static @NonNull NormalizedNodeStreamWriter create(final XMLStreamWriter writer,
             final EffectiveStatementInference inference) {
+        return create(writer, inference, false);
+    }
+
+    /**
+     * Create a new writer with the specified context and rooted at the specified node.
+     *
+     * @param writer Output {@link XMLStreamWriter}
+     * @param inference root node inference
+     * @param preferPrefixes prefer prefixes known to {@code context}
+     * @return A new {@link NormalizedNodeStreamWriter}
+     */
+    public static @NonNull NormalizedNodeStreamWriter create(final XMLStreamWriter writer,
+            final EffectiveStatementInference inference, final boolean preferPrefixes) {
         return new SchemaAwareXMLStreamNormalizedNodeStreamWriter(writer, inference.getEffectiveModelContext(),
-            NormalizedNodeStreamWriterStack.of(inference));
+            NormalizedNodeStreamWriterStack.of(inference), preferPrefixes);
     }
 
     /**
@@ -97,9 +123,8 @@ public abstract class XMLStreamNormalizedNodeStreamWriter<T> implements Normaliz
      * @return A new {@link NormalizedNodeStreamWriter}
      */
     public static @NonNull NormalizedNodeStreamWriter create(final XMLStreamWriter writer,
-            final EffectiveModelContext context, final SchemaPath path) {
-        return new SchemaAwareXMLStreamNormalizedNodeStreamWriter(writer, context,
-            NormalizedNodeStreamWriterStack.of(context, path));
+            final EffectiveModelContext context, final @Nullable Absolute path) {
+        return create(writer, context, path, false);
     }
 
     /**
@@ -108,12 +133,42 @@ public abstract class XMLStreamNormalizedNodeStreamWriter<T> implements Normaliz
      * @param writer Output {@link XMLStreamWriter}
      * @param context Associated {@link EffectiveModelContext}.
      * @param path path
+     * @param preferPrefixes prefer prefixes known to {@code context}
+     * @return A new {@link NormalizedNodeStreamWriter}
+     */
+    public static @NonNull NormalizedNodeStreamWriter create(final XMLStreamWriter writer,
+            final EffectiveModelContext context, final @Nullable Absolute path, final boolean preferPrefixes) {
+        return path == null ? create(writer, context)
+            : new SchemaAwareXMLStreamNormalizedNodeStreamWriter(writer, context,
+                NormalizedNodeStreamWriterStack.of(context, path), preferPrefixes);
+    }
+
+    /**
+     * Create a new writer with the specified context and rooted in the specified {@link YangInstanceIdentifier}.
+     *
+     * @param writer Output {@link XMLStreamWriter}
+     * @param context Associated {@link EffectiveModelContext}.
+     * @param path path
      * @return A new {@link NormalizedNodeStreamWriter}
      */
     public static @NonNull NormalizedNodeStreamWriter create(final XMLStreamWriter writer,
-            final EffectiveModelContext context, final Absolute path) {
+            final EffectiveModelContext context, final YangInstanceIdentifier path) {
+        return create(writer, context, path, false);
+    }
+
+    /**
+     * Create a new writer with the specified context and rooted in the specified {@link YangInstanceIdentifier}.
+     *
+     * @param writer Output {@link XMLStreamWriter}
+     * @param context Associated {@link EffectiveModelContext}.
+     * @param path path
+     * @param preferPrefixes prefer prefixes known to {@code context}
+     * @return A new {@link NormalizedNodeStreamWriter}
+     */
+    public static @NonNull NormalizedNodeStreamWriter create(final XMLStreamWriter writer,
+            final EffectiveModelContext context, final YangInstanceIdentifier path, final boolean preferPrefixes) {
         return new SchemaAwareXMLStreamNormalizedNodeStreamWriter(writer, context,
-            NormalizedNodeStreamWriterStack.of(context, path));
+            NormalizedNodeStreamWriterStack.of(context, path), preferPrefixes);
     }
 
     /**
@@ -126,8 +181,22 @@ public abstract class XMLStreamNormalizedNodeStreamWriter<T> implements Normaliz
      */
     public static @NonNull NormalizedNodeStreamWriter forInputOf(final XMLStreamWriter writer,
             final EffectiveModelContext context, final Absolute operationPath) {
+        return forInputOf(writer, context, operationPath, false);
+    }
+
+    /**
+     * Create a new writer with the specified context and rooted in the specified operation's input.
+     *
+     * @param writer Output {@link XMLStreamWriter}
+     * @param context Associated {@link EffectiveModelContext}.
+     * @param operationPath Parent operation (RPC or action) path.
+     * @param preferPrefixes prefer prefixes known to {@code context}
+     * @return A new {@link NormalizedNodeStreamWriter}
+     */
+    public static @NonNull NormalizedNodeStreamWriter forInputOf(final XMLStreamWriter writer,
+            final EffectiveModelContext context, final Absolute operationPath, final boolean preferPrefixes) {
         return forOperation(writer, context, operationPath,
-            YangConstants.operationInputQName(operationPath.lastNodeIdentifier().getModule()));
+            YangConstants.operationInputQName(operationPath.lastNodeIdentifier().getModule()), preferPrefixes);
     }
 
     /**
@@ -140,14 +209,30 @@ public abstract class XMLStreamNormalizedNodeStreamWriter<T> implements Normaliz
      */
     public static @NonNull NormalizedNodeStreamWriter forOutputOf(final XMLStreamWriter writer,
             final EffectiveModelContext context, final Absolute operationPath) {
+        return forOutputOf(writer, context, operationPath, false);
+    }
+
+    /**
+     * Create a new writer with the specified context and rooted in the specified operation's output.
+     *
+     * @param writer Output {@link XMLStreamWriter}
+     * @param context Associated {@link EffectiveModelContext}.
+     * @param operationPath Parent operation (RPC or action) path.
+     * @param preferPrefixes prefer prefixes known to {@code context}
+     * @return A new {@link NormalizedNodeStreamWriter}
+     */
+    public static @NonNull NormalizedNodeStreamWriter forOutputOf(final XMLStreamWriter writer,
+            final EffectiveModelContext context, final Absolute operationPath, final boolean preferPrefixes) {
         return forOperation(writer, context, operationPath,
-            YangConstants.operationOutputQName(operationPath.lastNodeIdentifier().getModule()));
+            YangConstants.operationOutputQName(operationPath.lastNodeIdentifier().getModule()),
+            preferPrefixes);
     }
 
     private static @NonNull NormalizedNodeStreamWriter forOperation(final XMLStreamWriter writer,
-            final EffectiveModelContext context, final Absolute operationPath, final QName qname) {
+            final EffectiveModelContext context, final Absolute operationPath, final QName qname,
+            final boolean preferPrefixes) {
         return new SchemaAwareXMLStreamNormalizedNodeStreamWriter(writer, context,
-            NormalizedNodeStreamWriterStack.ofOperation(context, operationPath, qname));
+            NormalizedNodeStreamWriterStack.ofOperation(context, operationPath, qname), preferPrefixes);
     }
 
     /**
@@ -163,8 +248,8 @@ public abstract class XMLStreamNormalizedNodeStreamWriter<T> implements Normaliz
     }
 
     @Override
-    public final ClassToInstanceMap<NormalizedNodeStreamWriterExtension> getExtensions() {
-        return ImmutableClassToInstanceMap.of(StreamWriterMetadataExtension.class, this);
+    public final List<MetadataExtension> supportedExtensions() {
+        return List.of(this);
     }
 
     abstract void startAnydata(NodeIdentifier name);
@@ -291,9 +376,10 @@ public abstract class XMLStreamNormalizedNodeStreamWriter<T> implements Normaliz
                     StreamWriterFacade.warnLegacyAttribute(localName);
                     if (!(value instanceof String)) {
                         if (BROKEN_ATTRIBUTES.add(localName)) {
-                            LOG.warn("Unbound annotation {} does not have a String value, ignoring it. Please fix the "
-                                    + "source of this annotation either by formatting it to a String or removing its "
-                                    + "use", localName, new Throwable("Call stack"));
+                            LOG.warn("""
+                                Unbound annotation {} does not have a String value, ignoring it. Please fix the \
+                                source of this annotation either by formatting it to a String or removing its \
+                                use""", localName, new Throwable("Call stack"));
                         }
                         LOG.debug("Ignoring annotation {} value {}", localName, value);
                     } else {