From 48ad618ab66517879082275d681aab64c90f7a70 Mon Sep 17 00:00:00 2001 From: Robert Varga Date: Thu, 11 Apr 2019 16:07:41 +0200 Subject: [PATCH] Split LeafNodeCodeContext and LeafSetNodeCodecContext These are the two basic node contexts we are currently supporting, split them from ValueNodeContext, properly separating deserializeObject() implementations. JIRA: MDSAL-436 Change-Id: Ieeb9c047f980631ab3861bb7e42ef87e52f9552e Signed-off-by: Robert Varga --- .../dom/codec/impl/BindingCodecContext.java | 19 ++- .../impl/BindingToNormalizedStreamWriter.java | 11 +- .../dom/codec/impl/LeafNodeCodecContext.java | 101 +++++++++++++ .../codec/impl/LeafSetNodeCodecContext.java | 40 ++++++ .../dom/codec/impl/ValueNodeCodecContext.java | 136 +++--------------- 5 files changed, 175 insertions(+), 132 deletions(-) create mode 100644 binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/LeafNodeCodecContext.java create mode 100644 binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/LeafSetNodeCodecContext.java diff --git a/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/BindingCodecContext.java b/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/BindingCodecContext.java index e19831657f..6a93dc4a92 100644 --- a/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/BindingCodecContext.java +++ b/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/BindingCodecContext.java @@ -254,15 +254,21 @@ final class BindingCodecContext implements CodecContextFactory, BindingCodecTree // We do not have schema for leaf, so we will ignore it (e.g. getClass). continue; } + final TypedDataSchemaNode typedSchema = (TypedDataSchemaNode) schema; - final Class valueType; + final ValueNodeCodecContext valueNode; if (schema instanceof LeafSchemaNode) { - valueType = method.getReturnType(); + final LeafSchemaNode leafSchema = (LeafSchemaNode) schema; + + final Class valueType = method.getReturnType(); + final Codec codec = getCodec(valueType, leafSchema.getType()); + valueNode = new LeafNodeCodecContext(leafSchema, codec, method, context.getSchemaContext()); } else if (schema instanceof LeafListSchemaNode) { final Optional optType = ClassLoaderUtils.getFirstGenericParameter( method.getGenericReturnType()); checkState(optType.isPresent(), "Failed to find return type for %s", method); + final Class valueType; final Type genericType = optType.get(); if (genericType instanceof Class) { valueType = (Class) genericType; @@ -271,14 +277,15 @@ final class BindingCodecContext implements CodecContextFactory, BindingCodecTree } else { throw new IllegalStateException("Unexpected return type " + genericType); } + + final LeafListSchemaNode leafListSchema = (LeafListSchemaNode) schema; + final Codec codec = getCodec(valueType, leafListSchema.getType()); + valueNode = new LeafSetNodeCodecContext(leafListSchema, codec, method); } else { throw new IllegalStateException("Unhandled typed schema " + typedSchema); } - final Codec codec = getCodec(valueType, typedSchema.getType()); - final ValueNodeCodecContext leafNode = new ValueNodeCodecContext(typedSchema, codec, method, - context.getSchemaContext()); - leaves.put(schema.getQName().getLocalName(), leafNode); + leaves.put(schema.getQName().getLocalName(), valueNode); } } return ImmutableMap.copyOf(leaves); diff --git a/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/BindingToNormalizedStreamWriter.java b/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/BindingToNormalizedStreamWriter.java index 35791ccf5e..129024f91b 100644 --- a/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/BindingToNormalizedStreamWriter.java +++ b/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/BindingToNormalizedStreamWriter.java @@ -7,9 +7,9 @@ */ package org.opendaylight.mdsal.binding.dom.codec.impl; +import static com.google.common.base.Preconditions.checkArgument; import static java.util.Objects.requireNonNull; -import com.google.common.base.Preconditions; import java.io.IOException; import java.util.AbstractMap; import java.util.ArrayDeque; @@ -74,8 +74,7 @@ final class BindingToNormalizedStreamWriter implements BindingStreamEventWriter, // Entry of first node next = rootNodeSchema; } else { - Preconditions.checkArgument(current() instanceof DataContainerCodecContext, "Could not start node %s", - name); + checkArgument(current() instanceof DataContainerCodecContext, "Could not start node %s", name); next = ((DataContainerCodecContext) current()).streamChild((Class) name); } this.schema.push(next); @@ -108,12 +107,12 @@ final class BindingToNormalizedStreamWriter implements BindingStreamEventWriter, } private Map.Entry serializeLeaf(final String localName, final Object value) { - Preconditions.checkArgument(current() instanceof DataObjectCodecContext); + checkArgument(current() instanceof DataObjectCodecContext); DataObjectCodecContext currentCasted = (DataObjectCodecContext) current(); ValueNodeCodecContext leafContext = currentCasted.getLeafChild(localName); - NodeIdentifier domArg = (NodeIdentifier) leafContext.getDomPathArgument(); + NodeIdentifier domArg = leafContext.getDomPathArgument(); Object domValue = leafContext.getValueCodec().serialize(value); emitSchema(leafContext.getSchema()); return new AbstractMap.SimpleEntry<>(domArg, domValue); @@ -137,7 +136,7 @@ final class BindingToNormalizedStreamWriter implements BindingStreamEventWriter, @Override public void leafSetEntryNode(final Object value) throws IOException { - final ValueNodeCodecContext ctx = (ValueNodeCodecContext) current(); + final LeafSetNodeCodecContext ctx = (LeafSetNodeCodecContext) current(); final Object domValue = ctx.getValueCodec().serialize(value); delegate.startLeafSetEntryNode(new NodeWithValue<>(ctx.getSchema().getQName(), domValue)); delegate.scalarValue(domValue); diff --git a/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/LeafNodeCodecContext.java b/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/LeafNodeCodecContext.java new file mode 100644 index 0000000000..fc310f4f93 --- /dev/null +++ b/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/LeafNodeCodecContext.java @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2019 PANTHEON.tech, 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.mdsal.binding.dom.codec.impl; + +import java.lang.reflect.Method; +import java.util.Optional; +import java.util.Set; +import org.opendaylight.yangtools.concepts.Codec; +import org.opendaylight.yangtools.yang.common.QName; +import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; +import org.opendaylight.yangtools.yang.data.impl.codec.TypeDefinitionAwareCodec; +import org.opendaylight.yangtools.yang.model.api.DataSchemaNode; +import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode; +import org.opendaylight.yangtools.yang.model.api.Module; +import org.opendaylight.yangtools.yang.model.api.ModuleImport; +import org.opendaylight.yangtools.yang.model.api.SchemaContext; +import org.opendaylight.yangtools.yang.model.api.TypeDefinition; +import org.opendaylight.yangtools.yang.model.api.type.IdentityrefTypeDefinition; + +final class LeafNodeCodecContext extends ValueNodeCodecContext { + LeafNodeCodecContext(final LeafSchemaNode schema, final Codec codec, + final Method getter, final SchemaContext schemaContext) { + super(schema, codec, getter, createDefaultObject(schema, codec, schemaContext)); + } + + @Override + protected Object deserializeObject(final NormalizedNode normalizedNode) { + return normalizedNode != null ? getValueCodec().deserialize(normalizedNode.getValue()) : null; + } + + private static Object createDefaultObject(final LeafSchemaNode schema, final Codec codec, + final SchemaContext schemaContext) { + Optional defaultValue = schema.getType().getDefaultValue(); + TypeDefinition type = schema.getType(); + if (defaultValue.isPresent()) { + if (type instanceof IdentityrefTypeDefinition) { + return qnameDomValueFromString(codec, schema, (String) defaultValue.get(), schemaContext); + } + return domValueFromString(codec, type, defaultValue.get()); + } + + while (type.getBaseType() != null && !type.getDefaultValue().isPresent()) { + type = type.getBaseType(); + } + + defaultValue = type.getDefaultValue(); + if (defaultValue.isPresent()) { + if (type instanceof IdentityrefTypeDefinition) { + return qnameDomValueFromString(codec, schema, (String) defaultValue.get(), schemaContext); + } + return domValueFromString(codec, type, defaultValue); + } + return null; + } + + private static Object qnameDomValueFromString(final Codec codec, final DataSchemaNode schema, + final String defaultValue, final SchemaContext schemaContext) { + int prefixEndIndex = defaultValue.indexOf(':'); + QName qname; + if (prefixEndIndex != -1) { + String defaultValuePrefix = defaultValue.substring(0, prefixEndIndex); + + Module module = schemaContext.findModule(schema.getQName().getModule()).get(); + if (module.getPrefix().equals(defaultValuePrefix)) { + qname = QName.create(module.getQNameModule(), defaultValue.substring(prefixEndIndex + 1)); + return codec.deserialize(qname); + } + + Set imports = module.getImports(); + for (ModuleImport moduleImport : imports) { + if (moduleImport.getPrefix().equals(defaultValuePrefix)) { + Module importedModule = schemaContext.findModule(moduleImport.getModuleName(), + moduleImport.getRevision()).get(); + qname = QName.create(importedModule.getQNameModule(), defaultValue.substring(prefixEndIndex + 1)); + return codec.deserialize(qname); + } + } + return null; + } + + qname = QName.create(schema.getQName(), defaultValue); + return codec.deserialize(qname); + } + + private static Object domValueFromString(final Codec codec, final TypeDefinition type, + final Object defaultValue) { + TypeDefinitionAwareCodec typeDefAwareCodec = TypeDefinitionAwareCodec.from(type); + if (typeDefAwareCodec != null) { + Object castedDefaultValue = typeDefAwareCodec.deserialize((String) defaultValue); + return codec.deserialize(castedDefaultValue); + } + // FIXME: BUG-4647 Refactor / redesign this to throw hard error, once BUG-4638 is fixed and will provide proper + // getDefaultValue() implementation. + return null; + } +} diff --git a/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/LeafSetNodeCodecContext.java b/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/LeafSetNodeCodecContext.java new file mode 100644 index 0000000000..e9de07df61 --- /dev/null +++ b/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/LeafSetNodeCodecContext.java @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2019 PANTHEON.tech, 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.mdsal.binding.dom.codec.impl; + +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import org.opendaylight.yangtools.concepts.Codec; +import org.opendaylight.yangtools.yang.data.api.schema.LeafSetEntryNode; +import org.opendaylight.yangtools.yang.data.api.schema.LeafSetNode; +import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; +import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode; + +final class LeafSetNodeCodecContext extends ValueNodeCodecContext { + LeafSetNodeCodecContext(final LeafListSchemaNode schema, final Codec codec, + final Method getter) { + // FIXME: add support for defaults + super(schema, codec, getter, null); + } + + @Override + protected Object deserializeObject(final NormalizedNode normalizedNode) { + if (normalizedNode instanceof LeafSetNode) { + @SuppressWarnings("unchecked") + final Collection> domValues = ((LeafSetNode) normalizedNode).getValue(); + final List result = new ArrayList<>(domValues.size()); + for (final LeafSetEntryNode valueNode : domValues) { + result.add(getValueCodec().deserialize(valueNode.getValue())); + } + return result; + } + return null; + } +} diff --git a/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/ValueNodeCodecContext.java b/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/ValueNodeCodecContext.java index d0c892835a..a99ef85a93 100644 --- a/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/ValueNodeCodecContext.java +++ b/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/ValueNodeCodecContext.java @@ -10,160 +10,56 @@ package org.opendaylight.mdsal.binding.dom.codec.impl; import static java.util.Objects.requireNonNull; import java.lang.reflect.Method; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; -import java.util.Optional; -import java.util.Set; +import org.eclipse.jdt.annotation.NonNull; import org.opendaylight.yangtools.concepts.Codec; -import org.opendaylight.yangtools.yang.common.QName; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier; -import org.opendaylight.yangtools.yang.data.api.schema.LeafNode; -import org.opendaylight.yangtools.yang.data.api.schema.LeafSetEntryNode; -import org.opendaylight.yangtools.yang.data.api.schema.LeafSetNode; -import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; -import org.opendaylight.yangtools.yang.data.impl.codec.TypeDefinitionAwareCodec; -import org.opendaylight.yangtools.yang.model.api.DataSchemaNode; -import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode; -import org.opendaylight.yangtools.yang.model.api.Module; -import org.opendaylight.yangtools.yang.model.api.ModuleImport; -import org.opendaylight.yangtools.yang.model.api.SchemaContext; -import org.opendaylight.yangtools.yang.model.api.TypeDefinition; import org.opendaylight.yangtools.yang.model.api.TypedDataSchemaNode; -import org.opendaylight.yangtools.yang.model.api.type.IdentityrefTypeDefinition; /** * Abstract base class for atomic nodes. These are nodes which are not decomposed in the Binding Specification, such * as LeafNodes and LeafSetNodes. */ -// FIXME: MDSAL-436: this class should be specialized for Leaf and LeafSet -final class ValueNodeCodecContext extends NodeCodecContext implements NodeContextSupplier { - private final NodeIdentifier yangIdentifier; - private final Codec valueCodec; - private final Method getter; - private final TypedDataSchemaNode schema; +abstract class ValueNodeCodecContext extends NodeCodecContext implements NodeContextSupplier { + private final @NonNull NodeIdentifier yangIdentifier; + private final @NonNull Codec valueCodec; + private final @NonNull Method getter; + private final @NonNull TypedDataSchemaNode schema; private final Object defaultObject; ValueNodeCodecContext(final TypedDataSchemaNode schema, final Codec codec, - final Method getter, final SchemaContext schemaContext) { + final Method getter, final Object defaultObject) { this.yangIdentifier = NodeIdentifier.create(schema.getQName()); this.valueCodec = requireNonNull(codec); - this.getter = getter; + this.getter = requireNonNull(getter); this.schema = requireNonNull(schema); - - this.defaultObject = createDefaultObject(schema, valueCodec, schemaContext); - } - - private static Object createDefaultObject(final DataSchemaNode schema, final Codec codec, - final SchemaContext schemaContext) { - if (schema instanceof LeafSchemaNode) { - Optional defaultValue = ((LeafSchemaNode) schema).getType().getDefaultValue(); - TypeDefinition type = ((LeafSchemaNode) schema).getType(); - if (defaultValue.isPresent()) { - if (type instanceof IdentityrefTypeDefinition) { - return qnameDomValueFromString(codec, schema, (String) defaultValue.get(), schemaContext); - } - return domValueFromString(codec, type, defaultValue.get()); - } - - while (type.getBaseType() != null && !type.getDefaultValue().isPresent()) { - type = type.getBaseType(); - } - - defaultValue = type.getDefaultValue(); - if (defaultValue.isPresent()) { - if (type instanceof IdentityrefTypeDefinition) { - return qnameDomValueFromString(codec, schema, (String) defaultValue.get(), schemaContext); - } - return domValueFromString(codec, type, defaultValue); - } - } - return null; - } - - private static Object qnameDomValueFromString(final Codec codec, final DataSchemaNode schema, - final String defaultValue, final SchemaContext schemaContext) { - int prefixEndIndex = defaultValue.indexOf(':'); - QName qname; - if (prefixEndIndex != -1) { - String defaultValuePrefix = defaultValue.substring(0, prefixEndIndex); - - Module module = schemaContext.findModule(schema.getQName().getModule()).get(); - if (module.getPrefix().equals(defaultValuePrefix)) { - qname = QName.create(module.getQNameModule(), defaultValue.substring(prefixEndIndex + 1)); - return codec.deserialize(qname); - } - - Set imports = module.getImports(); - for (ModuleImport moduleImport : imports) { - if (moduleImport.getPrefix().equals(defaultValuePrefix)) { - Module importedModule = schemaContext.findModule(moduleImport.getModuleName(), - moduleImport.getRevision()).get(); - qname = QName.create(importedModule.getQNameModule(), defaultValue.substring(prefixEndIndex + 1)); - return codec.deserialize(qname); - } - } - return null; - } - - qname = QName.create(schema.getQName(), defaultValue); - return codec.deserialize(qname); - } - - private static Object domValueFromString(final Codec codec, final TypeDefinition type, - final Object defaultValue) { - TypeDefinitionAwareCodec typeDefAwareCodec = TypeDefinitionAwareCodec.from(type); - if (typeDefAwareCodec != null) { - Object castedDefaultValue = typeDefAwareCodec.deserialize((String) defaultValue); - return codec.deserialize(castedDefaultValue); - } - // FIXME: BUG-4647 Refactor / redesign this to throw hard error, once BUG-4638 is fixed and will provide proper - // getDefaultValue() implementation. - return null; + this.defaultObject = defaultObject; } @Override - protected NodeIdentifier getDomPathArgument() { + protected final NodeIdentifier getDomPathArgument() { return yangIdentifier; } - protected Codec getValueCodec() { - return valueCodec; - } - @Override - public NodeCodecContext get() { + public final NodeCodecContext get() { return this; } - Method getGetter() { + final Method getGetter() { return getter; } - @Override - protected Object deserializeObject(final NormalizedNode normalizedNode) { - if (normalizedNode instanceof LeafNode) { - return valueCodec.deserialize(normalizedNode.getValue()); - } - if (normalizedNode instanceof LeafSetNode) { - @SuppressWarnings("unchecked") - final Collection> domValues = ((LeafSetNode) normalizedNode).getValue(); - final List result = new ArrayList<>(domValues.size()); - for (final LeafSetEntryNode valueNode : domValues) { - result.add(valueCodec.deserialize(valueNode.getValue())); - } - return result; - } - return null; + final Codec getValueCodec() { + return valueCodec; } @Override - public TypedDataSchemaNode getSchema() { + public final TypedDataSchemaNode getSchema() { return schema; } @Override - Object defaultObject() { + final Object defaultObject() { return defaultObject; } } -- 2.36.6