BUG-7833: Fix identityref codecs
[yangtools.git] / yang / yang-data-codec-xml / src / main / java / org / opendaylight / yangtools / yang / data / codec / xml / IdentityrefXmlCodec.java
index fbd99587cdef94a1452d29c85a73e2fac0f613e5..378fef581a3af2e5cda0de284ef230ec824e7047 100644 (file)
@@ -8,35 +8,25 @@
 
 package org.opendaylight.yangtools.yang.data.codec.xml;
 
+import com.google.common.base.Preconditions;
 import java.net.URI;
-import java.util.ArrayDeque;
-import java.util.Deque;
-import javax.annotation.Nonnull;
+import java.util.Map.Entry;
 import javax.xml.namespace.NamespaceContext;
 import javax.xml.stream.XMLStreamException;
 import javax.xml.stream.XMLStreamWriter;
 import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.common.QNameModule;
-import org.opendaylight.yangtools.yang.data.util.ModuleStringIdentityrefCodec;
+import org.opendaylight.yangtools.yang.data.util.codec.QNameCodecUtil;
 import org.opendaylight.yangtools.yang.model.api.Module;
 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
 
-final class IdentityrefXmlCodec extends ModuleStringIdentityrefCodec implements XmlCodec<QName> {
-    private static final ThreadLocal<Deque<NamespaceContext>> TL_NSCONTEXT = new ThreadLocal<>();
+final class IdentityrefXmlCodec implements XmlCodec<QName> {
+    private final SchemaContext schemaContext;
+    private final QNameModule parentModule;
 
     IdentityrefXmlCodec(final SchemaContext context, final QNameModule parentModule) {
-        super(context, parentModule);
-    }
-
-    @Override
-    protected Module moduleForPrefix(@Nonnull final String prefix) {
-        if (prefix.isEmpty()) {
-            return context.findModuleByNamespaceAndRevision(parentModuleQname.getNamespace(),
-                    parentModuleQname.getRevision());
-        }
-
-        final String prefixedNS = getNamespaceContext().getNamespaceURI(prefix);
-        return context.findModuleByNamespaceAndRevision(URI.create(prefixedNS), null);
+        this.schemaContext = Preconditions.checkNotNull(context);
+        this.parentModule = Preconditions.checkNotNull(parentModule);
     }
 
     @Override
@@ -46,38 +36,26 @@ final class IdentityrefXmlCodec extends ModuleStringIdentityrefCodec implements
 
     @Override
     public QName parseValue(final NamespaceContext ctx, final String str) {
-        pushNamespaceContext(ctx);
-        try {
-            return deserialize(str);
-        } finally {
-            popNamespaceContext();
-        }
+        return QNameCodecUtil.decodeQName(str, prefix -> {
+            if (prefix.isEmpty()) {
+                return parentModule;
+            }
+
+            final String prefixedNS = ctx.getNamespaceURI(prefix);
+            final Module module = schemaContext.findModuleByNamespaceAndRevision(URI.create(prefixedNS), null);
+            Preconditions.checkArgument(module != null, "Could not find module for namespace %s", prefixedNS);
+            return module.getQNameModule();
+        });
     }
 
     @Override
     public void writeValue(final XMLStreamWriter ctx, final QName value) throws XMLStreamException {
-        // FIXME: this does not work correctly, as we need to populate entries into the namespace context
-        ctx.writeCharacters(serialize(value));
-    }
-
-    private static NamespaceContext getNamespaceContext() {
-        return TL_NSCONTEXT.get().getFirst();
-    }
-
-    private static void popNamespaceContext() {
-        final Deque<NamespaceContext> stack = TL_NSCONTEXT.get();
-        stack.pop();
-        if (stack.isEmpty()) {
-            TL_NSCONTEXT.set(null);
-        }
-    }
+        final RandomPrefix prefixes = new RandomPrefix(ctx.getNamespaceContext());
+        final String str = QNameCodecUtil.encodeQName(value, uri -> prefixes.encodePrefix(uri.getNamespace()));
 
-    private static void pushNamespaceContext(final NamespaceContext context) {
-        Deque<NamespaceContext> stack = TL_NSCONTEXT.get();
-        if (stack == null) {
-            stack = new ArrayDeque<>(1);
-            TL_NSCONTEXT.set(stack);
+        for (Entry<URI, String> e : prefixes.getPrefixes()) {
+            ctx.writeNamespace(e.getValue(), e.getKey().toString());
         }
-        stack.push(context);
+        ctx.writeCharacters(str);
     }
 }