Merge "Prevent ConfigPusher from killing its thread"
[controller.git] / opendaylight / md-sal / sal-rest-connector / src / main / java / org / opendaylight / controller / sal / restconf / impl / ControllerContext.xtend
index d0099bb3980f50ecd5fb59813a1ea0c795a62117..7d32194b1f386ca1a7e228ea25de24dbf6dc15e1 100644 (file)
@@ -1,16 +1,25 @@
+/*
+ * 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.controller.sal.restconf.impl
 
+import com.google.common.base.Preconditions
 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
 import java.net.URLEncoder
+import java.util.ArrayList
 import java.util.HashMap
 import java.util.List
 import java.util.Map
 import java.util.concurrent.ConcurrentHashMap
-import org.opendaylight.controller.sal.core.api.model.SchemaServiceListener
+import org.opendaylight.controller.sal.core.api.mount.MountInstance
 import org.opendaylight.controller.sal.core.api.mount.MountService
 import org.opendaylight.controller.sal.rest.impl.RestUtil
 import org.opendaylight.controller.sal.rest.impl.RestconfProvider
@@ -32,12 +41,12 @@ import org.opendaylight.yangtools.yang.model.api.ListSchemaNode
 import org.opendaylight.yangtools.yang.model.api.Module
 import org.opendaylight.yangtools.yang.model.api.RpcDefinition
 import org.opendaylight.yangtools.yang.model.api.SchemaContext
+import org.opendaylight.yangtools.yang.model.api.SchemaServiceListener
 import org.opendaylight.yangtools.yang.model.api.type.IdentityrefTypeDefinition
 import org.slf4j.LoggerFactory
 
 import static com.google.common.base.Preconditions.*
 import static javax.ws.rs.core.Response.Status.*
-import org.opendaylight.controller.sal.core.api.mount.MountInstance
 
 class ControllerContext implements SchemaServiceListener {
     val static LOG = LoggerFactory.getLogger(ControllerContext)
@@ -45,7 +54,7 @@ class ControllerContext implements SchemaServiceListener {
     val static NULL_VALUE = "null"
     val static MOUNT_MODULE = "yang-ext"
     val static MOUNT_NODE = "mount"
-    val static MOUNT = "yang-ext:mount"
+    public val static MOUNT = "yang-ext:mount"
 
     @Property
     var SchemaContext globalSchema;
@@ -336,19 +345,32 @@ class ControllerContext implements SchemaServiceListener {
                         "URI has bad format. \"" + moduleName + "\" module does not exist in mount point.")
                 }
             }
-            targetNode = parentNode.findInstanceDataChild(nodeName, module.namespace)
+            targetNode = parentNode.findInstanceDataChildByNameAndNamespace(nodeName, module.namespace)
             if (targetNode === null) {
                 throw new ResponseException(BAD_REQUEST, "URI has bad format. Possible reasons:\n" + 
                     "1. \"" + strings.head + "\" was not found in parent data node.\n" + 
                     "2. \"" + strings.head + "\" is behind mount point. Then it should be in format \"/" + MOUNT + "/" + strings.head + "\".")
             }
         } else { // string without module name
-            targetNode = parentNode.findInstanceDataChild(nodeName, null)
+            val potentialSchemaNodes = parentNode.findInstanceDataChildrenByName(nodeName)
+            if (potentialSchemaNodes.size > 1) {
+                val StringBuilder namespacesOfPotentialModules = new StringBuilder;
+                for (potentialNodeSchema : potentialSchemaNodes) {
+                    namespacesOfPotentialModules.append("   ").append(potentialNodeSchema.QName.namespace.toString).append("\n")
+                }
+                throw new ResponseException(BAD_REQUEST, "URI has bad format. Node \"" + nodeName + "\" is added as augment from more than one module. " 
+                        + "Therefore the node must have module name and it has to be in format \"moduleName:nodeName\"."
+                        + "\nThe node is added as augment from modules with namespaces:\n" + namespacesOfPotentialModules)
+            }
+            targetNode = potentialSchemaNodes.head
             if (targetNode === null) {
                 throw new ResponseException(BAD_REQUEST, "URI has bad format. \"" + nodeName + "\" was not found in parent data node.\n")
             }
         }
         
+        if (!(targetNode instanceof ListSchemaNode) && !(targetNode instanceof ContainerSchemaNode)) {
+            throw new ResponseException(BAD_REQUEST,"URI has bad format. Node \"" + strings.head + "\" must be Container or List yang type.")
+        }
         // Number of consumed elements
         var consumed = 1;
         if (targetNode instanceof ListSchemaNode) {
@@ -390,28 +412,36 @@ class ControllerContext implements SchemaServiceListener {
         return new InstanceIdWithSchemaNode(builder.toInstance, targetNode, mountPoint)
     }
 
-    def DataSchemaNode findInstanceDataChild(DataNodeContainer container, String name, URI moduleNamespace) {
-        var DataSchemaNode potentialNode = null
-        if (moduleNamespace === null) {
-            potentialNode = container.getDataChildByName(name);
-        } else {
-            potentialNode = container.childNodes.filter[n|n.QName.localName == name && n.QName.namespace == moduleNamespace].head
-        }
-        
-        if (potentialNode.instantiatedDataSchema) {
-            return potentialNode;
+    def DataSchemaNode findInstanceDataChildByNameAndNamespace(DataNodeContainer container,
+        String name, URI namespace) {
+        Preconditions.checkNotNull(namespace)
+        val potentialSchemaNodes = container.findInstanceDataChildrenByName(name)
+        return potentialSchemaNodes.filter[n|n.QName.namespace == namespace].head
+    }
+    
+    def List<DataSchemaNode> findInstanceDataChildrenByName(DataNodeContainer container, String name) {
+        Preconditions.checkNotNull(container)
+        Preconditions.checkNotNull(name)
+        val instantiatedDataNodeContainers = new ArrayList
+        instantiatedDataNodeContainers.collectInstanceDataNodeContainers(container, name)
+        return instantiatedDataNodeContainers
+    }
+    
+    private def void collectInstanceDataNodeContainers(List<DataSchemaNode> potentialSchemaNodes, DataNodeContainer container,
+        String name) {
+        val nodes = container.childNodes.filter[n|n.QName.localName == name]
+        for (potentialNode : nodes) {
+            if (potentialNode.isInstantiatedDataSchema) {
+                potentialSchemaNodes.add(potentialNode)
+            }
         }
         val allCases = container.childNodes.filter(ChoiceNode).map[cases].flatten
         for (caze : allCases) {
-            potentialNode = caze.findInstanceDataChild(name, moduleNamespace);
-            if (potentialNode !== null) {
-                return potentialNode;
-            }
+            collectInstanceDataNodeContainers(potentialSchemaNodes, caze, name)
         }
-        return null;
     }
     
-    static def boolean isInstantiatedDataSchema(DataSchemaNode node) {
+    def boolean isInstantiatedDataSchema(DataSchemaNode node) {
         switch node {
             LeafSchemaNode: return true
             LeafListSchemaNode: return true
@@ -420,7 +450,7 @@ class ControllerContext implements SchemaServiceListener {
             default: return false
         }
     }
-
+    
     private def void addKeyValue(HashMap<QName, Object> map, DataSchemaNode node, String uriValue) {
         checkNotNull(uriValue);
         checkArgument(node instanceof LeafSchemaNode);