+ @Override
+ public YangInstanceIdentifier toYangInstanceIdentifier(final InstanceIdentifier<?> binding) {
+ return instanceIdentifierCodec.fromBinding(binding);
+ }
+
+ @Override
+ public <T extends DataObject> InstanceIdentifier<T> fromYangInstanceIdentifier(final YangInstanceIdentifier dom) {
+ return instanceIdentifierCodec.toBinding(dom);
+ }
+
+ @Override
+ public <T extends DataObject> Entry<YangInstanceIdentifier, NormalizedNode> toNormalizedNode(
+ final InstanceIdentifier<T> path, final T data) {
+ final NormalizedNodeResult result = new NormalizedNodeResult();
+ // We create DOM stream writer which produces normalized nodes
+ final NormalizedNodeStreamWriter domWriter = ImmutableNormalizedNodeStreamWriter.from(result);
+
+ // We create Binding Stream Writer which translates from Binding to Normalized Nodes
+ final Entry<YangInstanceIdentifier, BindingStreamEventWriter> writeCtx = newWriterAndIdentifier(path,
+ domWriter);
+
+ // We get serializer which reads binding data and uses Binding To Normalized Node writer to write result
+ try {
+ getSerializer(path.getTargetType()).serialize(data, writeCtx.getValue());
+ } catch (final IOException e) {
+ LOG.error("Unexpected failure while serializing path {} data {}", path, data, e);
+ throw new IllegalStateException("Failed to create normalized node", e);
+ }
+ return Map.entry(writeCtx.getKey(), result.getResult());
+ }
+
+ @Override
+ public Entry<InstanceIdentifier<?>, DataObject> fromNormalizedNode(final YangInstanceIdentifier path,
+ final NormalizedNode data) {
+ if (notBindingRepresentable(data)) {
+ return null;
+ }
+
+ final List<PathArgument> builder = new ArrayList<>();
+ final BindingDataObjectCodecTreeNode<?> codec = getCodecContextNode(path, builder);
+ if (codec == null) {
+ if (data != null) {
+ LOG.warn("Path {} does not have a binding equivalent, should have been caught earlier ({})", path,
+ data.getClass());
+ }
+ return null;
+ }
+
+ final DataObject lazyObj = codec.deserialize(data);
+ final InstanceIdentifier<?> bindingPath = InstanceIdentifier.unsafeOf(builder);
+ return Map.entry(bindingPath, lazyObj);
+ }
+
+ @Override
+ public BaseNotification fromNormalizedNodeNotification(final Absolute path, final ContainerNode data) {
+ return getNotificationContext(path).deserialize(data);
+ }
+
+ @Override
+ public BaseNotification fromNormalizedNodeNotification(final Absolute path, final ContainerNode data,
+ final Instant eventInstant) {
+ return eventInstant == null ? fromNormalizedNodeNotification(path, data)
+ : getNotificationContext(path).deserialize(data, eventInstant);
+ }
+
+ @Override
+ public DataObject fromNormalizedNodeRpcData(final Absolute containerPath, final ContainerNode data) {
+ return getRpcInputCodec(containerPath).deserialize(data);
+ }
+
+ @Override
+ public <T extends RpcInput> T fromNormalizedNodeActionInput(final Class<? extends Action<?, ?, ?>> action,
+ final ContainerNode input) {
+ return (T) requireNonNull(getActionCodec(action).input().deserialize(requireNonNull(input)));
+ }
+
+ @Override
+ public <T extends RpcOutput> T fromNormalizedNodeActionOutput(final Class<? extends Action<?, ?, ?>> action,
+ final ContainerNode output) {
+ return (T) requireNonNull(getActionCodec(action).output().deserialize(requireNonNull(output)));
+ }
+
+ @Override
+ @SuppressFBWarnings("BC_UNCONFIRMED_CAST")
+ public ContainerNode toNormalizedNodeNotification(final Notification<?> data) {
+ // FIXME: Should the cast to DataObject be necessary?
+ return serializeDataObject((DataObject) data,
+ (ctx, iface, domWriter) -> ctx.newNotificationWriter(
+ (Class<? extends Notification<?>>) iface.asSubclass(Notification.class), domWriter));
+ }
+
+ @Override
+ public ContainerNode toNormalizedNodeNotification(final Absolute path, final BaseNotification data) {
+ checkArgument(data instanceof DataObject, "Unexpected data %s", data);
+ @SuppressWarnings("rawtypes")
+ final NotificationCodecContext notifContext = getNotificationContext(path);
+ @SuppressWarnings("unchecked")
+ final var result = notifContext.serialize((DataObject) data);
+ verify(result instanceof ContainerNode, "Unexpected result %s from %s", result, data);
+ return (ContainerNode) result;
+ }
+
+ @Override
+ @SuppressFBWarnings("BC_UNCONFIRMED_CAST")
+ public ContainerNode toNormalizedNodeRpcData(final DataContainer data) {
+ // FIXME: Should the cast to DataObject be necessary?
+ return serializeDataObject((DataObject) data, BindingNormalizedNodeWriterFactory::newRpcWriter);
+ }
+
+ @Override
+ public ContainerNode toNormalizedNodeActionInput(final Class<? extends Action<?, ?, ?>> action,
+ final RpcInput input) {
+ return serializeDataObject(input,(ctx, iface, domWriter) -> ctx.newActionInputWriter(action, domWriter));
+ }
+
+ @Override
+ public ContainerNode toNormalizedNodeActionOutput(final Class<? extends Action<?, ?, ?>> action,
+ final RpcOutput output) {
+ return serializeDataObject(output, (ctx, iface, domWriter) -> ctx.newActionOutputWriter(action, domWriter));
+ }
+
+ private <T extends DataContainer> @NonNull ContainerNode serializeDataObject(final DataObject data,
+ final WriterFactoryMethod<T> newWriter) {
+ final NormalizedNodeResult result = new NormalizedNodeResult();
+ // We create DOM stream writer which produces normalized nodes
+ final NormalizedNodeStreamWriter domWriter = ImmutableNormalizedNodeStreamWriter.from(result);
+ final Class<? extends DataObject> type = data.implementedInterface();
+ @SuppressWarnings("unchecked")
+ final BindingStreamEventWriter writer = newWriter.createWriter(this, (Class<T>) type, domWriter);
+ try {
+ 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 (ContainerNode) result.getResult();
+ }
+
+
+ private static boolean notBindingRepresentable(final NormalizedNode data) {
+ // ValueNode covers LeafNode and LeafSetEntryNode
+ return data instanceof ValueNode
+ || data instanceof MapNode || data instanceof UnkeyedListNode
+ || data instanceof ChoiceNode
+ || data instanceof LeafSetNode;
+ }
+