Merge "BUG-869: added proper handling of nullable parameter"
[yangtools.git] / code-generator / binding-data-codec / src / main / java / org / opendaylight / yangtools / binding / data / codec / impl / BindingNormalizedNodeCodecRegistry.java
index ffac120d8ee9dd182a2e26c76e2267b4da06e430..bfdad3efeb4cb555a22946a035ae460a8592698a 100644 (file)
@@ -7,13 +7,16 @@
  */
 package org.opendaylight.yangtools.binding.data.codec.impl;
 
+import com.google.common.base.Function;
+import com.google.common.base.Optional;
 import com.google.common.base.Preconditions;
 import com.google.common.cache.CacheBuilder;
 import com.google.common.cache.CacheLoader;
 import com.google.common.cache.LoadingCache;
 
+import java.io.IOException;
 import java.util.AbstractMap.SimpleEntry;
-import java.util.LinkedList;
+import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
@@ -29,13 +32,23 @@ import org.opendaylight.yangtools.yang.binding.DataObjectSerializer;
 import org.opendaylight.yangtools.yang.binding.DataObjectSerializerImplementation;
 import org.opendaylight.yangtools.yang.binding.DataObjectSerializerRegistry;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.PathArgument;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.ChoiceNode;
+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.MapNode;
 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.data.api.schema.UnkeyedListNode;
 import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter;
 import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNormalizedNodeStreamWriter;
 import org.opendaylight.yangtools.yang.data.impl.schema.NormalizedNodeResult;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 public class BindingNormalizedNodeCodecRegistry implements DataObjectSerializerRegistry, BindingNormalizedNodeWriterFactory, BindingNormalizedNodeSerializer {
+    private static final Logger LOG = LoggerFactory.getLogger(BindingNormalizedNodeCodecRegistry.class);
 
     private final DataObjectSerializerGenerator generator;
     private final LoadingCache<Class<? extends DataObject>, DataObjectSerializer> serializers;
@@ -63,39 +76,78 @@ public class BindingNormalizedNodeCodecRegistry implements DataObjectSerializerR
 
     @Override
     public YangInstanceIdentifier toYangInstanceIdentifier(final InstanceIdentifier<?> binding) {
-        List<YangInstanceIdentifier.PathArgument> builder = new LinkedList<>();
-        codecContext.getCodecContextNode(binding, builder);
         return codecContext.getInstanceIdentifierCodec().serialize(binding);
     }
 
     @Override
     public InstanceIdentifier<?> fromYangInstanceIdentifier(final YangInstanceIdentifier dom) {
         return codecContext.getInstanceIdentifierCodec().deserialize(dom);
-   }
+    }
 
     @Override
     public <T extends DataObject> Entry<YangInstanceIdentifier,NormalizedNode<?,?>> toNormalizedNode(final InstanceIdentifier<T> path, final T data) {
         NormalizedNodeResult result = new NormalizedNodeResult();
-        // We create dom stream writer which produces normalized nodes
+        // We create DOM stream writer which produces normalized nodes
         NormalizedNodeStreamWriter domWriter = ImmutableNormalizedNodeStreamWriter.from(result);
 
-        // We create Binding Stream Writer wchich translates from Binding to Normalized Nodes
+        // We create Binding Stream Writer which translates from Binding to Normalized Nodes
         Entry<YangInstanceIdentifier, BindingStreamEventWriter> writeCtx = codecContext.newWriter(path, domWriter);
 
-        // We get serializer which reads binding data and uses Binding To NOrmalized Node writer to write result
-        getSerializer(path.getTargetType()).serialize(data, writeCtx.getValue());
+        // 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 (IOException e) {
+            LOG.error("Unexpected failure while serializing path {} data {}", path, data, e);
+            throw new IllegalStateException("Failed to create normalized node", e);
+        }
         return new SimpleEntry<YangInstanceIdentifier,NormalizedNode<?,?>>(writeCtx.getKey(),result.getResult());
     }
 
+    private static boolean isBindingRepresentable(final NormalizedNode<?, ?> data) {
+        if (data instanceof ChoiceNode) {
+            return false;
+        }
+        if (data instanceof LeafNode<?>) {
+            return false;
+        }
+        if (data instanceof LeafSetNode) {
+            return false;
+        }
+        if( data instanceof LeafSetEntryNode<?>) {
+            return false;
+        }
+        if (data instanceof MapNode) {
+            return false;
+        }
+        if (data instanceof UnkeyedListNode) {
+            return false;
+        }
+
+        return true;
+    }
+
     @Override
-    public Entry<InstanceIdentifier<?>, DataObject> fromNormalizedNode(final YangInstanceIdentifier path,
-            final NormalizedNode<?, ?> data) {
-        throw new UnsupportedOperationException("Not implemented yet");
+    public Entry<InstanceIdentifier<?>, DataObject> fromNormalizedNode(final YangInstanceIdentifier path, final NormalizedNode<?, ?> data) {
+        if (!isBindingRepresentable(data)) {
+            return null;
+        }
+
+        final List<PathArgument> builder = new ArrayList<>();
+        final NodeCodecContext codec = codecContext.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 = (DataObject) codec.dataFromNormalizedNode(data);
+        final InstanceIdentifier<?> bindingPath = InstanceIdentifier.create(builder);
+        return new SimpleEntry<InstanceIdentifier<?>, DataObject>(bindingPath, lazyObj);
     }
 
     @Override
-    public Map<InstanceIdentifier<?>, DataObject> fromNormalizedNodes(
-            final Map<YangInstanceIdentifier, NormalizedNode<?, ?>> dom) {
+    public Map<InstanceIdentifier<?>, DataObject> fromNormalizedNodes(final Map<YangInstanceIdentifier, NormalizedNode<?, ?>> dom) {
         throw new UnsupportedOperationException("Not implemented yet");
     }
 
@@ -109,6 +161,31 @@ public class BindingNormalizedNodeCodecRegistry implements DataObjectSerializerR
         return codecContext.newWriterWithoutIdentifier(path, domWriter);
     }
 
+
+    public <T extends DataObject> Function<Optional<NormalizedNode<?, ?>>, Optional<T>>  deserializeFunction(final InstanceIdentifier<T> path) {
+        DataObjectCodecContext<?> ctx = (DataObjectCodecContext<?>) codecContext.getCodecContextNode(path, null);
+        return new DeserializeFunction<T>(ctx);
+    }
+
+
+    private static class DeserializeFunction<T> implements Function<Optional<NormalizedNode<?, ?>>, Optional<T>> {
+        private final DataObjectCodecContext<?> ctx;
+
+        public DeserializeFunction(final DataObjectCodecContext<?> ctx) {
+            super();
+            this.ctx = ctx;
+        }
+
+        @SuppressWarnings("unchecked")
+        @Override
+        public Optional<T> apply(final Optional<NormalizedNode<?, ?>> input) {
+            if(input.isPresent()) {
+                return Optional.of((T) ctx.dataFromNormalizedNode(input.get()));
+            }
+            return Optional.absent();
+        }
+    }
+
     private class GeneratorLoader extends CacheLoader<Class<? extends DataObject>, DataObjectSerializer> {
 
         @Override
@@ -133,7 +210,7 @@ public class BindingNormalizedNodeCodecRegistry implements DataObjectSerializerR
         }
 
         @Override
-        public void serialize(final DataObject obj, final BindingStreamEventWriter stream) {
+        public void serialize(final DataObject obj, final BindingStreamEventWriter stream) throws IOException {
             delegate.serialize(BindingNormalizedNodeCodecRegistry.this, obj, stream);
         }
     }