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.yangtools.yang.model.api.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
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)
@Property
var SchemaContext globalSchema;
-
+
@Property
var MountService mountService;
val modules = schema.modules.filter[m|m.name == moduleName]
return modules.filterLatestModule
}
-
+
private def filterLatestModule(Iterable<Module> modules) {
var latestModule = modules.head
for (module : modules) {
}
return latestModule
}
-
+
def findModuleByName(String moduleName) {
checkPreconditions
checkArgument(moduleName !== null && !moduleName.empty)
return globalSchema.getLatestModule(moduleName)
}
-
+
def findModuleByName(MountInstance mountPoint, String moduleName) {
checkArgument(moduleName !== null && mountPoint !== null)
val mountPointSchema = mountPoint.schemaContext;
return mountPointSchema?.getLatestModule(moduleName);
}
-
+
def findModuleByNamespace(URI namespace) {
checkPreconditions
checkArgument(namespace !== null)
val moduleSchemas = globalSchema.findModuleByNamespace(namespace)
return moduleSchemas?.filterLatestModule
}
-
+
def findModuleByNamespace(MountInstance mountPoint, URI namespace) {
checkArgument(namespace !== null && mountPoint !== null)
val mountPointSchema = mountPoint.schemaContext;
}
return moduleName
}
-
+
def findModuleNameByNamespace(MountInstance mountPoint, URI namespace) {
val module = mountPoint.findModuleByNamespace(namespace);
return module?.name
}
return namespace
}
-
+
def findNamespaceByModuleName(MountInstance mountPoint, String moduleName) {
val module = mountPoint.findModuleByName(moduleName)
return module?.namespace
if(object === null) return "";
return URLEncoder.encode(object.toString)
}
-
+
private def InstanceIdWithSchemaNode collectPathArguments(InstanceIdentifierBuilder builder, List<String> strings,
DataNodeContainer parentNode, MountInstance mountPoint) {
checkNotNull(strings)
if (strings.empty) {
return new InstanceIdWithSchemaNode(builder.toInstance, parentNode as DataSchemaNode, mountPoint)
}
-
+
val nodeName = strings.head.toNodeName
val moduleName = strings.head.toModuleName
var DataSchemaNode targetNode = null
if (mountPoint !== null) {
throw new ResponseException(BAD_REQUEST, "Restconf supports just one mount point in URI.")
}
-
+
if (mountService === null) {
- throw new ResponseException(SERVICE_UNAVAILABLE, "MountService was not found. "
+ throw new ResponseException(SERVICE_UNAVAILABLE, "MountService was not found. "
+ "Finding behind mount points does not work."
)
}
-
+
val partialPath = builder.toInstance;
val mount = mountService.getMountPoint(partialPath)
if (mount === null) {
LOG.debug("Instance identifier to missing mount point: {}", partialPath)
throw new ResponseException(BAD_REQUEST, "Mount point does not exist.")
}
-
+
val mountPointSchema = mount.schemaContext;
if (mountPointSchema === null) {
throw new ResponseException(BAD_REQUEST, "Mount point does not contain any schema with modules.")
}
-
+
if (strings.size == 1) { // any data node is not behind mount point
return new InstanceIdWithSchemaNode(InstanceIdentifier.builder().toInstance, mountPointSchema, mount)
}
-
+
val moduleNameBehindMountPoint = strings.get(1).toModuleName()
if (moduleNameBehindMountPoint === null) {
throw new ResponseException(BAD_REQUEST,
"First node after mount point in URI has to be in format \"moduleName:nodeName\"")
}
-
+
val moduleBehindMountPoint = mountPointSchema.getLatestModule(moduleNameBehindMountPoint)
if (moduleBehindMountPoint === null) {
throw new ResponseException(BAD_REQUEST,
"URI has bad format. \"" + moduleName + "\" module does not exist in mount point.")
}
-
+
return collectPathArguments(InstanceIdentifier.builder(), strings.subList(1, strings.size),
moduleBehindMountPoint, mount);
}
-
+
var Module module = null;
if (mountPoint === null) {
module = globalSchema.getLatestModule(moduleName)
"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" +
+ 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) {
// key value cannot be NULL
if (uriKeyValue.equals(NULL_VALUE)) {
- throw new ResponseException(BAD_REQUEST, "URI has bad format. List \"" + listNode.QName.localName
+ throw new ResponseException(BAD_REQUEST, "URI has bad format. List \"" + listNode.QName.localName
+ "\" cannot contain \"null\" value as a key."
)
}
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
default: return false
}
}
-
+
private def void addKeyValue(HashMap<QName, Object> map, DataSchemaNode node, String uriValue) {
checkNotNull(uriValue);
checkArgument(node instanceof LeafSchemaNode);
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)