Merge "Switched codecs infrastructure to use yang-data-impl codecs"
[controller.git] / opendaylight / md-sal / sal-rest-connector / src / main / java / org / opendaylight / controller / sal / restconf / impl / ControllerContext.xtend
index 882c73d001071dea11ee8bfb1d253887780a0875..eec2d452a178c15da2f0c70befa8c1367aae31eb 100644 (file)
@@ -1,6 +1,7 @@
 package org.opendaylight.controller.sal.restconf.impl
 
 import com.google.common.collect.BiMap
+import com.google.common.collect.FluentIterable
 import com.google.common.collect.HashBiMap
 import java.net.URI
 import java.net.URLDecoder
@@ -11,6 +12,7 @@ import java.util.Map
 import java.util.concurrent.ConcurrentHashMap
 import javax.ws.rs.core.Response
 import org.opendaylight.controller.sal.core.api.model.SchemaServiceListener
+import org.opendaylight.controller.sal.rest.impl.RestUtil
 import org.opendaylight.controller.sal.rest.impl.RestconfProvider
 import org.opendaylight.yangtools.yang.common.QName
 import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier
@@ -18,6 +20,7 @@ import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.InstanceIdent
 import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeIdentifier
 import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeIdentifierWithPredicates
 import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.PathArgument
+import org.opendaylight.yangtools.yang.data.impl.codec.TypeDefinitionAwareCodec
 import org.opendaylight.yangtools.yang.model.api.ChoiceCaseNode
 import org.opendaylight.yangtools.yang.model.api.ChoiceNode
 import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode
@@ -27,22 +30,21 @@ import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode
 import org.opendaylight.yangtools.yang.model.api.ListSchemaNode
 import org.opendaylight.yangtools.yang.model.api.RpcDefinition
 import org.opendaylight.yangtools.yang.model.api.SchemaContext
+import org.opendaylight.yangtools.yang.model.api.type.IdentityrefTypeDefinition
+import org.slf4j.LoggerFactory
 
 import static com.google.common.base.Preconditions.*
 
 class ControllerContext implements SchemaServiceListener {
-
+    val static LOG = LoggerFactory.getLogger(ControllerContext)
     val static ControllerContext INSTANCE = new ControllerContext
-
     val static NULL_VALUE = "null"
 
-    @Property
-    SchemaContext schemas;
+    var SchemaContext schemas;
 
     private val BiMap<URI, String> uriToModuleName = HashBiMap.create();
     private val Map<String, URI> moduleNameToUri = uriToModuleName.inverse();
-    private val Map<QName,RpcDefinition> qnameToRpc = new ConcurrentHashMap();
-    
+    private val Map<QName, RpcDefinition> qnameToRpc = new ConcurrentHashMap();
 
     private new() {
         if (INSTANCE !== null) {
@@ -53,13 +55,17 @@ class ControllerContext implements SchemaServiceListener {
     static def getInstance() {
         return INSTANCE
     }
-    
+
     private def void checkPreconditions() {
         if (schemas === null) {
             throw new ResponseException(Response.Status.SERVICE_UNAVAILABLE, RestconfProvider::NOT_INITALIZED_MSG)
         }
     }
 
+    def setSchemas(SchemaContext schemas) {
+        onGlobalContextUpdated(schemas)
+    }
+
     public def InstanceIdWithSchemaNode toInstanceIdentifier(String restconfInstance) {
         val ret = InstanceIdentifier.builder();
         val pathArgs = restconfInstance.split("/");
@@ -73,7 +79,7 @@ class ControllerContext implements SchemaServiceListener {
         if (schemaNode === null) {
             return null
         }
-        new InstanceIdWithSchemaNode(ret.toInstance, schemaNode)
+        return new InstanceIdWithSchemaNode(ret.toInstance, schemaNode)
     }
 
     private def findModule(String restconfInstance) {
@@ -85,13 +91,13 @@ class ControllerContext implements SchemaServiceListener {
         }
         val modulWithFirstYangStatement = pathArgs.filter[s|s.contains(":")].head
         val startModule = modulWithFirstYangStatement.toModuleName();
-        schemas.getLatestModule(startModule)
+        return getLatestModule(startModule)
     }
 
-    private def getLatestModule(SchemaContext schema, String moduleName) {
-        checkNotNull(schema)
+    def getLatestModule(String moduleName) {
+        checkPreconditions
         checkArgument(moduleName !== null && !moduleName.empty)
-        val modules = schema.modules.filter[m|m.name == moduleName]
+        val modules = schemas.modules.filter[m|m.name == moduleName]
         var latestModule = modules.head
         for (module : modules) {
             if (module.revision.after(latestModule.revision)) {
@@ -128,26 +134,43 @@ class ControllerContext implements SchemaServiceListener {
     private def dispatch CharSequence toRestconfIdentifier(PathArgument argument, DataSchemaNode node) {
         throw new IllegalArgumentException("Conversion of generic path argument is not supported");
     }
-    
+
     def findModuleByNamespace(URI namespace) {
         checkPreconditions
         var module = uriToModuleName.get(namespace)
         if (module === null) {
             val moduleSchemas = schemas.findModuleByNamespace(namespace);
-            if(moduleSchemas === null) throw new IllegalArgumentException()
+            if(moduleSchemas === null) return null
             var latestModule = moduleSchemas.head
             for (m : moduleSchemas) {
                 if (m.revision.after(latestModule.revision)) {
                     latestModule = m
                 }
             }
-            if(latestModule === null) throw new IllegalArgumentException()
+            if(latestModule === null) return null
             uriToModuleName.put(namespace, latestModule.name)
             module = latestModule.name;
         }
         return module
     }
 
+    def findNamespaceByModule(String module) {
+        var namespace = moduleNameToUri.get(module)
+        if (namespace === null) {
+            val moduleSchemas = schemas.modules.filter[it|it.name.equals(module)]
+            var latestModule = moduleSchemas.head
+            for (m : moduleSchemas) {
+                if (m.revision.after(latestModule.revision)) {
+                    latestModule = m
+                }
+            }
+            if(latestModule === null) return null
+            namespace = latestModule.namespace
+            uriToModuleName.put(namespace, latestModule.name)
+        }
+        return namespace
+    }
+
     def CharSequence toRestconfIdentifier(QName qname) {
         checkPreconditions
         var module = uriToModuleName.get(qname.namespace)
@@ -283,9 +306,17 @@ class ControllerContext implements SchemaServiceListener {
     private def void addKeyValue(HashMap<QName, Object> map, DataSchemaNode node, String uriValue) {
         checkNotNull(uriValue);
         checkArgument(node instanceof LeafSchemaNode);
-        val decoded = URLDecoder.decode(uriValue);
+        val urlDecoded = URLDecoder.decode(uriValue);
+        val typedef = (node as LeafSchemaNode).type;
+        
+        var decoded = TypeDefinitionAwareCodec.from(typedef)?.deserialize(urlDecoded)
+        if(decoded === null) {
+            var baseType = RestUtil.resolveBaseTypeFrom(typedef)
+            if(baseType instanceof IdentityrefTypeDefinition) {
+                decoded = toQName(urlDecoded)
+            }
+        }
         map.put(node.QName, decoded);
-
     }
 
     private def String toModuleName(String str) {
@@ -309,27 +340,25 @@ class ControllerContext implements SchemaServiceListener {
         }
     }
 
-    public def QName toQName(String name) {
+    private def QName toQName(String name) {
         val module = name.toModuleName;
         val node = name.toNodeName;
-        val namespace = moduleNameToUri.get(module);
-        return new QName(namespace,null,node);
+        val namespace = FluentIterable.from(schemas.modules.sort[o1,o2 | o1.revision.compareTo(o2.revision)]) //
+            .transform[QName.create(namespace,revision,it.name)].findFirst[module == localName]
+        ;
+        return QName.create(namespace,node);
+    }
+
+    def getRpcDefinition(String name) {
+        return qnameToRpc.get(name.toQName)
     }
 
     override onGlobalContextUpdated(SchemaContext context) {
         this.schemas = context;
-        for(operation : context.operations) {
-            val qname = new QName(operation.QName.namespace,null,operation.QName.localName);
-            qnameToRpc.put(qname,operation);
+        for (operation : context.operations) {
+            val qname = operation.QName;
+            qnameToRpc.put(qname, operation);
         }
     }
-    
-    def ContainerSchemaNode getRpcOutputSchema(QName name) {
-        qnameToRpc.get(name)?.output;
-    }
-    
-    def ContainerSchemaNode getRpcInputSchema(QName name) {
-        qnameToRpc.get(name)?.input;
-    }
 
 }