X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=blobdiff_plain;f=opendaylight%2Fmd-sal%2Fsal-rest-connector%2Fsrc%2Fmain%2Fjava%2Forg%2Fopendaylight%2Fcontroller%2Fsal%2Frestconf%2Fimpl%2FControllerContext.xtend;fp=opendaylight%2Fmd-sal%2Fsal-rest-connector%2Fsrc%2Fmain%2Fjava%2Forg%2Fopendaylight%2Fcontroller%2Fsal%2Frestconf%2Fimpl%2FControllerContext.xtend;h=ced272e00b90cdb4e2b6996ead43d5967195d45f;hb=dcab45c7357f57e8642f2ea0a714c12386e4935e;hp=9a61b43df51467dbe76e40a6f10709e60089e4a0;hpb=b3ef17aee23bd6c6b36c0610bb7faa6a2d313be0;p=netconf.git diff --git a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/ControllerContext.xtend b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/ControllerContext.xtend index 9a61b43df5..ced272e00b 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/ControllerContext.xtend +++ b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/ControllerContext.xtend @@ -1,16 +1,18 @@ 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 @@ -32,12 +34,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) @@ -49,7 +51,7 @@ class ControllerContext implements SchemaServiceListener { @Property var SchemaContext globalSchema; - + @Property var MountService mountService; @@ -104,7 +106,7 @@ class ControllerContext implements SchemaServiceListener { val modules = schema.modules.filter[m|m.name == moduleName] return modules.filterLatestModule } - + private def filterLatestModule(Iterable modules) { var latestModule = modules.head for (module : modules) { @@ -114,26 +116,26 @@ class ControllerContext implements SchemaServiceListener { } 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; @@ -180,7 +182,7 @@ class ControllerContext implements SchemaServiceListener { } return moduleName } - + def findModuleNameByNamespace(MountInstance mountPoint, URI namespace) { val module = mountPoint.findModuleByNamespace(namespace); return module?.name @@ -196,7 +198,7 @@ class ControllerContext implements SchemaServiceListener { } return namespace } - + def findNamespaceByModuleName(MountInstance mountPoint, String moduleName) { val module = mountPoint.findModuleByName(moduleName) return module?.namespace @@ -263,7 +265,7 @@ class ControllerContext implements SchemaServiceListener { if(object === null) return ""; return URLEncoder.encode(object.toString) } - + private def InstanceIdWithSchemaNode collectPathArguments(InstanceIdentifierBuilder builder, List strings, DataNodeContainer parentNode, MountInstance mountPoint) { checkNotNull(strings) @@ -273,7 +275,7 @@ class ControllerContext implements SchemaServiceListener { 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 @@ -283,45 +285,45 @@ class ControllerContext implements SchemaServiceListener { 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) @@ -336,19 +338,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" + + 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) { @@ -367,7 +382,7 @@ class ControllerContext implements SchemaServiceListener { // 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." ) } @@ -390,28 +405,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 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 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,13 +443,13 @@ class ControllerContext implements SchemaServiceListener { default: return false } } - + private def void addKeyValue(HashMap 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)