From: Robert Varga Date: Mon, 27 Mar 2017 17:42:17 +0000 (+0200) Subject: BUG-8004: handle implicit RPC input X-Git-Tag: release/boron-sr4~8 X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?p=mdsal.git;a=commitdiff_plain;h=eba6505fa7ca734ff895fcf753664f3d73f1324b BUG-8004: handle implicit RPC input RPC input is always defined implicitly, which is something we cannot deal with in Binding Specification compatibly, as original generators did not emit classes for such methods and implicitly map them to Void. In order to deal with these, we need to recognize when an RPC input is not declared and re-wire it to a null codec. This loses information, but it is the best we can do (simply because there is no binding representation). Change-Id: I4edbcd0cc886396bdba79f4c0ccfd91ba3d6b2c7 Signed-off-by: Robert Varga (cherry picked from commit a69ca3a80b53cf7697b8a29029260209dea842ac) --- diff --git a/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/impl/BindingCodecContext.java b/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/impl/BindingCodecContext.java index 31d3375336..1f8f9eb79d 100644 --- a/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/impl/BindingCodecContext.java +++ b/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/impl/BindingCodecContext.java @@ -213,7 +213,7 @@ final class BindingCodecContext implements CodecContextFactory, BindingCodecTree return root.getNotification(notification); } - ContainerNodeCodecContext getRpcDataContext(final SchemaPath path) { + RpcInputCodec getRpcInputCodec(final SchemaPath path) { return root.getRpc(path); } diff --git a/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/impl/BindingNormalizedNodeCodecRegistry.java b/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/impl/BindingNormalizedNodeCodecRegistry.java index 334a20415b..3cd656398e 100644 --- a/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/impl/BindingNormalizedNodeCodecRegistry.java +++ b/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/impl/BindingNormalizedNodeCodecRegistry.java @@ -108,7 +108,7 @@ public class BindingNormalizedNodeCodecRegistry implements DataObjectSerializerR LOG.error("Unexpected failure while serializing path {} data {}", path, data, e); throw new IllegalStateException("Failed to create normalized node", e); } - return new SimpleEntry>(writeCtx.getKey(),result.getResult()); + return new SimpleEntry<>(writeCtx.getKey(),result.getResult()); } @Override @@ -189,7 +189,7 @@ public class BindingNormalizedNodeCodecRegistry implements DataObjectSerializerR final DataObject lazyObj = codec.deserialize(data); final InstanceIdentifier bindingPath = InstanceIdentifier.create(builder); - return new SimpleEntry, DataObject>(bindingPath, lazyObj); + return new SimpleEntry<>(bindingPath, lazyObj); } @Override @@ -200,7 +200,7 @@ public class BindingNormalizedNodeCodecRegistry implements DataObjectSerializerR @Override public DataObject fromNormalizedNodeRpcData(final SchemaPath path, final ContainerNode data) { - final ContainerNodeCodecContext codec = codecContext.getRpcDataContext(path); + final RpcInputCodec codec = codecContext.getRpcInputCodec(path); return codec.deserialize(data); } @@ -228,7 +228,7 @@ public class BindingNormalizedNodeCodecRegistry implements DataObjectSerializerR public Function>, Optional> deserializeFunction(final InstanceIdentifier path) { final DataObjectCodecContext ctx = (DataObjectCodecContext) codecContext.getCodecContextNode(path, null); - return new DeserializeFunction(ctx); + return new DeserializeFunction<>(ctx); } @Override diff --git a/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/impl/ContainerNodeCodecContext.java b/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/impl/ContainerNodeCodecContext.java index 33a65fd9fe..1c7b0e47a4 100644 --- a/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/impl/ContainerNodeCodecContext.java +++ b/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/impl/ContainerNodeCodecContext.java @@ -13,7 +13,8 @@ import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode; import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode; -final class ContainerNodeCodecContext extends DataObjectCodecContext { +final class ContainerNodeCodecContext extends DataObjectCodecContext + implements RpcInputCodec { ContainerNodeCodecContext(final DataContainerCodecPrototype prototype) { super(prototype); diff --git a/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/impl/RpcInputDataObjectCodec.java b/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/impl/RpcInputDataObjectCodec.java new file mode 100644 index 0000000000..c2ed1aedd1 --- /dev/null +++ b/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/impl/RpcInputDataObjectCodec.java @@ -0,0 +1,27 @@ +/* + * 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.binding.data.codec.impl; + +import org.opendaylight.mdsal.binding.dom.codec.api.BindingNormalizedNodeCodec; +import org.opendaylight.yangtools.yang.binding.DataObject; + +/** + * Marker interface for codecs dealing with RPC input being potentially unmapped. We use this interface to mark both + * {@link UnmappedRpcInputCodec} and {@link ContainerNodeCodecContext}, which results in bimorphic invocation in + * {@link BindingNormalizedNodeCodecRegistry#fromNormalizedNodeRpcData()}. + * + * Without this interface we could end up with megamorphic invocation, as the two implementations cannot share class + * hierarchy. + * + * @author Robert Varga + * + * @param Binding representation of data + */ +interface RpcInputCodec extends BindingNormalizedNodeCodec { + +} diff --git a/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/impl/SchemaRootCodecContext.java b/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/impl/SchemaRootCodecContext.java index 512c10e5da..ba84c18e06 100644 --- a/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/impl/SchemaRootCodecContext.java +++ b/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/impl/SchemaRootCodecContext.java @@ -33,6 +33,8 @@ import org.opendaylight.yangtools.yang.model.api.NotificationDefinition; import org.opendaylight.yangtools.yang.model.api.RpcDefinition; import org.opendaylight.yangtools.yang.model.api.SchemaContext; import org.opendaylight.yangtools.yang.model.api.SchemaPath; +import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement; +import org.opendaylight.yangtools.yang.model.api.meta.StatementSource; import org.opendaylight.yangtools.yang.model.util.SchemaContextUtil; import org.opendaylight.yangtools.yang.model.util.SchemaNodeUtils; @@ -44,7 +46,6 @@ final class SchemaRootCodecContext extends DataContainerCo public DataContainerCodecContext load(final Class key) { return createDataTreeChildContext(key); } - }); private final LoadingCache, ContainerNodeCodecContext> rpcDataByClass = CacheBuilder.newBuilder().build( @@ -74,23 +75,29 @@ final class SchemaRootCodecContext extends DataContainerCo @SuppressWarnings("rawtypes") final Class childCls = factory().getRuntimeContext().getClassForSchema(childSchema); return streamChild(childCls); - } else { - throw new UnsupportedOperationException("Unsupported child type " + childSchema.getClass()); } + + throw new UnsupportedOperationException("Unsupported child type " + childSchema.getClass()); } }); - private final LoadingCache> rpcDataByPath = CacheBuilder.newBuilder().build( - new CacheLoader>() { - - @SuppressWarnings({ "rawtypes", "unchecked" }) - @Override - public ContainerNodeCodecContext load(final SchemaPath key) { - final ContainerSchemaNode schema = SchemaContextUtil.getRpcDataSchema(getSchema(), key); - final Class cls = factory().getRuntimeContext().getClassForSchema(schema); - return getRpc(cls); + private final LoadingCache> rpcDataByPath = CacheBuilder.newBuilder().build( + new CacheLoader>() { + @SuppressWarnings({ "rawtypes", "unchecked" }) + @Override + public RpcInputCodec load(final SchemaPath key) { + final ContainerSchemaNode schema = SchemaContextUtil.getRpcDataSchema(getSchema(), key); + if (schema instanceof EffectiveStatement && + ((EffectiveStatement) schema).getDeclared().getStatementSource() != StatementSource.DECLARATION) { + // This is an implicitly-defined input or output statement. We do not have a corresponding + // data representation, so we hard-wire it to null. + return UnmappedRpcInputCodec.getInstance(); } - }); + + final Class cls = factory().getRuntimeContext().getClassForSchema(schema); + return getRpc(cls); + } + }); private final LoadingCache> notificationsByPath = CacheBuilder.newBuilder() .build(new CacheLoader>() { @@ -165,7 +172,7 @@ final class SchemaRootCodecContext extends DataContainerCo return getOrRethrow(notificationsByPath, notification); } - ContainerNodeCodecContext getRpc(final SchemaPath notification) { + RpcInputCodec getRpc(final SchemaPath notification) { return getOrRethrow(rpcDataByPath, notification); } @@ -183,7 +190,6 @@ final class SchemaRootCodecContext extends DataContainerCo for (final RpcDefinition potential : getSchema().getOperations()) { final QName potentialQName = potential.getQName(); /* - * * Check if rpc and class represents data from same module and then * checks if rpc local name produces same class name as class name * appended with Input/Output based on QName associated with bidning @@ -242,7 +248,7 @@ final class SchemaRootCodecContext extends DataContainerCo return cache.getUnchecked(key); } catch (final UncheckedExecutionException e) { final Throwable cause = e.getCause(); - if(cause != null) { + if (cause != null) { Throwables.propagateIfPossible(cause); } throw e; diff --git a/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/impl/UnmappedRpcInputCodec.java b/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/impl/UnmappedRpcInputCodec.java new file mode 100644 index 0000000000..58253827f9 --- /dev/null +++ b/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/impl/UnmappedRpcInputCodec.java @@ -0,0 +1,42 @@ +/* + * 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.binding.data.codec.impl; + +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; + +/** + * Singleton codec for translating RPCs with implicit input statements, which are not mapped by binding spec v1. Since + * there is no equivalent, we always return null. + * + * @author Robert Varga + * + * @param Data object type + */ +final class UnmappedRpcInputCodec implements RpcInputCodec { + private static final UnmappedRpcInputCodec INSTANCE = new UnmappedRpcInputCodec<>(); + + private UnmappedRpcInputCodec() { + + } + + @SuppressWarnings("unchecked") + static UnmappedRpcInputCodec getInstance() { + return (UnmappedRpcInputCodec) INSTANCE; + } + + @Override + public D deserialize(final NormalizedNode data) { + return null; + } + + @Override + public NormalizedNode serialize(final D data) { + throw new UnsupportedOperationException("Serialization of " + data + " not supported"); + } +}