import org.opendaylight.mdsal.binding.dom.codec.api.BindingCodecTree;
import org.opendaylight.mdsal.binding.dom.codec.api.BindingCodecTreeFactory;
import org.opendaylight.mdsal.binding.dom.codec.api.BindingCodecTreeNode;
+import org.opendaylight.mdsal.binding.dom.codec.api.BindingLazyContainerNode;
import org.opendaylight.mdsal.binding.dom.codec.api.BindingNormalizedNodeSerializer;
import org.opendaylight.mdsal.binding.dom.codec.gen.impl.StreamWriterGenerator;
import org.opendaylight.mdsal.binding.dom.codec.impl.BindingNormalizedNodeCodecRegistry;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.PathArgument;
import org.opendaylight.yangtools.yang.binding.Notification;
+import org.opendaylight.yangtools.yang.binding.RpcInput;
+import org.opendaylight.yangtools.yang.binding.RpcOutput;
import org.opendaylight.yangtools.yang.binding.RpcService;
import org.opendaylight.yangtools.yang.binding.util.BindingReflections;
import org.opendaylight.yangtools.yang.common.QNameModule;
import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
import org.opendaylight.yangtools.yang.data.impl.codec.DeserializationException;
return codecRegistry.fromNormalizedNodeRpcData(path, data);
}
+ @Override
+ public <T extends RpcInput> T fromNormalizedNodeActionInput(final Class<? extends Action<?, ?, ?>> action,
+ final ContainerNode input) {
+ return codecRegistry.fromNormalizedNodeActionInput(action, input);
+ }
+
+ @Override
+ public <T extends RpcOutput> T fromNormalizedNodeActionOutput(final Class<? extends Action<?, ?, ?>> action,
+ final ContainerNode output) {
+ return codecRegistry.fromNormalizedNodeActionOutput(action, output);
+ }
+
@Override
public final InstanceIdentifier<?> fromYangInstanceIdentifier(@Nonnull final YangInstanceIdentifier dom) {
return codecRegistry.fromYangInstanceIdentifier(dom);
return codecRegistry.toNormalizedNodeRpcData(data);
}
+ @Override
+ public ContainerNode toNormalizedNodeActionInput(final Class<? extends Action<?, ?, ?>> action,
+ final RpcInput input) {
+ return codecRegistry.toNormalizedNodeActionInput(action, input);
+ }
+
+ @Override
+ public ContainerNode toNormalizedNodeActionOutput(final Class<? extends Action<?, ?, ?>> action,
+ final RpcOutput output) {
+ return codecRegistry.toNormalizedNodeActionOutput(action, output);
+ }
+
+ @Override
+ public BindingLazyContainerNode<RpcInput> toLazyNormalizedNodeActionInput(
+ final Class<? extends Action<?, ?, ?>> action, final NodeIdentifier identifier, final RpcInput input) {
+ return codecRegistry.toLazyNormalizedNodeActionInput(action, identifier, input);
+ }
+
+ @Override
+ public BindingLazyContainerNode<RpcOutput> toLazyNormalizedNodeActionOutput(
+ final Class<? extends Action<?, ?, ?>> action, final NodeIdentifier identifier, final RpcOutput output) {
+ return codecRegistry.toLazyNormalizedNodeActionOutput(action, identifier, output);
+ }
+
/**
* Returns a Binding-Aware instance identifier from normalized
* instance-identifier if it is possible to create representation.
*/
package org.opendaylight.mdsal.binding.dom.codec.api;
+import com.google.common.annotations.Beta;
import java.util.Map.Entry;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
+import org.eclipse.jdt.annotation.NonNull;
+import org.opendaylight.yangtools.yang.binding.Action;
import org.opendaylight.yangtools.yang.binding.DataContainer;
import org.opendaylight.yangtools.yang.binding.DataObject;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
import org.opendaylight.yangtools.yang.binding.Notification;
+import org.opendaylight.yangtools.yang.binding.RpcInput;
+import org.opendaylight.yangtools.yang.binding.RpcOutput;
+import org.opendaylight.yangtools.yang.binding.util.BindingReflections;
+import org.opendaylight.yangtools.yang.common.YangConstants;
import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
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.SchemaPath;
* Binding Data representation and NormalizedNode representation.
*/
public interface BindingNormalizedNodeSerializer {
-
/**
- * Translates supplied Binding Instance Identifier into NormalizedNode
- * instance identifier.
+ * Translates supplied Binding Instance Identifier into NormalizedNode instance identifier.
*
- * @param binding
- * Binding Instance Identifier
+ * @param binding Binding Instance Identifier
* @return DOM Instance Identifier
- * @throws IllegalArgumentException
- * If supplied Instance Identifier is not valid.
+ * @throws IllegalArgumentException If supplied Instance Identifier is not valid.
*/
YangInstanceIdentifier toYangInstanceIdentifier(@Nonnull InstanceIdentifier<?> binding);
/**
- * Translates supplied YANG Instance Identifier into Binding instance
- * identifier.
+ * Translates supplied YANG Instance Identifier into Binding instance identifier.
*
- * @param dom
- * YANG Instance Identifier
- * @return Binding Instance Identifier, or null if the instance identifier
- * is not representable.
+ * @param dom YANG Instance Identifier
+ * @return Binding Instance Identifier, or null if the instance identifier is not representable.
*/
@Nullable
- InstanceIdentifier<?> fromYangInstanceIdentifier(@Nonnull YangInstanceIdentifier dom);
+ <T extends DataObject> InstanceIdentifier<T> fromYangInstanceIdentifier(@Nonnull YangInstanceIdentifier dom);
/**
- * Translates supplied Binding Instance Identifier and data into
- * NormalizedNode representation.
+ * Translates supplied Binding Instance Identifier and data into NormalizedNode representation.
*
- * @param path
- * Binding Instance Identifier pointing to data
- * @param data
- * Data object representing data
+ * @param path Binding Instance Identifier pointing to data
+ * @param data Data object representing data
* @return NormalizedNode representation
- * @throws IllegalArgumentException
- * If supplied Instance Identifier is not valid.
+ * @throws IllegalArgumentException If supplied Instance Identifier is not valid.
*/
<T extends DataObject> Entry<YangInstanceIdentifier, NormalizedNode<?, ?>> toNormalizedNode(
InstanceIdentifier<T> path, T data);
/**
- * Translates supplied YANG Instance Identifier and NormalizedNode into
- * Binding data.
+ * Translates supplied YANG Instance Identifier and NormalizedNode into Binding data.
*
* @param path Binding Instance Identifier
* @param data NormalizedNode representing data
*/
@Nullable DataObject fromNormalizedNodeRpcData(@Nonnull SchemaPath path,@Nonnull ContainerNode data);
+ /**
+ * Translates supplied ContainerNode action input.
+ *
+ * @param action Binding action class
+ * @param input ContainerNode representing data
+ * @return Binding representation of action input
+ * @throws NullPointerException if any of the arguments is null
+ */
+ @Beta
+ <T extends RpcInput> @NonNull T fromNormalizedNodeActionInput(
+ @NonNull Class<? extends Action<?, ?, ?>> action, @NonNull ContainerNode input);
+
+ /**
+ * Translates supplied ContainerNode action output.
+ *
+ * @param action Binding action class
+ * @param output ContainerNode representing data
+ * @return Binding representation of action output
+ * @throws NullPointerException if any of the arguments is null
+ */
+ @Beta
+ <T extends RpcOutput> @NonNull T fromNormalizedNodeActionOutput(
+ @NonNull Class<? extends Action<?, ?, ?>> action, @NonNull ContainerNode output);
+
/**
* Translates supplied Binding Notification or output into NormalizedNode notification.
*
* @return NormalizedNode representation of rpc data
*/
@Nonnull ContainerNode toNormalizedNodeRpcData(@Nonnull DataContainer data);
+
+ /**
+ * Lazily translates supplied Binding action input into NormalizedNode data.
+ *
+ * @param action Binding action class
+ * @param input Binding action input
+ * @return NormalizedNode representation of action input
+ * @throws NullPointerException if any of the arguments is null
+ */
+ @Beta
+ @NonNull BindingLazyContainerNode<RpcInput> toLazyNormalizedNodeActionInput(
+ @NonNull Class<? extends Action<?, ?, ?>> action, @NonNull NodeIdentifier identifier,
+ @NonNull RpcInput input);
+
+ /**
+ * Lazily translates supplied Binding action input into NormalizedNode data.
+ *
+ * @param action Binding action class
+ * @param input Binding action input
+ * @return NormalizedNode representation of action input
+ * @throws NullPointerException if any of the arguments is null
+ */
+ @Beta default @NonNull BindingLazyContainerNode<RpcInput> toLazyNormalizedNodeActionInput(
+ @NonNull final Class<? extends Action<?, ?, ?>> action, @NonNull final RpcInput input) {
+ return toLazyNormalizedNodeActionInput(action,
+ new NodeIdentifier(YangConstants.operationInputQName(BindingReflections.getQNameModule(action))), input);
+ }
+
+ /**
+ * Translates supplied Binding action input into NormalizedNode data.
+ *
+ * @param action Binding action class
+ * @param input Binding action input
+ * @return NormalizedNode representation of action input
+ * @throws NullPointerException if any of the arguments is null
+ */
+ @Beta default @NonNull ContainerNode toNormalizedNodeActionInput(
+ @NonNull final Class<? extends Action<?, ?, ?>> action, @NonNull final RpcInput input) {
+ return toLazyNormalizedNodeActionInput(action,
+ new NodeIdentifier(YangConstants.operationInputQName(BindingReflections.getQNameModule(action))), input)
+ .getDelegate();
+ }
+
+ /**
+ * Lazily translates supplied Binding action output into NormalizedNode data.
+ *
+ * @param action Binding action class
+ * @param output Binding action output
+ * @return NormalizedNode representation of action output
+ */
+ @Beta
+ @NonNull BindingLazyContainerNode<RpcOutput> toLazyNormalizedNodeActionOutput(
+ @NonNull Class<? extends Action<?, ?, ?>> action, @NonNull NodeIdentifier identifier,
+ @NonNull RpcOutput output);
+
+ /**
+ * Lazily translates supplied Binding action output into NormalizedNode data.
+ *
+ * @param action Binding action class
+ * @param output Binding action output
+ * @return NormalizedNode representation of action output
+ */
+ @Beta default @NonNull BindingLazyContainerNode<RpcOutput> toLazyNormalizedNodeActionOutput(
+ @NonNull final Class<? extends Action<?, ?, ?>> action, @NonNull final RpcOutput output) {
+ return toLazyNormalizedNodeActionOutput(action,
+ new NodeIdentifier(YangConstants.operationInputQName(BindingReflections.getQNameModule(action))), output);
+ }
+
+ /**
+ * Translates supplied Binding action output into NormalizedNode data.
+ *
+ * @param output Binding action output
+ * @return NormalizedNode representation of action output
+ */
+ @Beta default @NonNull ContainerNode toNormalizedNodeActionOutput(
+ @NonNull final Class<? extends Action<?, ?, ?>> action, @NonNull final RpcOutput output) {
+ return toLazyNormalizedNodeActionOutput(action,
+ new NodeIdentifier(YangConstants.operationInputQName(BindingReflections.getQNameModule(action))), output)
+ .getDelegate();
+ }
}
import java.util.Map.Entry;
import javax.annotation.Nonnull;
+import org.opendaylight.yangtools.yang.binding.Action;
import org.opendaylight.yangtools.yang.binding.BindingStreamEventWriter;
import org.opendaylight.yangtools.yang.binding.DataContainer;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
@Nonnull
BindingStreamEventWriter newNotificationWriter(@Nonnull Class<? extends Notification> notification,
@Nonnull NormalizedNodeStreamWriter domWriter);
+
+ /**
+ * Creates a {@link BindingStreamEventWriter} for action input which will translate to NormalizedNode model
+ * and invoke proper events on supplied {@link NormalizedNodeStreamWriter}.
+ *
+ * @param action Binding class representing action for which writer should be instantiated
+ * @param domWriter Stream writer on which events will be invoked.
+ * @return {@link BindingStreamEventWriter} which will write to supplied {@link NormalizedNodeStreamWriter}.
+ */
+ @Nonnull
+ BindingStreamEventWriter newActionInputWriter(@Nonnull Class<? extends Action<?, ?, ?>> action,
+ @Nonnull NormalizedNodeStreamWriter domWriter);
+
+ /**
+ * Creates a {@link BindingStreamEventWriter} for action output which will translate to NormalizedNode model
+ * and invoke proper events on supplied {@link NormalizedNodeStreamWriter}.
+ *
+ * @param action Binding class representing action for which writer should be instantiated
+ * @param domWriter Stream writer on which events will be invoked.
+ * @return {@link BindingStreamEventWriter} which will write to supplied {@link NormalizedNodeStreamWriter}.
+ */
+ @Nonnull
+ BindingStreamEventWriter newActionOutputWriter(@Nonnull Class<? extends Action<?, ?, ?>> action,
+ @Nonnull NormalizedNodeStreamWriter domWriter);
}
--- /dev/null
+/*
+ * Copyright (c) 2018 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.mdsal.binding.dom.codec.impl;
+
+import static java.util.Objects.requireNonNull;
+
+import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
+
+/**
+ * This is not really a codec context, but rather a holder of input and output codec contexts.
+ */
+final class ActionCodecContext {
+ private final DataContainerCodecContext<?, ContainerSchemaNode> input;
+ private final DataContainerCodecContext<?, ContainerSchemaNode> output;
+
+ ActionCodecContext(final DataContainerCodecContext<?, ContainerSchemaNode> input,
+ final DataContainerCodecContext<?, ContainerSchemaNode> output) {
+ this.input = requireNonNull(input);
+ this.output = requireNonNull(output);
+ }
+
+ DataContainerCodecContext<?, ContainerSchemaNode> input() {
+ return input;
+ }
+
+ DataContainerCodecContext<?, ContainerSchemaNode> output() {
+ return output;
+ }
+}
import org.opendaylight.yangtools.concepts.Codec;
import org.opendaylight.yangtools.concepts.Immutable;
import org.opendaylight.yangtools.util.ClassLoaderUtils;
+import org.opendaylight.yangtools.yang.binding.Action;
import org.opendaylight.yangtools.yang.binding.BindingMapping;
import org.opendaylight.yangtools.yang.binding.BindingStreamEventWriter;
import org.opendaylight.yangtools.yang.binding.DataContainer;
return root.getRpc(path);
}
+ ActionCodecContext getActionCodec(final Class<? extends Action<?, ?, ?>> action) {
+ return root.getAction(action);
+ }
+
@Override
public ImmutableMap<String, LeafNodeCodecContext<?>> getLeafNodes(final Class<?> parentClass,
final DataNodeContainer childSchema) {
*/
package org.opendaylight.mdsal.binding.dom.codec.impl;
+import static java.util.Objects.requireNonNull;
+
import com.google.common.base.Function;
import com.google.common.base.Optional;
import com.google.common.base.Preconditions;
import java.util.ArrayList;
import java.util.List;
import java.util.Map.Entry;
+import java.util.function.BiFunction;
+import org.eclipse.jdt.annotation.NonNullByDefault;
import org.opendaylight.mdsal.binding.dom.codec.api.BindingCodecTree;
import org.opendaylight.mdsal.binding.dom.codec.api.BindingCodecTreeFactory;
+import org.opendaylight.mdsal.binding.dom.codec.api.BindingLazyContainerNode;
import org.opendaylight.mdsal.binding.dom.codec.api.BindingNormalizedNodeSerializer;
import org.opendaylight.mdsal.binding.dom.codec.api.BindingNormalizedNodeWriterFactory;
import org.opendaylight.mdsal.binding.dom.codec.gen.impl.DataObjectSerializerGenerator;
+import org.opendaylight.mdsal.binding.dom.codec.util.AbstractBindingLazyContainerNode;
import org.opendaylight.mdsal.binding.generator.impl.ModuleInfoBackedContext;
import org.opendaylight.mdsal.binding.generator.util.BindingRuntimeContext;
import org.opendaylight.yangtools.concepts.Delegator;
+import org.opendaylight.yangtools.yang.binding.Action;
import org.opendaylight.yangtools.yang.binding.BindingStreamEventWriter;
import org.opendaylight.yangtools.yang.binding.DataContainer;
import org.opendaylight.yangtools.yang.binding.DataObject;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.PathArgument;
import org.opendaylight.yangtools.yang.binding.Notification;
+import org.opendaylight.yangtools.yang.binding.RpcInput;
+import org.opendaylight.yangtools.yang.binding.RpcOutput;
import org.opendaylight.yangtools.yang.binding.util.BindingReflections;
import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
import org.opendaylight.yangtools.yang.data.api.schema.ChoiceNode;
import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
import org.opendaylight.yangtools.yang.data.api.schema.LeafNode;
@Override
public ContainerNode toNormalizedNodeNotification(final Notification data) {
- final NormalizedNodeResult result = new NormalizedNodeResult();
- // We create DOM stream writer which produces normalized nodes
- final NormalizedNodeStreamWriter domWriter = ImmutableNormalizedNodeStreamWriter.from(result);
- @SuppressWarnings({ "unchecked", "rawtypes" })
- final Class<? extends DataObject> type = (Class) data.getImplementedInterface();
- @SuppressWarnings({ "unchecked", "rawtypes" })
- final BindingStreamEventWriter writer = newNotificationWriter((Class) type, domWriter);
- try {
- // FIXME: Should be cast to DataObject necessary?
- getSerializer(type).serialize((DataObject) data, writer);
- } catch (final IOException e) {
- LOG.error("Unexpected failure while serializing data {}", data, e);
- throw new IllegalStateException("Failed to create normalized node", e);
- }
- return (ContainerNode) result.getResult();
-
+ // FIXME: Should the cast to DataObject be necessary?
+ return serializeDataObject((DataObject) data,
+ // javac does not like a methodhandle here
+ (iface, domWriter) -> newNotificationWriter(iface.asSubclass(Notification.class), domWriter));
}
@Override
public ContainerNode toNormalizedNodeRpcData(final DataContainer data) {
+ // FIXME: Should the cast to DataObject be necessary?
+ return serializeDataObject((DataObject) data, this::newRpcWriter);
+ }
+
+ @Override
+ public ContainerNode toNormalizedNodeActionInput(final Class<? extends Action<?, ?, ?>> action,
+ final RpcInput input) {
+ return serializeDataObject(input, (iface, domWriter) -> newActionInputWriter(action, domWriter));
+ }
+
+ @Override
+ public ContainerNode toNormalizedNodeActionOutput(final Class<? extends Action<?, ?, ?>> action,
+ final RpcOutput output) {
+ return serializeDataObject(output, (iface, domWriter) -> newActionOutputWriter(action, domWriter));
+ }
+
+ @Override
+ public BindingLazyContainerNode<RpcInput> toLazyNormalizedNodeActionInput(
+ final Class<? extends Action<?, ?, ?>> action, final NodeIdentifier identifier, final RpcInput input) {
+ return new LazyActionInputContainerNode(identifier, input, this, action);
+ }
+
+ @Override
+ public BindingLazyContainerNode<RpcOutput> toLazyNormalizedNodeActionOutput(
+ final Class<? extends Action<?, ?, ?>> action, final NodeIdentifier identifier, final RpcOutput output) {
+ return new LazyActionOutputContainerNode(identifier, output, this, action);
+ }
+
+ private <T extends DataContainer> ContainerNode serializeDataObject(final DataObject data,
+ final BiFunction<Class<? extends T>, NormalizedNodeStreamWriter, BindingStreamEventWriter> newWriter) {
final NormalizedNodeResult result = new NormalizedNodeResult();
// We create DOM stream writer which produces normalized nodes
final NormalizedNodeStreamWriter domWriter = ImmutableNormalizedNodeStreamWriter.from(result);
- @SuppressWarnings({ "unchecked", "rawtypes" })
- final Class<? extends DataObject> type = (Class) data.getImplementedInterface();
- final BindingStreamEventWriter writer = newRpcWriter(type, domWriter);
+ @SuppressWarnings("unchecked")
+ final Class<? extends DataObject> type = (Class<? extends DataObject>) data.getImplementedInterface();
+ final BindingStreamEventWriter writer = newWriter.apply((Class<T>)type, domWriter);
try {
- // FIXME: Should be cast to DataObject necessary?
- getSerializer(type).serialize((DataObject) data, writer);
+ getSerializer(type).serialize(data, writer);
} catch (final IOException e) {
LOG.error("Unexpected failure while serializing data {}", data, e);
throw new IllegalStateException("Failed to create normalized node", e);
return codec.deserialize(data);
}
+ @Override
+ public <T extends RpcInput> T fromNormalizedNodeActionInput(final Class<? extends Action<?, ?, ?>> action,
+ final ContainerNode input) {
+ return (T) requireNonNull(codecContext.getActionCodec(action).input().deserialize(requireNonNull(input)));
+ }
+
+ @Override
+ public <T extends RpcOutput> T fromNormalizedNodeActionOutput(final Class<? extends Action<?, ?, ?>> action,
+ final ContainerNode output) {
+ return (T) requireNonNull(codecContext.getActionCodec(action).output().deserialize(requireNonNull(output)));
+ }
+
@Override
public Entry<YangInstanceIdentifier, BindingStreamEventWriter> newWriterAndIdentifier(
final InstanceIdentifier<?> path, final NormalizedNodeStreamWriter domWriter) {
return codecContext.newNotificationWriter(notification, streamWriter);
}
+ @Override
+ public BindingStreamEventWriter newActionInputWriter(final Class<? extends Action<?, ?, ?>> action,
+ final NormalizedNodeStreamWriter domWriter) {
+ return codecContext.getActionCodec(action).input().createWriter(domWriter);
+ }
+
+ @Override
+ public BindingStreamEventWriter newActionOutputWriter(final Class<? extends Action<?, ?, ?>> action,
+ final NormalizedNodeStreamWriter domWriter) {
+ return codecContext.getActionCodec(action).output().createWriter(domWriter);
+ }
+
@Override
public BindingStreamEventWriter newRpcWriter(final Class<? extends DataContainer> rpcInputOrOutput,
final NormalizedNodeStreamWriter streamWriter) {
@SuppressWarnings("unchecked")
@Override
public Optional<T> apply(final Optional<NormalizedNode<?, ?>> input) {
- if (input.isPresent()) {
- return Optional.of((T) ctx.deserialize(input.get()));
- }
- return Optional.absent();
+ return input.transform(data -> (T) ctx.deserialize(data));
}
}
private final class GeneratorLoader extends CacheLoader<Class<? extends DataContainer>, DataObjectSerializer> {
@Override
- public DataObjectSerializer load(final Class<? extends DataContainer> key) throws Exception {
+ public DataObjectSerializer load(final Class<? extends DataContainer> key) {
final DataObjectSerializerImplementation prototype = generator.getSerializer(key);
return new DataObjectSerializerProxy(prototype);
}
delegate.serialize(BindingNormalizedNodeCodecRegistry.this, obj, stream);
}
}
+
+ @NonNullByDefault
+ private abstract static class AbstractLazyActionContainerNode<T extends DataObject>
+ extends AbstractBindingLazyContainerNode<T, BindingNormalizedNodeCodecRegistry> {
+ protected final Class<? extends Action<?, ?, ?>> action;
+
+ AbstractLazyActionContainerNode(final NodeIdentifier identifier, final T bindingData,
+ final BindingNormalizedNodeCodecRegistry context, final Class<? extends Action<?, ?, ?>> action) {
+ super(identifier, bindingData, context);
+ this.action = requireNonNull(action);
+ }
+ }
+
+ @NonNullByDefault
+ private static final class LazyActionInputContainerNode extends AbstractLazyActionContainerNode<RpcInput> {
+ LazyActionInputContainerNode(final NodeIdentifier identifier, final RpcInput bindingData,
+ final BindingNormalizedNodeCodecRegistry context, final Class<? extends Action<?, ?, ?>> action) {
+ super(identifier, bindingData, context, action);
+ }
+
+ @Override
+ protected ContainerNode computeContainerNode(final BindingNormalizedNodeCodecRegistry context) {
+ return context.toNormalizedNodeActionInput(action, getDataObject());
+ }
+ }
+
+ @NonNullByDefault
+ private static final class LazyActionOutputContainerNode extends AbstractLazyActionContainerNode<RpcOutput> {
+ LazyActionOutputContainerNode(final NodeIdentifier identifier, final RpcOutput bindingData,
+ final BindingNormalizedNodeCodecRegistry context, final Class<? extends Action<?, ?, ?>> action) {
+ super(identifier, bindingData, context, action);
+ }
+
+ @Override
+ protected ContainerNode computeContainerNode(final BindingNormalizedNodeCodecRegistry context) {
+ return context.toNormalizedNodeActionOutput(action, getDataObject());
+ }
+ }
}
*/
package org.opendaylight.mdsal.binding.dom.codec.impl;
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Verify.verify;
+
import com.google.common.base.Optional;
-import com.google.common.base.Preconditions;
import com.google.common.base.Throwables;
import com.google.common.base.Verify;
import com.google.common.cache.CacheBuilder;
import com.google.common.util.concurrent.UncheckedExecutionException;
import java.lang.reflect.Type;
import java.util.List;
+import org.opendaylight.yangtools.util.ClassLoaderUtils;
+import org.opendaylight.yangtools.yang.binding.Action;
import org.opendaylight.yangtools.yang.binding.BindingMapping;
import org.opendaylight.yangtools.yang.binding.ChoiceIn;
import org.opendaylight.yangtools.yang.binding.DataContainer;
import org.opendaylight.yangtools.yang.binding.DataObject;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
import org.opendaylight.yangtools.yang.binding.Notification;
+import org.opendaylight.yangtools.yang.binding.RpcInput;
+import org.opendaylight.yangtools.yang.binding.RpcOutput;
import org.opendaylight.yangtools.yang.binding.util.BindingReflections;
import org.opendaylight.yangtools.yang.common.QName;
import org.opendaylight.yangtools.yang.common.QNameModule;
import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.model.api.ActionDefinition;
import org.opendaylight.yangtools.yang.model.api.ChoiceSchemaNode;
import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
}
});
+ private final LoadingCache<Class<? extends Action<?, ?, ?>>, ActionCodecContext> actionsByClass = CacheBuilder
+ .newBuilder().build(new CacheLoader<Class<? extends Action<?, ?, ?>>, ActionCodecContext>() {
+ @Override
+ public ActionCodecContext load(final Class<? extends Action<?, ?, ?>> key) {
+ return createActionContext(key);
+ }
+ });
+
private final LoadingCache<Class<?>, ContainerNodeCodecContext<?>> rpcDataByClass = CacheBuilder.newBuilder().build(
new CacheLoader<Class<?>, ContainerNodeCodecContext<?>>() {
@Override
throw new UnsupportedOperationException("Could not create Binding data representation for root");
}
+ ActionCodecContext getAction(final Class<? extends Action<?, ?, ?>> action) {
+ return getOrRethrow(actionsByClass, action);
+ }
+
NotificationCodecContext<?> getNotification(final Class<? extends Notification> notification) {
return getOrRethrow(notificationsByClass, notification);
}
return DataContainerCodecPrototype.from(key, childSchema, factory()).get();
}
+ ActionCodecContext createActionContext(final Class<? extends Action<?, ?, ?>> action) {
+ final Type[] args = ClassLoaderUtils.findParameterizedType(action, Action.class).getActualTypeArguments();
+ checkArgument(args.length == 3, "Unexpected (%s) Action generatic arguments", args.length);
+
+ final ActionDefinition schema = factory().getRuntimeContext().getActionDefinition(action);
+ return new ActionCodecContext(
+ DataContainerCodecPrototype.from(asClass(args[1], RpcInput.class), schema.getInput(), factory()).get(),
+ DataContainerCodecPrototype.from(asClass(args[2], RpcOutput.class), schema.getOutput(), factory()).get());
+ }
+
+ private static <T extends DataObject> Class<? extends T> asClass(final Type type, final Class<T> target) {
+ verify(type instanceof Class, "Type %s is not a class", type);
+ return ((Class<?>) type).asSubclass(target);
+ }
+
ContainerNodeCodecContext<?> createRpcDataContext(final Class<?> key) {
- Preconditions.checkArgument(DataContainer.class.isAssignableFrom(key));
+ checkArgument(DataContainer.class.isAssignableFrom(key));
final QName qname = BindingReflections.findQName(key);
final QNameModule qnameModule = qname.getModule();
final Module module = getSchema().findModule(qnameModule)
break;
}
}
- Preconditions.checkArgument(rpc != null, "Supplied class %s is not valid RPC class.", key);
+ checkArgument(rpc != null, "Supplied class %s is not valid RPC class.", key);
final ContainerSchemaNode schema = SchemaNodeUtils.getRpcDataSchema(rpc, qname);
- Preconditions.checkArgument(schema != null, "Schema for %s does not define input / output.", rpc.getQName());
+ checkArgument(schema != null, "Schema for %s does not define input / output.", rpc.getQName());
return (ContainerNodeCodecContext<?>) DataContainerCodecPrototype.from(key, schema, factory()).get();
}
NotificationCodecContext<?> createNotificationDataContext(final Class<?> notificationType) {
- Preconditions.checkArgument(Notification.class.isAssignableFrom(notificationType));
- Preconditions.checkArgument(notificationType.isInterface(), "Supplied class must be interface.");
+ checkArgument(Notification.class.isAssignableFrom(notificationType));
+ checkArgument(notificationType.isInterface(), "Supplied class must be interface.");
final QName qname = BindingReflections.findQName(notificationType);
/**
* FIXME: After Lithium cleanup of yang-model-api, use direct call on schema context
*/
final NotificationDefinition schema = SchemaContextUtil.getNotificationSchema(getSchema(),
SchemaPath.create(true, qname));
- Preconditions.checkArgument(schema != null, "Supplied %s is not valid notification", notificationType);
+ checkArgument(schema != null, "Supplied %s is not valid notification", notificationType);
return new NotificationCodecContext<>(notificationType, schema, factory());
}
ChoiceNodeCodecContext<?> createChoiceDataContext(final Class<? extends DataObject> caseType) {
final Class<?> choiceClass = findCaseChoice(caseType);
- Preconditions.checkArgument(choiceClass != null, "Class %s is not a valid case representation", caseType);
+ checkArgument(choiceClass != null, "Class %s is not a valid case representation", caseType);
final DataSchemaNode schema = factory().getRuntimeContext().getSchemaDefinition(choiceClass);
- Preconditions.checkArgument(schema instanceof ChoiceSchemaNode, "Class %s does not refer to a choice",
- caseType);
+ checkArgument(schema instanceof ChoiceSchemaNode, "Class %s does not refer to a choice", caseType);
final DataContainerCodecContext<?, ChoiceSchemaNode> choice = DataContainerCodecPrototype.from(choiceClass,
(ChoiceSchemaNode)schema, factory()).get();
@Override
public InstanceIdentifier.PathArgument deserializePathArgument(final YangInstanceIdentifier.PathArgument arg) {
- Preconditions.checkArgument(arg == null);
+ checkArgument(arg == null);
return null;
}
@Override
public YangInstanceIdentifier.PathArgument serializePathArgument(final InstanceIdentifier.PathArgument arg) {
- Preconditions.checkArgument(arg == null);
+ checkArgument(arg == null);
return null;
}
this.context = context;
}
+ @Override
public final @NonNull T getDataObject() {
return bindingData;
}
return delegate().getChild(child);
}
+ @Override
+ public int hashCode() {
+ return delegate().hashCode();
+ }
+
+ @Override
+ public boolean equals(final @Nullable Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (!(obj instanceof ContainerNode)) {
+ return false;
+ }
+ final ContainerNode other = (ContainerNode) obj;
+ return delegate().equals(obj);
+ }
+
@Override
protected final @NonNull ContainerNode delegate() {
ContainerNode local = delegate;
--- /dev/null
+/*
+ * Copyright (c) 2018 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.mdsal.binding.dom.codec.test;
+
+import static org.junit.Assert.assertEquals;
+import static org.opendaylight.yangtools.yang.common.YangConstants.operationInputQName;
+import static org.opendaylight.yangtools.yang.common.YangConstants.operationOutputQName;
+import static org.opendaylight.yangtools.yang.data.impl.schema.Builders.containerBuilder;
+import static org.opendaylight.yangtools.yang.data.impl.schema.Builders.leafBuilder;
+
+import org.junit.Test;
+import org.opendaylight.yang.gen.v1.urn.odl.actions.norev.cont.Foo;
+import org.opendaylight.yang.gen.v1.urn.odl.actions.norev.cont.foo.InputBuilder;
+import org.opendaylight.yang.gen.v1.urn.odl.actions.norev.cont.foo.OutputBuilder;
+import org.opendaylight.yang.gen.v1.urn.odl.actions.norev.grpcont.Bar;
+import org.opendaylight.yangtools.yang.binding.RpcInput;
+import org.opendaylight.yangtools.yang.binding.RpcOutput;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
+
+public class ActionSerializeDeserializeTest extends AbstractBindingCodecTest {
+ private static final NodeIdentifier FOO_INPUT = NodeIdentifier.create(operationInputQName(Foo.QNAME.getModule()));
+ private static final NodeIdentifier FOO_OUTPUT = NodeIdentifier.create(operationOutputQName(Foo.QNAME.getModule()));
+ private static final NodeIdentifier FOO_XYZZY = NodeIdentifier.create(QName.create(Foo.QNAME, "xyzzy"));
+ private static final ContainerNode DOM_FOO_INPUT = containerBuilder().withNodeIdentifier(FOO_INPUT)
+ .withChild(leafBuilder().withNodeIdentifier(FOO_XYZZY).withValue("xyzzy").build())
+ .build();
+ private static final ContainerNode DOM_FOO_OUTPUT = containerBuilder().withNodeIdentifier(FOO_OUTPUT).build();
+ private static final RpcInput BINDING_FOO_INPUT = new InputBuilder().setXyzzy("xyzzy").build();
+ private static final RpcOutput BINDING_FOO_OUTPUT = new OutputBuilder().build();
+
+ private static final NodeIdentifier BAR_INPUT = NodeIdentifier.create(operationInputQName(Foo.QNAME.getModule()));
+ private static final NodeIdentifier BAR_OUTPUT = NodeIdentifier.create(operationOutputQName(Foo.QNAME.getModule()));
+ private static final NodeIdentifier BAR_XYZZY = NodeIdentifier.create(QName.create(Bar.QNAME, "xyzzy"));
+ private static final ContainerNode DOM_BAR_INPUT = containerBuilder().withNodeIdentifier(BAR_INPUT).build();
+ private static final ContainerNode DOM_BAR_OUTPUT = containerBuilder().withNodeIdentifier(BAR_OUTPUT)
+ .withChild(leafBuilder().withNodeIdentifier(BAR_XYZZY).withValue("xyzzy").build())
+ .build();
+ private static final RpcInput BINDING_BAR_INPUT =
+ new org.opendaylight.yang.gen.v1.urn.odl.actions.norev.grp.bar.InputBuilder().build();
+ private static final RpcOutput BINDING_BAR_OUTPUT =
+ new org.opendaylight.yang.gen.v1.urn.odl.actions.norev.grp.bar.OutputBuilder().setXyzzy("xyzzy").build();
+
+ @Test
+ public void testSerialization() {
+ assertEquals(DOM_FOO_INPUT, registry.toLazyNormalizedNodeActionInput(Foo.class, BINDING_FOO_INPUT)
+ .getDelegate());
+ assertEquals(DOM_BAR_INPUT, registry.toLazyNormalizedNodeActionInput(Bar.class, BINDING_BAR_INPUT)
+ .getDelegate());
+ assertEquals(DOM_FOO_OUTPUT, registry.toLazyNormalizedNodeActionOutput(Foo.class, BINDING_FOO_OUTPUT)
+ .getDelegate());
+ assertEquals(DOM_BAR_OUTPUT, registry.toLazyNormalizedNodeActionOutput(Bar.class, BINDING_BAR_OUTPUT)
+ .getDelegate());
+ }
+
+ @Test
+ public void testDeserialization() {
+ assertEquals(BINDING_FOO_INPUT, registry.fromNormalizedNodeActionInput(Foo.class, DOM_FOO_INPUT));
+ assertEquals(BINDING_BAR_INPUT, registry.fromNormalizedNodeActionInput(Bar.class, DOM_FOO_INPUT));
+ assertEquals(BINDING_FOO_OUTPUT, registry.fromNormalizedNodeActionOutput(Foo.class, DOM_FOO_OUTPUT));
+ assertEquals(BINDING_BAR_OUTPUT, registry.fromNormalizedNodeActionOutput(Bar.class, DOM_FOO_INPUT));
+ }
+}
container cont {
action foo {
-
+ input {
+ leaf xyzzy {
+ type string;
+ }
+ }
}
}
grouping grp {
action bar {
-
+ output {
+ leaf xyzzy {
+ type string;
+ }
+ }
}
}
* @return A FluentFuture which completes with the result of invocation
* @throws NullPointerException if any of the arguments is null
*/
- FluentFuture<DOMOperationResult> invokeAction(SchemaPath type, DOMDataTreeIdentifier path, ContainerNode input);
+ FluentFuture<? extends DOMOperationResult> invokeAction(SchemaPath type, DOMDataTreeIdentifier path,
+ ContainerNode input);
}
/**
* @return A FluentFuture which completes with the result of invocation
* @throws NullPointerException if any of the arguments is null
*/
- FluentFuture<DOMOperationResult> invokeRpc(QName type, ContainerNode input);
+ FluentFuture<? extends DOMOperationResult> invokeRpc(QName type, ContainerNode input);
}
/**