From 744f6e33a9b97ac2b8e86866c02e00464da4dac1 Mon Sep 17 00:00:00 2001 From: Robert Varga Date: Sun, 26 Mar 2017 17:49:03 +0200 Subject: [PATCH] BUG-7983: make XmlCodecFactory a subclass of AbstractCodecFactory AbstractCodecFactory contains everything we need for efficient caching, the only problem we need to solve is binding to NamespaceContext. This patch does exactly that, decoupling XmlCodec from the generic Codec interface, so that serialization and deserialization paths are explicit. This flushes out the fact that the codecs are not used in the egress path at all and rely on TypeDefinitionAwareCodec instead. That deficiency will be fixed in a subsequent patch. Change-Id: I0bdf8af673893f2dc4fcc8842b64f9bed1bc5236 Signed-off-by: Robert Varga --- .../yang/data/codec/gson/UnionJSONCodec.java | 2 +- .../yang/data/codec/xml/AbstractXmlCodec.java | 44 +---- .../yang/data/codec/xml/BooleanXmlCodec.java | 13 +- ...{XmlEmptyCodec.java => EmptyXmlCodec.java} | 15 +- .../data/codec/xml/IdentityrefXmlCodec.java | 89 +++++++++ .../yang/data/codec/xml/NullXmlCodec.java | 41 ++++ .../yang/data/codec/xml/NumberXmlCodec.java | 15 +- .../yang/data/codec/xml/QuotedXmlCodec.java | 8 +- .../yang/data/codec/xml/UnionXmlCodec.java | 111 +++++++++++ .../yang/data/codec/xml/XmlCodec.java | 7 +- .../yang/data/codec/xml/XmlCodecFactory.java | 178 +++++++----------- .../yang/data/codec/xml/XmlParserStream.java | 4 +- .../codec/xml/XmlStringIdentityrefCodec.java | 54 ------ .../xml/XmlStringInstanceIdentifierCodec.java | 56 ++++-- .../data/codec/xml/XmlStringUnionCodec.java | 46 ----- 15 files changed, 392 insertions(+), 291 deletions(-) rename yang/yang-data-codec-xml/src/main/java/org/opendaylight/yangtools/yang/data/codec/xml/{XmlEmptyCodec.java => EmptyXmlCodec.java} (61%) create mode 100644 yang/yang-data-codec-xml/src/main/java/org/opendaylight/yangtools/yang/data/codec/xml/IdentityrefXmlCodec.java create mode 100644 yang/yang-data-codec-xml/src/main/java/org/opendaylight/yangtools/yang/data/codec/xml/NullXmlCodec.java create mode 100644 yang/yang-data-codec-xml/src/main/java/org/opendaylight/yangtools/yang/data/codec/xml/UnionXmlCodec.java delete mode 100644 yang/yang-data-codec-xml/src/main/java/org/opendaylight/yangtools/yang/data/codec/xml/XmlStringIdentityrefCodec.java delete mode 100644 yang/yang-data-codec-xml/src/main/java/org/opendaylight/yangtools/yang/data/codec/xml/XmlStringUnionCodec.java diff --git a/yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/UnionJSONCodec.java b/yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/UnionJSONCodec.java index 103010a9e6..0ef7cda192 100644 --- a/yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/UnionJSONCodec.java +++ b/yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/UnionJSONCodec.java @@ -90,7 +90,7 @@ abstract class UnionJSONCodec implements JSONCodec { return getDataClass().cast(ret); } - throw new IllegalArgumentException("Input '" + input +"' did not match any codecs"); + throw new IllegalArgumentException("Invalid value \"" + input + "\" for union type."); } @Override diff --git a/yang/yang-data-codec-xml/src/main/java/org/opendaylight/yangtools/yang/data/codec/xml/AbstractXmlCodec.java b/yang/yang-data-codec-xml/src/main/java/org/opendaylight/yangtools/yang/data/codec/xml/AbstractXmlCodec.java index 2568cf6f31..78e30d679c 100644 --- a/yang/yang-data-codec-xml/src/main/java/org/opendaylight/yangtools/yang/data/codec/xml/AbstractXmlCodec.java +++ b/yang/yang-data-codec-xml/src/main/java/org/opendaylight/yangtools/yang/data/codec/xml/AbstractXmlCodec.java @@ -9,17 +9,8 @@ package org.opendaylight.yangtools.yang.data.codec.xml; import com.google.common.base.Preconditions; -import org.opendaylight.yangtools.concepts.Codec; -import org.opendaylight.yangtools.yang.data.api.codec.BooleanCodec; -import org.opendaylight.yangtools.yang.data.api.codec.DecimalCodec; -import org.opendaylight.yangtools.yang.data.api.codec.Int16Codec; -import org.opendaylight.yangtools.yang.data.api.codec.Int32Codec; -import org.opendaylight.yangtools.yang.data.api.codec.Int64Codec; -import org.opendaylight.yangtools.yang.data.api.codec.Int8Codec; -import org.opendaylight.yangtools.yang.data.api.codec.Uint16Codec; -import org.opendaylight.yangtools.yang.data.api.codec.Uint32Codec; -import org.opendaylight.yangtools.yang.data.api.codec.Uint64Codec; -import org.opendaylight.yangtools.yang.data.api.codec.Uint8Codec; +import javax.xml.namespace.NamespaceContext; +import org.opendaylight.yangtools.yang.data.impl.codec.DataStringCodec; import org.opendaylight.yangtools.yang.data.impl.codec.TypeDefinitionAwareCodec; /** @@ -29,38 +20,23 @@ import org.opendaylight.yangtools.yang.data.impl.codec.TypeDefinitionAwareCodec; */ abstract class AbstractXmlCodec implements XmlCodec { - private final Codec codec; + private final DataStringCodec codec; - protected AbstractXmlCodec(final Codec codec) { + protected AbstractXmlCodec(final DataStringCodec codec) { this.codec = Preconditions.checkNotNull(codec); } - /** - * Create a proper XmlCodec based on the underlying codec type - * @param codec underlying codec - * @return An XmlCodec instance - */ - public static XmlCodec create(final Codec codec) { - if (codec instanceof BooleanCodec) { - return new BooleanXmlCodec((BooleanCodec) codec); - } else if (codec instanceof DecimalCodec || codec instanceof Int8Codec - || codec instanceof Int16Codec || codec instanceof Int32Codec - || codec instanceof Int64Codec || codec instanceof Uint8Codec - || codec instanceof Uint16Codec || codec instanceof Uint32Codec - || codec instanceof Uint64Codec) { - return new NumberXmlCodec(codec); - } else { - return new QuotedXmlCodec(codec); - } + @Override + public final Class getDataClass() { + return codec.getInputClass(); } @Override - public final T deserialize(final String input) { - return codec.deserialize(input); + public final T deserializeFromString(final NamespaceContext namespaceContext, final String value) { + return codec.deserialize(value); } - @Override - public final String serialize(final T input) { + final String serialize(final T input) { return codec.serialize(input); } } diff --git a/yang/yang-data-codec-xml/src/main/java/org/opendaylight/yangtools/yang/data/codec/xml/BooleanXmlCodec.java b/yang/yang-data-codec-xml/src/main/java/org/opendaylight/yangtools/yang/data/codec/xml/BooleanXmlCodec.java index b83df131bc..14b1404be6 100644 --- a/yang/yang-data-codec-xml/src/main/java/org/opendaylight/yangtools/yang/data/codec/xml/BooleanXmlCodec.java +++ b/yang/yang-data-codec-xml/src/main/java/org/opendaylight/yangtools/yang/data/codec/xml/BooleanXmlCodec.java @@ -10,22 +10,15 @@ package org.opendaylight.yangtools.yang.data.codec.xml; import javax.xml.stream.XMLStreamException; import javax.xml.stream.XMLStreamWriter; -import org.opendaylight.yangtools.concepts.Codec; +import org.opendaylight.yangtools.yang.data.impl.codec.DataStringCodec; final class BooleanXmlCodec extends AbstractXmlCodec { - - BooleanXmlCodec(final Codec codec) { + BooleanXmlCodec(final DataStringCodec codec) { super(codec); } - /** - * Serialize specified value with specified XMLStreamWriter. - * - * @param writer XMLStreamWriter - * @param value value which will be serialized to the writer - */ @Override - public void serializeToWriter(XMLStreamWriter writer, Boolean value) throws XMLStreamException { + public void serializeToWriter(final XMLStreamWriter writer, final Boolean value) throws XMLStreamException { writer.writeCharacters(String.valueOf(value)); } } diff --git a/yang/yang-data-codec-xml/src/main/java/org/opendaylight/yangtools/yang/data/codec/xml/XmlEmptyCodec.java b/yang/yang-data-codec-xml/src/main/java/org/opendaylight/yangtools/yang/data/codec/xml/EmptyXmlCodec.java similarity index 61% rename from yang/yang-data-codec-xml/src/main/java/org/opendaylight/yangtools/yang/data/codec/xml/XmlEmptyCodec.java rename to yang/yang-data-codec-xml/src/main/java/org/opendaylight/yangtools/yang/data/codec/xml/EmptyXmlCodec.java index 1d7abc628f..626626a4e8 100644 --- a/yang/yang-data-codec-xml/src/main/java/org/opendaylight/yangtools/yang/data/codec/xml/XmlEmptyCodec.java +++ b/yang/yang-data-codec-xml/src/main/java/org/opendaylight/yangtools/yang/data/codec/xml/EmptyXmlCodec.java @@ -8,29 +8,30 @@ package org.opendaylight.yangtools.yang.data.codec.xml; +import javax.xml.namespace.NamespaceContext; import javax.xml.stream.XMLStreamException; import javax.xml.stream.XMLStreamWriter; -final class XmlEmptyCodec implements XmlCodec { +final class EmptyXmlCodec implements XmlCodec { - static final XmlEmptyCodec INSTANCE = new XmlEmptyCodec(); + static final EmptyXmlCodec INSTANCE = new EmptyXmlCodec(); - private XmlEmptyCodec() { + private EmptyXmlCodec() { } @Override - public Object deserialize(final String input) { - return null; + public Class getDataClass() { + return Void.class; } @Override - public String serialize(final Object input) { + public Void deserializeFromString(final NamespaceContext namespaceContext, final String value) { return null; } @Override - public void serializeToWriter(final XMLStreamWriter writer, final Object value) throws XMLStreamException { + public void serializeToWriter(final XMLStreamWriter writer, final Void value) throws XMLStreamException { writer.writeCharacters(""); } } diff --git a/yang/yang-data-codec-xml/src/main/java/org/opendaylight/yangtools/yang/data/codec/xml/IdentityrefXmlCodec.java b/yang/yang-data-codec-xml/src/main/java/org/opendaylight/yangtools/yang/data/codec/xml/IdentityrefXmlCodec.java new file mode 100644 index 0000000000..21df404f24 --- /dev/null +++ b/yang/yang-data-codec-xml/src/main/java/org/opendaylight/yangtools/yang/data/codec/xml/IdentityrefXmlCodec.java @@ -0,0 +1,89 @@ +/* + * 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.yangtools.yang.data.codec.xml; + +import java.net.URI; +import java.util.ArrayDeque; +import java.util.Deque; +import javax.annotation.Nonnull; +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.model.api.Module; +import org.opendaylight.yangtools.yang.model.api.SchemaContext; + +final class IdentityrefXmlCodec extends ModuleStringIdentityrefCodec implements XmlCodec { + private static final ThreadLocal> TL_NSCONTEXT = new ThreadLocal<>(); + + 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); + } + + @Override + public Class getDataClass() { + return QName.class; + } + + /** + * Serialize QName with specified XMLStreamWriter. + * + * @param writer XMLStreamWriter + * @param value QName + */ + @Override + public void serializeToWriter(final XMLStreamWriter writer, final QName value) throws XMLStreamException { + // FIXME: this does not work correctly, as we need to populate entries into the namespace context + writer.writeCharacters(serialize(value)); + } + + @Override + public QName deserializeFromString(final NamespaceContext namespaceContext, final String value) { + pushNamespaceContext(namespaceContext); + try { + return deserialize(value); + } finally { + popNamespaceContext(); + } + } + + private static NamespaceContext getNamespaceContext() { + return TL_NSCONTEXT.get().getFirst(); + } + + private static void popNamespaceContext() { + final Deque stack = TL_NSCONTEXT.get(); + stack.pop(); + if (stack.isEmpty()) { + TL_NSCONTEXT.set(null); + } + } + + private static void pushNamespaceContext(final NamespaceContext context) { + Deque stack = TL_NSCONTEXT.get(); + if (stack == null) { + stack = new ArrayDeque<>(1); + TL_NSCONTEXT.set(stack); + } + stack.push(context); + } +} diff --git a/yang/yang-data-codec-xml/src/main/java/org/opendaylight/yangtools/yang/data/codec/xml/NullXmlCodec.java b/yang/yang-data-codec-xml/src/main/java/org/opendaylight/yangtools/yang/data/codec/xml/NullXmlCodec.java new file mode 100644 index 0000000000..5abad0bd01 --- /dev/null +++ b/yang/yang-data-codec-xml/src/main/java/org/opendaylight/yangtools/yang/data/codec/xml/NullXmlCodec.java @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2017 Pantheon Technologies, s.r.o. 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.yangtools.yang.data.codec.xml; + +import javax.xml.namespace.NamespaceContext; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamWriter; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +final class NullXmlCodec implements XmlCodec { + static final NullXmlCodec INSTANCE = new NullXmlCodec(); + private static final Logger LOG = LoggerFactory.getLogger(NullXmlCodec.class); + + private NullXmlCodec() { + + } + + @Override + public Class getDataClass() { + return Object.class; + } + + @Override + public void serializeToWriter(final XMLStreamWriter writer, final Object value) throws XMLStreamException { + // NOOP since codec is unkwown. + LOG.warn("Call of the serializeToWriter method on null codec. No operation performed."); + } + + @Override + public Object deserializeFromString(final NamespaceContext namespaceContext, final String value) { + LOG.warn("Call of the deserializeString method on null codec. No operation performed."); + return null; + } + +} diff --git a/yang/yang-data-codec-xml/src/main/java/org/opendaylight/yangtools/yang/data/codec/xml/NumberXmlCodec.java b/yang/yang-data-codec-xml/src/main/java/org/opendaylight/yangtools/yang/data/codec/xml/NumberXmlCodec.java index 3343832edd..161ae8afec 100644 --- a/yang/yang-data-codec-xml/src/main/java/org/opendaylight/yangtools/yang/data/codec/xml/NumberXmlCodec.java +++ b/yang/yang-data-codec-xml/src/main/java/org/opendaylight/yangtools/yang/data/codec/xml/NumberXmlCodec.java @@ -10,22 +10,15 @@ package org.opendaylight.yangtools.yang.data.codec.xml; import javax.xml.stream.XMLStreamException; import javax.xml.stream.XMLStreamWriter; -import org.opendaylight.yangtools.concepts.Codec; +import org.opendaylight.yangtools.yang.data.impl.codec.DataStringCodec; -final class NumberXmlCodec extends AbstractXmlCodec{ - - NumberXmlCodec(final Codec codec) { +final class NumberXmlCodec extends AbstractXmlCodec { + NumberXmlCodec(final DataStringCodec codec) { super(codec); } - /** - * Serialize specified value with specified XMLStreamWriter. - * - * @param writer XMLStreamWriter - * @param value value which will be serialized to the writer - */ @Override - public void serializeToWriter(XMLStreamWriter writer, T value) throws XMLStreamException { + public void serializeToWriter(final XMLStreamWriter writer, final T value) throws XMLStreamException { writer.writeCharacters(String.valueOf(value)); } } diff --git a/yang/yang-data-codec-xml/src/main/java/org/opendaylight/yangtools/yang/data/codec/xml/QuotedXmlCodec.java b/yang/yang-data-codec-xml/src/main/java/org/opendaylight/yangtools/yang/data/codec/xml/QuotedXmlCodec.java index 200094bf3f..3d1002661b 100644 --- a/yang/yang-data-codec-xml/src/main/java/org/opendaylight/yangtools/yang/data/codec/xml/QuotedXmlCodec.java +++ b/yang/yang-data-codec-xml/src/main/java/org/opendaylight/yangtools/yang/data/codec/xml/QuotedXmlCodec.java @@ -10,11 +10,10 @@ package org.opendaylight.yangtools.yang.data.codec.xml; import javax.xml.stream.XMLStreamException; import javax.xml.stream.XMLStreamWriter; -import org.opendaylight.yangtools.concepts.Codec; +import org.opendaylight.yangtools.yang.data.impl.codec.DataStringCodec; final class QuotedXmlCodec extends AbstractXmlCodec { - - QuotedXmlCodec(final Codec codec) { + QuotedXmlCodec(final DataStringCodec codec) { super(codec); } @@ -25,8 +24,7 @@ final class QuotedXmlCodec extends AbstractXmlCodec { * @param value value which will be serialized to the writer */ @Override - public void serializeToWriter(XMLStreamWriter writer, T value) throws XMLStreamException { + public void serializeToWriter(final XMLStreamWriter writer, final T value) throws XMLStreamException { writer.writeCharacters(serialize(value)); } - } diff --git a/yang/yang-data-codec-xml/src/main/java/org/opendaylight/yangtools/yang/data/codec/xml/UnionXmlCodec.java b/yang/yang-data-codec-xml/src/main/java/org/opendaylight/yangtools/yang/data/codec/xml/UnionXmlCodec.java new file mode 100644 index 0000000000..e244617fae --- /dev/null +++ b/yang/yang-data-codec-xml/src/main/java/org/opendaylight/yangtools/yang/data/codec/xml/UnionXmlCodec.java @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2016 Intel Corporation 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.yangtools.yang.data.codec.xml; + +import com.google.common.base.Preconditions; +import com.google.common.base.Verify; +import com.google.common.collect.ImmutableList; +import java.util.Iterator; +import java.util.List; +import javax.xml.namespace.NamespaceContext; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamWriter; +import org.opendaylight.yangtools.yang.model.api.type.UnionTypeDefinition; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +abstract class UnionXmlCodec implements XmlCodec { + private static final class Diverse extends UnionXmlCodec { + Diverse(final List> codecs) { + super(codecs); + } + + @Override + public Class getDataClass() { + return Object.class; + } + } + + private static final class SingleType extends UnionXmlCodec { + private final Class dataClass; + + SingleType(final Class dataClass, final List> codecs) { + super(codecs); + this.dataClass = Preconditions.checkNotNull(dataClass); + } + + @Override + public Class getDataClass() { + return dataClass; + } + } + + private static final Logger LOG = LoggerFactory.getLogger(UnionXmlCodec.class); + + private final List> codecs; + + UnionXmlCodec(final List> codecs) { + this.codecs = ImmutableList.copyOf(codecs); + } + + static UnionXmlCodec create(final UnionTypeDefinition type, final List> codecs) { + final Iterator> it = codecs.iterator(); + Verify.verify(it.hasNext(), "Union %s has no subtypes", type); + + Class dataClass = it.next().getDataClass(); + while (it.hasNext()) { + final Class next = it.next().getDataClass(); + if (!dataClass.equals(next)) { + LOG.debug("Type {} has diverse data classes: {} and {}", type, dataClass, next); + return new Diverse(codecs); + } + } + + LOG.debug("Type {} has single data class {}", type, dataClass); + return new SingleType<>(dataClass, codecs); + } + + @Override + public final T deserializeFromString(final NamespaceContext namespaceContext, final String input) { + for (XmlCodec codec : codecs) { + final Object ret; + try { + ret = codec.deserializeFromString(namespaceContext, input); + } catch (RuntimeException e) { + LOG.debug("Codec {} did not accept input '{}'", codec, input, e); + continue; + } + + return getDataClass().cast(ret); + } + + throw new IllegalArgumentException("Invalid value \"" + input + "\" for union type."); + } + + @Override + public void serializeToWriter(final XMLStreamWriter writer, final Object value) throws XMLStreamException { + for (XmlCodec codec : codecs) { + if (!codec.getDataClass().isInstance(value)) { + LOG.debug("Codec {} cannot accept input {}, skipping it", codec, value); + continue; + } + + @SuppressWarnings("unchecked") + final XmlCodec objCodec = (XmlCodec) codec; + try { + objCodec.serializeToWriter(writer, value); + return; + } catch (RuntimeException e) { + LOG.debug("Codec {} failed to serialize {}", codec, value, e); + } + } + + throw new IllegalArgumentException("No codecs could serialize" + value); + } +} diff --git a/yang/yang-data-codec-xml/src/main/java/org/opendaylight/yangtools/yang/data/codec/xml/XmlCodec.java b/yang/yang-data-codec-xml/src/main/java/org/opendaylight/yangtools/yang/data/codec/xml/XmlCodec.java index d8307aec56..93ee13e782 100644 --- a/yang/yang-data-codec-xml/src/main/java/org/opendaylight/yangtools/yang/data/codec/xml/XmlCodec.java +++ b/yang/yang-data-codec-xml/src/main/java/org/opendaylight/yangtools/yang/data/codec/xml/XmlCodec.java @@ -8,11 +8,14 @@ package org.opendaylight.yangtools.yang.data.codec.xml; +import javax.xml.namespace.NamespaceContext; import javax.xml.stream.XMLStreamException; import javax.xml.stream.XMLStreamWriter; -import org.opendaylight.yangtools.concepts.Codec; -interface XmlCodec extends Codec { +interface XmlCodec { + Class getDataClass(); + + T deserializeFromString(NamespaceContext namespaceContext, String value); /** * Serialize specified value with specified XMLStreamWriter. diff --git a/yang/yang-data-codec-xml/src/main/java/org/opendaylight/yangtools/yang/data/codec/xml/XmlCodecFactory.java b/yang/yang-data-codec-xml/src/main/java/org/opendaylight/yangtools/yang/data/codec/xml/XmlCodecFactory.java index 726f013912..ee1ec83d87 100644 --- a/yang/yang-data-codec-xml/src/main/java/org/opendaylight/yangtools/yang/data/codec/xml/XmlCodecFactory.java +++ b/yang/yang-data-codec-xml/src/main/java/org/opendaylight/yangtools/yang/data/codec/xml/XmlCodecFactory.java @@ -9,72 +9,39 @@ package org.opendaylight.yangtools.yang.data.codec.xml; import com.google.common.annotations.Beta; -import com.google.common.base.Preconditions; -import com.google.common.base.Verify; -import com.google.common.cache.CacheBuilder; -import com.google.common.cache.CacheLoader; -import com.google.common.cache.LoadingCache; -import java.util.AbstractMap.SimpleImmutableEntry; -import java.util.Map.Entry; -import javax.annotation.Nonnull; +import java.util.List; import javax.annotation.concurrent.ThreadSafe; -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.data.api.YangInstanceIdentifier; -import org.opendaylight.yangtools.yang.data.impl.codec.TypeDefinitionAwareCodec; -import org.opendaylight.yangtools.yang.model.api.DataSchemaNode; +import org.opendaylight.yangtools.yang.common.QNameModule; +import org.opendaylight.yangtools.yang.data.impl.codec.AbstractIntegerStringCodec; +import org.opendaylight.yangtools.yang.data.impl.codec.BinaryStringCodec; +import org.opendaylight.yangtools.yang.data.impl.codec.BitsStringCodec; +import org.opendaylight.yangtools.yang.data.impl.codec.BooleanStringCodec; +import org.opendaylight.yangtools.yang.data.impl.codec.DecimalStringCodec; +import org.opendaylight.yangtools.yang.data.impl.codec.EnumStringCodec; +import org.opendaylight.yangtools.yang.data.impl.codec.StringStringCodec; +import org.opendaylight.yangtools.yang.data.util.codec.AbstractCodecFactory; +import org.opendaylight.yangtools.yang.data.util.codec.SharedCodecCache; import org.opendaylight.yangtools.yang.model.api.SchemaContext; -import org.opendaylight.yangtools.yang.model.api.TypeDefinition; -import org.opendaylight.yangtools.yang.model.api.TypedSchemaNode; +import org.opendaylight.yangtools.yang.model.api.type.BinaryTypeDefinition; +import org.opendaylight.yangtools.yang.model.api.type.BitsTypeDefinition; +import org.opendaylight.yangtools.yang.model.api.type.BooleanTypeDefinition; +import org.opendaylight.yangtools.yang.model.api.type.DecimalTypeDefinition; import org.opendaylight.yangtools.yang.model.api.type.EmptyTypeDefinition; +import org.opendaylight.yangtools.yang.model.api.type.EnumTypeDefinition; import org.opendaylight.yangtools.yang.model.api.type.IdentityrefTypeDefinition; import org.opendaylight.yangtools.yang.model.api.type.InstanceIdentifierTypeDefinition; -import org.opendaylight.yangtools.yang.model.api.type.LeafrefTypeDefinition; +import org.opendaylight.yangtools.yang.model.api.type.IntegerTypeDefinition; +import org.opendaylight.yangtools.yang.model.api.type.StringTypeDefinition; import org.opendaylight.yangtools.yang.model.api.type.UnionTypeDefinition; -import org.opendaylight.yangtools.yang.model.util.SchemaContextUtil; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import org.opendaylight.yangtools.yang.model.api.type.UnknownTypeDefinition; +import org.opendaylight.yangtools.yang.model.api.type.UnsignedIntegerTypeDefinition; @Beta @ThreadSafe -public final class XmlCodecFactory { - - private static final Logger LOG = LoggerFactory.getLogger(XmlCodecFactory.class); - private static final XmlCodec NULL_CODEC = new XmlCodec() { - @Override - public Object deserialize(final String input) { - return null; - } - - @Override - public String serialize(final Object input) { - return null; - } - - @Override - public void serializeToWriter(final XMLStreamWriter writer, final Object value) throws XMLStreamException { - // NOOP since codec is unkwown. - LOG.warn("Call of the serializeToWriter method on XmlCodecFactory.NULL_CODEC object. No operation " + - "performed."); - } - }; - - private final LoadingCache, XmlCodec> codecs = CacheBuilder.newBuilder() - .softValues().build(new CacheLoader, XmlCodec>() { - @Override - public XmlCodec load(@Nonnull final Entry pair) { - final TypedSchemaNode schemaNode = pair.getKey(); - final TypeDefinition type = schemaNode.getType(); - return createCodec(schemaNode, type, pair.getValue()); - } - }); - - private final SchemaContext schemaContext; +public final class XmlCodecFactory extends AbstractCodecFactory> { private XmlCodecFactory(final SchemaContext context) { - this.schemaContext = Preconditions.checkNotNull(context); + super(context, new SharedCodecCache<>()); } /** @@ -87,71 +54,68 @@ public final class XmlCodecFactory { return new XmlCodecFactory(context); } - private XmlCodec createCodec(final DataSchemaNode key, final TypeDefinition type, - final NamespaceContext namespaceContext) { - if (type instanceof LeafrefTypeDefinition) { - return createReferencedTypeCodec(key, (LeafrefTypeDefinition) type, namespaceContext); - } else if (type instanceof IdentityrefTypeDefinition) { - return createIdentityrefTypeCodec(key, namespaceContext); - } else if (type instanceof UnionTypeDefinition) { - return createUnionTypeCodec(key, (UnionTypeDefinition)type, namespaceContext); - } - return createFromSimpleType(key, type, namespaceContext); + @Override + protected XmlCodec binaryCodec(final BinaryTypeDefinition type) { + return new QuotedXmlCodec<>(BinaryStringCodec.from(type)); } - private XmlCodec createReferencedTypeCodec(final DataSchemaNode schema, final LeafrefTypeDefinition type, - final NamespaceContext namespaceContext) { - // FIXME: Verify if this does indeed support leafref of leafref - final TypeDefinition referencedType = - SchemaContextUtil.getBaseTypeForLeafRef(type, getSchemaContext(), schema); - Verify.verifyNotNull(referencedType, "Unable to find base type for leafref node '%s'.", schema.getPath()); - return createCodec(schema, referencedType, namespaceContext); + @Override + protected XmlCodec booleanCodec(final BooleanTypeDefinition type) { + return new BooleanXmlCodec(BooleanStringCodec.from(type)); } - public XmlCodec createIdentityrefTypeCodec(final DataSchemaNode schema, - final NamespaceContext namespaceContext) { - final XmlCodec xmlStringIdentityrefCodec = - new XmlStringIdentityrefCodec(getSchemaContext(), schema.getQName().getModule(), namespaceContext); - return xmlStringIdentityrefCodec; + @Override + protected XmlCodec bitsCodec(final BitsTypeDefinition type) { + return new QuotedXmlCodec<>(BitsStringCodec.from(type)); } - private XmlCodec createUnionTypeCodec(final DataSchemaNode schema, final UnionTypeDefinition type, - final NamespaceContext namespaceContext) { - final XmlCodec xmlStringUnionCodec = new XmlStringUnionCodec(schema, type, this, namespaceContext); - return xmlStringUnionCodec; + @Override + protected XmlCodec emptyCodec(final EmptyTypeDefinition type) { + return EmptyXmlCodec.INSTANCE; } - private XmlCodec createFromSimpleType( - final DataSchemaNode schema, final TypeDefinition type, - final NamespaceContext namespaceContext) { - if (type instanceof InstanceIdentifierTypeDefinition) { - final XmlCodec iidCodec = new XmlStringInstanceIdentifierCodec(schemaContext, this, - namespaceContext); - return iidCodec; - } - if (type instanceof EmptyTypeDefinition) { - return XmlEmptyCodec.INSTANCE; - } - - final TypeDefinitionAwareCodec codec = TypeDefinitionAwareCodec.from(type); - if (codec == null) { - LOG.debug("Codec for type \"{}\" is not implemented yet.", type.getQName().getLocalName()); - return NULL_CODEC; - } - return AbstractXmlCodec.create(codec); + @Override + protected XmlCodec enumCodec(final EnumTypeDefinition type) { + return new QuotedXmlCodec<>(EnumStringCodec.from(type)); } - SchemaContext getSchemaContext() { - return schemaContext; + @Override + protected XmlCodec identityRefCodec(final IdentityrefTypeDefinition type, final QNameModule module) { + return new IdentityrefXmlCodec(getSchemaContext(), module); } - XmlCodec codecFor(final DataSchemaNode schema, final NamespaceContext namespaceContext) { - Preconditions.checkArgument(schema instanceof TypedSchemaNode, "Unsupported node type %s", schema.getClass()); - return codecs.getUnchecked(new SimpleImmutableEntry<>((TypedSchemaNode)schema, namespaceContext)); + @Override + protected XmlCodec instanceIdentifierCodec(final InstanceIdentifierTypeDefinition type) { + return new XmlStringInstanceIdentifierCodec(getSchemaContext(), this); } - XmlCodec codecFor(final DataSchemaNode schema, final TypeDefinition unionSubType, - final NamespaceContext namespaceContext) { - return createCodec(schema, unionSubType, namespaceContext); + @Override + protected XmlCodec intCodec(final IntegerTypeDefinition type) { + return new NumberXmlCodec<>(AbstractIntegerStringCodec.from(type)); + } + + @Override + protected XmlCodec decimalCodec(final DecimalTypeDefinition type) { + return new NumberXmlCodec<>(DecimalStringCodec.from(type)); + } + + @Override + protected XmlCodec stringCodec(final StringTypeDefinition type) { + return new QuotedXmlCodec<>(StringStringCodec.from(type)); + } + + @Override + protected XmlCodec uintCodec(final UnsignedIntegerTypeDefinition type) { + return new NumberXmlCodec<>(AbstractIntegerStringCodec.from(type)); + } + + @Override + protected XmlCodec unionCodec(final UnionTypeDefinition type, final List> codecs) { + return UnionXmlCodec.create(type, codecs); + } + + @Override + protected XmlCodec unknownCodec(final UnknownTypeDefinition type) { + return NullXmlCodec.INSTANCE; } } diff --git a/yang/yang-data-codec-xml/src/main/java/org/opendaylight/yangtools/yang/data/codec/xml/XmlParserStream.java b/yang/yang-data-codec-xml/src/main/java/org/opendaylight/yangtools/yang/data/codec/xml/XmlParserStream.java index 4c8ebbbefe..c6d11a1ce1 100644 --- a/yang/yang-data-codec-xml/src/main/java/org/opendaylight/yangtools/yang/data/codec/xml/XmlParserStream.java +++ b/yang/yang-data-codec-xml/src/main/java/org/opendaylight/yangtools/yang/data/codec/xml/XmlParserStream.java @@ -45,6 +45,7 @@ import org.opendaylight.yangtools.yang.model.api.DataSchemaNode; import org.opendaylight.yangtools.yang.model.api.RpcDefinition; import org.opendaylight.yangtools.yang.model.api.SchemaContext; import org.opendaylight.yangtools.yang.model.api.SchemaNode; +import org.opendaylight.yangtools.yang.model.api.TypedSchemaNode; import org.opendaylight.yangtools.yang.model.api.YangModeledAnyXmlSchemaNode; import org.w3c.dom.Document; import org.xml.sax.InputSource; @@ -259,7 +260,8 @@ public final class XmlParserStream implements Closeable, Flushable { return new DOMSource(doc.getDocumentElement()); } - return codecs.codecFor(node, namespaceCtx).deserialize(value); + Preconditions.checkArgument(node instanceof TypedSchemaNode); + return codecs.codecFor((TypedSchemaNode) node).deserializeFromString(namespaceCtx, value); } private static AbstractNodeDataWithSchema newEntryNode(final AbstractNodeDataWithSchema parent) { diff --git a/yang/yang-data-codec-xml/src/main/java/org/opendaylight/yangtools/yang/data/codec/xml/XmlStringIdentityrefCodec.java b/yang/yang-data-codec-xml/src/main/java/org/opendaylight/yangtools/yang/data/codec/xml/XmlStringIdentityrefCodec.java deleted file mode 100644 index fab629d649..0000000000 --- a/yang/yang-data-codec-xml/src/main/java/org/opendaylight/yangtools/yang/data/codec/xml/XmlStringIdentityrefCodec.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * 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.yangtools.yang.data.codec.xml; - -import com.google.common.base.Preconditions; -import java.net.URI; -import javax.annotation.Nonnull; -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.model.api.Module; -import org.opendaylight.yangtools.yang.model.api.SchemaContext; - -final class XmlStringIdentityrefCodec extends ModuleStringIdentityrefCodec implements XmlCodec { - - private final NamespaceContext namespaceContext; - - XmlStringIdentityrefCodec(final SchemaContext context, final QNameModule parentModule, - final NamespaceContext namespaceContext) { - super(context, parentModule); - this.namespaceContext = Preconditions.checkNotNull(namespaceContext); - } - - @Override - protected Module moduleForPrefix(@Nonnull final String prefix) { - if (prefix.isEmpty()) { - return context.findModuleByNamespaceAndRevision(parentModuleQname.getNamespace(), - parentModuleQname.getRevision()); - } else { - final String prefixedNS = namespaceContext.getNamespaceURI(prefix); - return context.findModuleByNamespaceAndRevision(URI.create(prefixedNS), null); - } - } - - /** - * Serialize QName with specified XMLStreamWriter. - * - * @param writer XMLStreamWriter - * @param value QName - */ - @Override - public void serializeToWriter(final XMLStreamWriter writer, final QName value) throws XMLStreamException { - writer.writeCharacters(serialize(value)); - } -} diff --git a/yang/yang-data-codec-xml/src/main/java/org/opendaylight/yangtools/yang/data/codec/xml/XmlStringInstanceIdentifierCodec.java b/yang/yang-data-codec-xml/src/main/java/org/opendaylight/yangtools/yang/data/codec/xml/XmlStringInstanceIdentifierCodec.java index c9aa69e939..292078f458 100644 --- a/yang/yang-data-codec-xml/src/main/java/org/opendaylight/yangtools/yang/data/codec/xml/XmlStringInstanceIdentifierCodec.java +++ b/yang/yang-data-codec-xml/src/main/java/org/opendaylight/yangtools/yang/data/codec/xml/XmlStringInstanceIdentifierCodec.java @@ -10,6 +10,8 @@ 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 javax.xml.namespace.NamespaceContext; import javax.xml.stream.XMLStreamException; @@ -25,22 +27,21 @@ import org.opendaylight.yangtools.yang.model.api.SchemaContext; final class XmlStringInstanceIdentifierCodec extends AbstractModuleStringInstanceIdentifierCodec implements XmlCodec { + private static final ThreadLocal> TL_CONTEXT = new ThreadLocal<>(); + private final DataSchemaContextTree dataContextTree; private final XmlCodecFactory codecFactory; private final SchemaContext context; - private final NamespaceContext namespaceContext; - XmlStringInstanceIdentifierCodec(final SchemaContext context, final XmlCodecFactory xmlCodecFactory, - final NamespaceContext namespaceContext) { + XmlStringInstanceIdentifierCodec(final SchemaContext context, final XmlCodecFactory xmlCodecFactory) { this.context = Preconditions.checkNotNull(context); this.dataContextTree = DataSchemaContextTree.from(context); this.codecFactory = Preconditions.checkNotNull(xmlCodecFactory); - this.namespaceContext = Preconditions.checkNotNull(namespaceContext); } @Override protected Module moduleForPrefix(@Nonnull final String prefix) { - final String prefixedNS = namespaceContext.getNamespaceURI(prefix); + final String prefixedNS = getNamespaceContext().getNamespaceURI(prefix); return context.findModuleByNamespaceAndRevision(URI.create(prefixedNS), null); } @@ -60,20 +61,49 @@ final class XmlStringInstanceIdentifierCodec extends AbstractModuleStringInstan protected Object deserializeKeyValue(final DataSchemaNode schemaNode, final String value) { Preconditions.checkNotNull(schemaNode, "schemaNode cannot be null"); Preconditions.checkArgument(schemaNode instanceof LeafSchemaNode, "schemaNode must be of type LeafSchemaNode"); - final XmlCodec objectXmlCodec = codecFactory.codecFor(schemaNode, namespaceContext); - return objectXmlCodec.deserialize(value); + final XmlCodec objectXmlCodec = codecFactory.codecFor((LeafSchemaNode) schemaNode); + return objectXmlCodec.deserializeFromString(getNamespaceContext(), value); + } + + @Override + public Class getDataClass() { + return YangInstanceIdentifier.class; + } + + @Override + public YangInstanceIdentifier deserializeFromString(final NamespaceContext namespaceContext, final String value) { + pushNamespaceContext(namespaceContext); + try { + return deserialize(value); + } finally { + popNamespaceContext(); + } } - /** - * Serialize YangInstanceIdentifier with specified XMLStreamWriter. - * - * @param writer XMLStreamWriter - * @param value YangInstanceIdentifier - */ @Override public void serializeToWriter(final XMLStreamWriter writer, final YangInstanceIdentifier value) throws XMLStreamException { writer.writeCharacters(serialize(value)); } + private static NamespaceContext getNamespaceContext() { + return TL_CONTEXT.get().getFirst(); + } + + private static void popNamespaceContext() { + final Deque stack = TL_CONTEXT.get(); + stack.pop(); + if (stack.isEmpty()) { + TL_CONTEXT.set(null); + } + } + + private static void pushNamespaceContext(final NamespaceContext context) { + Deque stack = TL_CONTEXT.get(); + if (stack == null) { + stack = new ArrayDeque<>(1); + TL_CONTEXT.set(stack); + } + stack.push(context); + } } diff --git a/yang/yang-data-codec-xml/src/main/java/org/opendaylight/yangtools/yang/data/codec/xml/XmlStringUnionCodec.java b/yang/yang-data-codec-xml/src/main/java/org/opendaylight/yangtools/yang/data/codec/xml/XmlStringUnionCodec.java deleted file mode 100644 index 0b4b82be1c..0000000000 --- a/yang/yang-data-codec-xml/src/main/java/org/opendaylight/yangtools/yang/data/codec/xml/XmlStringUnionCodec.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (c) 2016 Intel Corporation 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.yangtools.yang.data.codec.xml; - -import com.google.common.base.Preconditions; -import javax.xml.namespace.NamespaceContext; -import javax.xml.stream.XMLStreamException; -import javax.xml.stream.XMLStreamWriter; - -import org.opendaylight.yangtools.concepts.Codec; -import org.opendaylight.yangtools.yang.data.util.AbstractStringUnionCodec; -import org.opendaylight.yangtools.yang.model.api.DataSchemaNode; -import org.opendaylight.yangtools.yang.model.api.TypeDefinition; -import org.opendaylight.yangtools.yang.model.api.type.UnionTypeDefinition; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -final class XmlStringUnionCodec extends AbstractStringUnionCodec implements XmlCodec { - private static final Logger LOG = LoggerFactory.getLogger(XmlStringUnionCodec.class); - - private final XmlCodecFactory codecFactory; - private final NamespaceContext namespaceContext; - - XmlStringUnionCodec(final DataSchemaNode schema, final UnionTypeDefinition typeDefinition, - final XmlCodecFactory xmlCodecFactory, final NamespaceContext namespaceContext) { - super(schema, typeDefinition); - this.codecFactory = Preconditions.checkNotNull(xmlCodecFactory); - this.namespaceContext = Preconditions.checkNotNull(namespaceContext); - } - - @Override - public void serializeToWriter(XMLStreamWriter writer, Object value) throws XMLStreamException { - writer.writeCharacters(serialize(value)); - } - - @Override - protected Codec codecFor(final TypeDefinition type) { - return (Codec) codecFactory.codecFor(schema, type, namespaceContext); - } -} -- 2.36.6