From: Robert Varga Date: Sat, 12 Mar 2022 13:17:40 +0000 (+0100) Subject: Split out BindingDataObjectCodecTreeNode.streamChild() X-Git-Tag: v9.0.0~10 X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?p=mdsal.git;a=commitdiff_plain;h=5249f594a56cc600052a4f8e184c529f6ab18fc8 Split out BindingDataObjectCodecTreeNode.streamChild() BindingCodecTree does not have a way of entering the tree without specifying an InstanceIdentifier construct. This is a mistake, as we need more powerful addressing capabilities to be able to deal with Notifications and other constructs. SchemaRootCodecContext is then taught to handle Notifications specially, now that they cannot legally come from InstanceIdentifier. JIRA: MDSAL-730 Change-Id: I970cab36d2794472ef801cd0e0d67c264bd169f4 Signed-off-by: Robert Varga --- diff --git a/binding/mdsal-binding-dom-codec-api/src/main/java/org/opendaylight/mdsal/binding/dom/codec/api/BindingCodecTree.java b/binding/mdsal-binding-dom-codec-api/src/main/java/org/opendaylight/mdsal/binding/dom/codec/api/BindingCodecTree.java index 25e5ed54c7..124d9fd3e3 100644 --- a/binding/mdsal-binding-dom-codec-api/src/main/java/org/opendaylight/mdsal/binding/dom/codec/api/BindingCodecTree.java +++ b/binding/mdsal-binding-dom-codec-api/src/main/java/org/opendaylight/mdsal/binding/dom/codec/api/BindingCodecTree.java @@ -12,6 +12,7 @@ import org.eclipse.jdt.annotation.NonNull; import org.eclipse.jdt.annotation.Nullable; import org.opendaylight.yangtools.yang.binding.DataObject; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.opendaylight.yangtools.yang.common.Empty; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; import org.opendaylight.yangtools.yang.model.api.stmt.SchemaNodeIdentifier.Absolute; @@ -21,7 +22,7 @@ import org.opendaylight.yangtools.yang.model.api.stmt.SchemaNodeIdentifier.Absol * context. */ // TODO: Add more detailed documentation -public interface BindingCodecTree { +public interface BindingCodecTree extends BindingDataObjectCodecTreeParent { @Nullable BindingDataObjectCodecTreeNode getSubtreeCodec(InstanceIdentifier path); diff --git a/binding/mdsal-binding-dom-codec-api/src/main/java/org/opendaylight/mdsal/binding/dom/codec/api/BindingDataObjectCodecTreeNode.java b/binding/mdsal-binding-dom-codec-api/src/main/java/org/opendaylight/mdsal/binding/dom/codec/api/BindingDataObjectCodecTreeNode.java index 2dc3b398ee..8d8a32f5ef 100644 --- a/binding/mdsal-binding-dom-codec-api/src/main/java/org/opendaylight/mdsal/binding/dom/codec/api/BindingDataObjectCodecTreeNode.java +++ b/binding/mdsal-binding-dom-codec-api/src/main/java/org/opendaylight/mdsal/binding/dom/codec/api/BindingDataObjectCodecTreeNode.java @@ -16,12 +16,13 @@ import org.eclipse.jdt.annotation.Nullable; import org.opendaylight.yangtools.yang.binding.BindingObject; import org.opendaylight.yangtools.yang.binding.DataObject; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.opendaylight.yangtools.yang.common.Empty; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter; @Beta -public interface BindingDataObjectCodecTreeNode extends BindingObjectCodecTreeNode, - BindingNormalizedNodeCodec { +public interface BindingDataObjectCodecTreeNode + extends BindingDataObjectCodecTreeParent, BindingObjectCodecTreeNode, BindingNormalizedNodeCodec { /** * Returns binding class of interface which represents API of current schema node. The result is same as invoking @@ -32,17 +33,6 @@ public interface BindingDataObjectCodecTreeNode extends Bi @Override @NonNull Class getBindingClass(); - /** - * Returns child context as if it was walked by {@link BindingStreamEventWriter}. This means that to enter case, - * one must issue getChild(ChoiceClass).getChild(CaseClass). - * - * @param childClass Child class by Binding Stream navigation - * @return Context of child - * @throws IllegalArgumentException - * If supplied child class is not valid in specified context. - */ - @NonNull BindingDataObjectCodecTreeNode streamChild(@NonNull Class childClass); - /** * Returns child context as if it was walked by {@link BindingStreamEventWriter}. This means that to enter case, * one must issue getChild(ChoiceClass).getChild(CaseClass). diff --git a/binding/mdsal-binding-dom-codec-api/src/main/java/org/opendaylight/mdsal/binding/dom/codec/api/BindingDataObjectCodecTreeParent.java b/binding/mdsal-binding-dom-codec-api/src/main/java/org/opendaylight/mdsal/binding/dom/codec/api/BindingDataObjectCodecTreeParent.java new file mode 100644 index 0000000000..2e561e59a3 --- /dev/null +++ b/binding/mdsal-binding-dom-codec-api/src/main/java/org/opendaylight/mdsal/binding/dom/codec/api/BindingDataObjectCodecTreeParent.java @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2022 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.api; + +import com.google.common.annotations.Beta; +import org.eclipse.jdt.annotation.NonNull; +import org.opendaylight.yangtools.yang.binding.ChoiceIn; +import org.opendaylight.yangtools.yang.binding.DataObject; + +/** + * Common interface for entities which can supply a {@link BindingDataObjectCodecTreeNode} based on Binding DataObject + * class instance. + * + * @param Dummy parameter to work around problems with streaming {@link ChoiceIn} classes. Essentially we want + * {@link #streamChild(Class)} to also service such classes, which are not {@link DataObject}s. The problem + * really is that {@code case} interfaces are DataObjects and hence are an alluring target for that method. + * The workaround works with two sides: + *
    + *
  • Here the fact that we are generic means that binary compatibility dictates that our signature be + * backwards compatible with anyone who might have seen us as non-generic, i.e. in streamChild() taking + * a raw class (because there were no generics)
  • + *
  • Users pick it up from there: all they need to do is to go to raw types, then accepts any class, but + * from there we can just chain on method return, arriving into a type-safe world again
  • + *
+ */ +@Beta +// FIXME: Now the above documentation is fine and dandy, but can we adjust the shape of our classes somehow? +// The problem seems to be grouping interfaces, which are pulling in 'DataObject' to the picture and thus +// and up marking case statements even if we do not mark them specially. If we could disconnect concrete cases +// from DataObject in a civil manner, then we could go the DataObject -> ChoiceIn -> CaseOf and not have +// choice/case statements in the picture. But what would that do to all the concepts hanging off of DataObject? +public interface BindingDataObjectCodecTreeParent { + /** + * Returns child context as if it was walked by {@link BindingStreamEventWriter}. This means that to enter case, + * one must issue {@code streamChild(ChoiceClass).streamChild(CaseClass)}. + * + * @param Stream child DataObject type + * @param childClass Child class by Binding Stream navigation + * @return Context of child + * @throws IllegalArgumentException If supplied child class is not valid in specified context. + */ + @NonNull BindingDataObjectCodecTreeNode streamChild(@NonNull Class childClass); +} diff --git a/binding/mdsal-binding-dom-codec-spi/src/main/java/org/opendaylight/mdsal/binding/dom/codec/spi/ForwardingBindingDOMCodecServices.java b/binding/mdsal-binding-dom-codec-spi/src/main/java/org/opendaylight/mdsal/binding/dom/codec/spi/ForwardingBindingDOMCodecServices.java index 167e65fb0d..cc28ef3b80 100644 --- a/binding/mdsal-binding-dom-codec-spi/src/main/java/org/opendaylight/mdsal/binding/dom/codec/spi/ForwardingBindingDOMCodecServices.java +++ b/binding/mdsal-binding-dom-codec-spi/src/main/java/org/opendaylight/mdsal/binding/dom/codec/spi/ForwardingBindingDOMCodecServices.java @@ -187,4 +187,9 @@ public abstract class ForwardingBindingDOMCodecServices extends ForwardingObject public BindingRuntimeContext getRuntimeContext() { return delegate().getRuntimeContext(); } + + @Override + public BindingDataObjectCodecTreeNode streamChild(final Class childClass) { + return delegate().streamChild(childClass); + } } 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 a8537dab27..94bc76c79c 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 @@ -484,8 +484,13 @@ public final class BindingCodecContext extends AbstractBindingNormalizedNodeSeri return IdentifiableItemCodec.of(type.statement(), identifier, listClz, valueCtx); } - @SuppressWarnings("unchecked") @Override + public BindingDataObjectCodecTreeNode streamChild(final Class childClass) { + return root.streamChild(childClass); + } + + @Override + @SuppressWarnings("unchecked") public BindingDataObjectCodecTreeNode getSubtreeCodec(final InstanceIdentifier path) { // TODO Do we need defensive check here? return (BindingDataObjectCodecTreeNode) getCodecContextNode(path, null); diff --git a/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/SchemaRootCodecContext.java b/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/SchemaRootCodecContext.java index 8b80d4152b..bc1b2d4b8d 100644 --- a/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/SchemaRootCodecContext.java +++ b/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/SchemaRootCodecContext.java @@ -225,10 +225,12 @@ final class SchemaRootCodecContext extends DataContainerCo return getType().getEffectiveModelContext(); } - @SuppressWarnings("unchecked") @Override + @SuppressWarnings("unchecked") public DataContainerCodecContext streamChild(final Class childClass) { - return (DataContainerCodecContext) getOrRethrow(childrenByClass, childClass); + final DataContainerCodecContext result = Notification.class.isAssignableFrom(childClass) + ? getNotificationImpl(childClass) : getOrRethrow(childrenByClass, childClass); + return (DataContainerCodecContext) result; } @Override