Fix for Bug-427. 99/5399/6
authorMilos Fabian <milfabia@cisco.com>
Wed, 19 Feb 2014 00:10:36 +0000 (01:10 +0100)
committerMartin Vitez <mvitez@cisco.com>
Mon, 24 Feb 2014 15:02:35 +0000 (16:02 +0100)
Added test for mapping from dom (with nested augmenation nodes) to data object.
Added javadocs.

Change-Id: I0d0c08092c6485afb820d9bfbb352cf934f282f3
Signed-off-by: Martin Vitez <mvitez@cisco.com>
Signed-off-by: Milos Fabian <milfabia@cisco.com>
code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/impl/LazyGeneratedCodecRegistry.java
code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/impl/ModuleContext.java
code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/impl/RuntimeGeneratedMappingServiceImpl.xtend
restconf/restconf-util/pom.xml
restconf/restconf-util/src/main/java/org/opendaylight/yangtools/restconf/utils/RestconfUtils.java
restconf/restconf-util/src/test/java/org/opendaylight/yangtools/restconf/utils/RestconfUtilsTest.java [new file with mode: 0644]
restconf/restconf-util/src/test/resources/topology.xml [new file with mode: 0644]
yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/codec/BindingIndependentMappingService.java

index dee6ee6e1f731206c2862d1d35640c74cb16f783..8d64b9d5d788857396fd6e2302156314a125fd98 100644 (file)
@@ -80,6 +80,7 @@ public class LazyGeneratedCodecRegistry implements //
     private static final Map<SchemaPath, GeneratedTypeBuilder> pathToType = new ConcurrentHashMap<>();
     private static final Map<List<QName>, Type> pathToInstantiatedType = new ConcurrentHashMap<>();
     private static final Map<Type, QName> typeToQname = new ConcurrentHashMap<>();
+    private static final Map<AugmentationSchema, Type> augmentToType = new ConcurrentHashMap<>();
 
     private final SchemaLock lock;
 
@@ -382,6 +383,7 @@ public class LazyGeneratedCodecRegistry implements //
 
     public void onModuleContextAdded(SchemaContext schemaContext, Module module, ModuleContext context) {
         pathToType.putAll(context.getChildNodes());
+        augmentToType.putAll(context.getTypeToAugmentation().inverse());
         qnamesToIdentityMap.putAll(context.getIdentities());
         for (Entry<QName, GeneratedTOBuilder> identity : context.getIdentities().entrySet()) {
             typeToQname.put(
@@ -481,9 +483,48 @@ public class LazyGeneratedCodecRegistry implements //
         }
         ret = new AugmentableCompositeCodec(dataClass);
         augmentableCodecs.put(dataClass, ret);
+
+        Map<Type, SchemaNode> typeToSchemaNode = generator.getTypeToSchemaNode();
+        Type refType = new ReferencedTypeImpl(dataClass.getPackage().getName(), dataClass.getSimpleName());
+        SchemaNode node = typeToSchemaNode.get(refType);
+        tryToLoadAugmentations(node);
+
         return ret;
     }
 
+    private void tryToLoadAugmentations(SchemaNode schemaNode) {
+        if (schemaNode instanceof AugmentationTarget) {
+            AugmentationTarget augmentationTarget = (AugmentationTarget) schemaNode;
+            Set<AugmentationSchema> augments = augmentationTarget.getAvailableAugmentations();
+            Set<Type> augmentTypes = new HashSet<>();
+            if (augments != null) {
+                for (AugmentationSchema augment : augments) {
+                    Type augmentType = augmentToType.get(augment);
+                    if (augmentType == null) {
+                        LOG.warn("Failed to find type for augmentation of " + augment);
+                    }
+                    augmentTypes.add(augmentType);
+                }
+                for (Type augmentType : augmentTypes) {
+                    Class<? extends Augmentation<?>> clazz = null;
+                    try {
+                        clazz = (Class<? extends Augmentation<?>>) classLoadingStrategy.loadClass(augmentType);
+                    } catch (ClassNotFoundException e) {
+                        LOG.warn("Failed to find class for augmentation of " + augmentType);
+                    }
+                    getCodecForAugmentation(clazz);
+                }
+            }
+        }
+
+        if (schemaNode instanceof DataNodeContainer) {
+            Set<DataSchemaNode> childNodes = ((DataNodeContainer) schemaNode).getChildNodes();
+            for (DataSchemaNode child : childNodes) {
+                tryToLoadAugmentations(child);
+            }
+        }
+    }
+
     private static abstract class IntermediateCodec<T> implements //
             DomCodec<T>, Delegator<BindingCodec<Map<QName, Object>, Object>> {
 
index c57f6226fcda68b80df51dc47c413a159206f3f5..460349f74bb671f2674c4bc5a65fb3d9196df395 100644 (file)
@@ -21,6 +21,9 @@ import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.model.api.AugmentationSchema;
 import org.opendaylight.yangtools.yang.model.api.SchemaPath;
 
+import com.google.common.collect.BiMap;
+import com.google.common.collect.HashBiMap;
+
 public final class ModuleContext {
     private GeneratedTypeBuilder moduleNode;
     private final List<GeneratedTOBuilder> genTOs = new ArrayList<GeneratedTOBuilder>();
@@ -31,7 +34,7 @@ public final class ModuleContext {
     private final Map<QName,GeneratedTOBuilder> identities = new HashMap<>();
     private final Set<GeneratedTypeBuilder> topLevelNodes = new HashSet<GeneratedTypeBuilder>();
     private final List<GeneratedTypeBuilder> augmentations = new ArrayList<GeneratedTypeBuilder>();
-    private final Map<Type,AugmentationSchema> typeToAugmentation = new HashMap<>();
+    private final BiMap<Type,AugmentationSchema> typeToAugmentation = HashBiMap.create();
 
 
 
@@ -151,7 +154,7 @@ public final class ModuleContext {
         return augmentations;
     }
 
-    public Map<Type, AugmentationSchema> getTypeToAugmentation() {
+    public BiMap<Type, AugmentationSchema> getTypeToAugmentation() {
         return typeToAugmentation;
     }
 
index c4345ae7b50bab833097d3aefeaaecc1f062d094..b8d8ec2af16acd8acde60ba90601f5e618809aed 100644 (file)
@@ -38,7 +38,6 @@ import org.opendaylight.yangtools.yang.data.impl.codec.DataContainerCodec
 import org.opendaylight.yangtools.binding.generator.util.Types
 
 //import org.osgi.framework.BundleContext
-import java.util.Hashtable
 
 //import org.osgi.framework.ServiceRegistration
 import org.opendaylight.yangtools.yang.data.impl.codec.DeserializationException
@@ -56,8 +55,6 @@ import java.util.Set
 import org.opendaylight.yangtools.yang.common.QName
 import com.google.common.collect.FluentIterable
 import org.opendaylight.yangtools.binding.generator.util.BindingGeneratorUtil
-import java.util.HashMap
-import java.net.URI
 import org.opendaylight.yangtools.yang.model.api.Module
 import com.google.common.base.Optional
 import org.opendaylight.yangtools.yang.binding.BindingMapping
index 4a64093c670f7c5415b00aac390b0c7e7ef6251d..503cc774157a2884d6e3a83192a028dcc2a8dd1a 100644 (file)
           <groupId>commons-io</groupId>
           <artifactId>commons-io</artifactId>
       </dependency>
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.yangtools.model</groupId>
+            <artifactId>ietf-topology-isis</artifactId>
+            <version>2013.10.21.2-SNAPSHOT</version>
+            <scope>test</scope>
+        </dependency>
   </dependencies>
 </project>
index 6ee4b9a8f201542dfe605b7126edc4f84430439c..95f167bda0e32d6257341ada7d63d540eecd9ffe 100644 (file)
@@ -231,6 +231,18 @@ public class RestconfUtils {
         return moduleName;
     }
 
+    /**
+     * Parse rpc services from input stream.
+     *
+     * @param inputStream
+     *            stream containing rpc services definition in xml
+     *            representation
+     * @param mappingService
+     *            current mapping service
+     * @param schemaContext
+     *            parsed yang data context
+     * @return Set of classes representing rpc services parsed from input stream
+     */
     public static Set<Class<? extends RpcService>> rpcServicesFromInputStream(InputStream inputStream, BindingIndependentMappingService mappingService,SchemaContext schemaContext){
         try {
             DocumentBuilderFactory documentBuilder = DocumentBuilderFactory.newInstance();
@@ -276,6 +288,22 @@ public class RestconfUtils {
         }
         return null;
     }
+
+    /**
+     * Parse DataObject from input stream.
+     *
+     * @param path
+     *            identifier of expected result object
+     * @param inputStream
+     *            stream containing xml data to parse
+     * @param schemaContext
+     *            parsed yang data context
+     * @param mappingService
+     *            current mapping service
+     * @param dataSchema
+     *            yang data schema node representation of resulting data object
+     * @return DataObject instance parsed from input stream
+     */
     public static DataObject dataObjectFromInputStream(org.opendaylight.yangtools.yang.binding.InstanceIdentifier<?> path, InputStream inputStream, SchemaContext schemaContext, BindingIndependentMappingService mappingService, DataSchemaNode dataSchema) {
         // Parse stream into w3c Document
         try {
@@ -288,8 +316,7 @@ public class RestconfUtils {
             DataObject  dataObject = mappingService.dataObjectFromDataDom(path, (CompositeNode) domNode); //getDataFromResponse
             return dataObject;
         } catch (DeserializationException e) {
-
-
+            logger.trace("Deserialization exception {}",e);
         } catch (ParserConfigurationException e) {
             logger.trace("Parse configuration exception {}",e);
         } catch (SAXException e) {
diff --git a/restconf/restconf-util/src/test/java/org/opendaylight/yangtools/restconf/utils/RestconfUtilsTest.java b/restconf/restconf-util/src/test/java/org/opendaylight/yangtools/restconf/utils/RestconfUtilsTest.java
new file mode 100644 (file)
index 0000000..67bbf15
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. 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.restconf.utils;
+
+import static junit.framework.Assert.assertNotNull;
+import static org.junit.Assert.assertEquals;
+
+import java.io.InputStream;
+
+import javassist.ClassPool;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.isis.topology.rev131021.IgpNodeAttributes1;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TopologyId;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.nt.l3.unicast.igp.topology.rev131021.Node1;
+import org.opendaylight.yangtools.sal.binding.generator.impl.ModuleInfoBackedContext;
+import org.opendaylight.yangtools.sal.binding.generator.impl.RuntimeGeneratedMappingServiceImpl;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.binding.util.BindingReflections;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+
+public class RestconfUtilsTest {
+
+    private RuntimeGeneratedMappingServiceImpl mappingService;
+
+    @Before
+    public void setup() {
+        this.mappingService = new RuntimeGeneratedMappingServiceImpl();
+        this.mappingService.setPool(new ClassPool());
+        this.mappingService.init();
+
+        final ModuleInfoBackedContext moduleInfo = ModuleInfoBackedContext.create();
+        moduleInfo.addModuleInfos(BindingReflections.loadModuleInfos());
+        this.mappingService.onGlobalContextUpdated(moduleInfo.tryToCreateSchemaContext().get());
+    }
+
+    @Test
+    public void testToDataObjectMappingWithNestedAugmentations() {
+        final InstanceIdentifier<Topology> topologyIdentifier = InstanceIdentifier.builder(NetworkTopology.class)
+                .child(Topology.class, new TopologyKey(new TopologyId("topology"))).toInstance();
+        final InputStream is = this.getClass().getClassLoader().getResourceAsStream("topology.xml");
+        final DataSchemaNode dataSchema = RestconfUtils.toRestconfIdentifier(topologyIdentifier, this.mappingService,
+                this.mappingService.getSchemaContext()).getValue();
+        final Topology topology = (Topology) RestconfUtils.dataObjectFromInputStream(topologyIdentifier, is,
+                this.mappingService.getSchemaContext(), this.mappingService, dataSchema);
+
+        assertNotNull(topology);
+        assertEquals(1, topology.getNode().size());
+        final Node node = topology.getNode().get(0);
+        assertEquals("bgpls://IsisLevel2:1/type=node&as=72&domain=673720360&router=0000.0000.0042", node.getNodeId()
+                .getValue());
+
+        final Node1 node1 = node.getAugmentation(Node1.class);
+        assertNotNull(node1);
+        assertNotNull(node1.getIgpNodeAttributes());
+        assertEquals("Of-9k-02", node1.getIgpNodeAttributes().getName().getValue());
+
+        final IgpNodeAttributes1 igpAttributes1 = node1.getIgpNodeAttributes()
+                .getAugmentation(IgpNodeAttributes1.class);
+        assertNotNull(igpAttributes1);
+        assertNotNull(igpAttributes1.getIsisNodeAttributes());
+        assertEquals("66", igpAttributes1.getIsisNodeAttributes().getIso().getIsoSystemId().getValue());
+    }
+
+}
diff --git a/restconf/restconf-util/src/test/resources/topology.xml b/restconf/restconf-util/src/test/resources/topology.xml
new file mode 100644 (file)
index 0000000..47756de
--- /dev/null
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<topology xmlns="urn:TBD:params:xml:ns:yang:network-topology">
+    <node>
+        <node-id>bgpls://IsisLevel2:1/type=node&amp;as=72&amp;domain=673720360&amp;router=0000.0000.0042</node-id>
+        <igp-node-attributes xmlns="urn:TBD:params:xml:ns:yang:nt:l3-unicast-igp-topology">
+            <name>Of-9k-02</name>
+            <router-id>42.42.42.42</router-id>
+            <isis-node-attributes xmlns="urn:TBD:params:xml:ns:yang:network:isis-topology">
+                <iso>
+                    <iso-system-id>66</iso-system-id>
+                </iso>
+                <ted>
+                    <te-router-id-ipv4>42.42.42.42</te-router-id-ipv4>
+                </ted>
+            </isis-node-attributes>
+        </igp-node-attributes>
+    </node>
+</topology>
\ No newline at end of file
index f4294b0889cc94ab51bb8cdf4798976042f18452..7d6dd678b16a25d07c83548041d51e0122dc5be7 100644 (file)
@@ -21,29 +21,97 @@ import com.google.common.base.Optional;
 
 public interface BindingIndependentMappingService {
 
+    /**
+     * Get codec registry.
+     *
+     * @return codec registry
+     */
     CodecRegistry getCodecRegistry();
 
+    /**
+     * Convert given DataObject data to DOM-like node.
+     *
+     * @param data
+     *            DataObject instance
+     * @return CompositeNode created from DataObject instance
+     */
     CompositeNode toDataDom(DataObject data);
 
+    /**
+     * Create map entry representing node data (key = data schema node
+     * identifier, value = value is node data representation as Composite node)
+     * from entry representing node class (key = class object identifier, value
+     * = class object).
+     *
+     * @param entry
+     *            map entry, where key is class object identifier and value
+     *            class object
+     * @return data schema node identifier
+     */
     Entry<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, CompositeNode> toDataDom(
             Entry<InstanceIdentifier<? extends DataObject>, DataObject> entry);
 
+    /**
+     * Create data schema node identifier from class object identifier.
+     *
+     * @param path
+     *            class object identifier
+     * @return data schema node identifier
+     */
     org.opendaylight.yangtools.yang.data.api.InstanceIdentifier toDataDom(InstanceIdentifier<? extends DataObject> path);
 
-    DataObject dataObjectFromDataDom(InstanceIdentifier<? extends DataObject> path, CompositeNode result) throws DeserializationException;
+    /**
+     * Create DataObject instance from CompositeNode data based on given path.
+     *
+     * @param path
+     *            node identifier
+     * @param result
+     *            node data
+     * @return inputClass instance created from composite node input
+     */
+    DataObject dataObjectFromDataDom(InstanceIdentifier<? extends DataObject> path, CompositeNode result)
+            throws DeserializationException;
 
-    InstanceIdentifier<?> fromDataDom(org.opendaylight.yangtools.yang.data.api.InstanceIdentifier entry)  throws DeserializationException;
+    /**
+     * Create class object identifier from data schema node identifier.
+     *
+     * @param entry
+     *            data schema node identifier
+     * @return class object identifier
+     */
+    InstanceIdentifier<?> fromDataDom(org.opendaylight.yangtools.yang.data.api.InstanceIdentifier entry)
+            throws DeserializationException;
 
     /**
      * Returns the list of currently-known QNames for instances of a service.
      *
-     * @param service RPC service
+     * @param service
+     *            RPC service
      * @return List of QNames. The user may not modify this list.
      */
     Set<QName> getRpcQNamesFor(Class<? extends RpcService> service);
 
+    /**
+     * Get RpcService by namespace and revision.
+     *
+     * @param namespace
+     *            rpc service namespace
+     * @param revision
+     *            rpc service revision
+     * @return Optional reference on RpcServices based on given namespace and
+     *         revision
+     */
     Optional<Class<? extends RpcService>> getRpcServiceClassFor(String namespace, String revision);
 
+    /**
+     * Create inputClass instance from CompositeNode data.
+     *
+     * @param inputClass
+     *            expected type of resulting object
+     * @param domInput
+     *            node data
+     * @return inputClass instance created from composite node input
+     */
     DataContainer dataObjectFromDataDom(Class<? extends DataContainer> inputClass, CompositeNode domInput);
 
 }