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>
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;
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(
}
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>> {
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>();
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();
return augmentations;
}
- public Map<Type, AugmentationSchema> getTypeToAugmentation() {
+ public BiMap<Type, AugmentationSchema> getTypeToAugmentation() {
return typeToAugmentation;
}
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
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
<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>
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();
}
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 {
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) {
--- /dev/null
+/*
+ * 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());
+ }
+
+}
--- /dev/null
+<?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&as=72&domain=673720360&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
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);
}