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;h=9a61b43df51467dbe76e40a6f10709e60089e4a0;hb=065ef4acddbae75329e75562c533120d2d615efe;hp=308975c8c599a595d24f928cd6dbe4f4c76b8b9b;hpb=811583cee43dd5a0198acdb179ae9c80160ca65f;p=controller.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 308975c8c5..9a61b43df5 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 @@ -10,8 +10,7 @@ import java.util.HashMap import java.util.List 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.yangtools.yang.model.api.SchemaServiceListener 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 @@ -37,16 +36,20 @@ import org.opendaylight.yangtools.yang.model.api.type.IdentityrefTypeDefinition import org.slf4j.LoggerFactory import static com.google.common.base.Preconditions.* -import java.util.ArrayList +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) val static ControllerContext INSTANCE = new ControllerContext val static NULL_VALUE = "null" + val static MOUNT_MODULE = "yang-ext" + val static MOUNT_NODE = "mount" + public val static MOUNT = "yang-ext:mount" @Property var SchemaContext globalSchema; - + @Property var MountService mountService; @@ -66,7 +69,7 @@ class ControllerContext implements SchemaServiceListener { private def void checkPreconditions() { if (globalSchema === null) { - throw new ResponseException(Response.Status.SERVICE_UNAVAILABLE, RestconfProvider::NOT_INITALIZED_MSG) + throw new ResponseException(SERVICE_UNAVAILABLE, RestconfProvider::NOT_INITALIZED_MSG) } } @@ -76,7 +79,6 @@ class ControllerContext implements SchemaServiceListener { public def InstanceIdWithSchemaNode toInstanceIdentifier(String restconfInstance) { checkPreconditions - val ret = InstanceIdentifier.builder(); val pathArgs = restconfInstance.split("/"); if (pathArgs.empty) { return null; @@ -84,27 +86,25 @@ class ControllerContext implements SchemaServiceListener { if (pathArgs.head.empty) { pathArgs.remove(0) } - val mountPoints = new ArrayList - val schemaNode = ret.collectPathArguments(pathArgs, globalSchema.findModule(pathArgs.head), mountPoints); - if (schemaNode === null) { - return null + val startModule = pathArgs.head.toModuleName(); + if (startModule === null) { + throw new ResponseException(BAD_REQUEST, "First node in URI has to be in format \"moduleName:nodeName\"") + } + val iiWithSchemaNode = collectPathArguments(InstanceIdentifier.builder(), pathArgs, + globalSchema.getLatestModule(startModule), null); + if (iiWithSchemaNode === null) { + throw new ResponseException(BAD_REQUEST, "URI has bad format") } - return new InstanceIdWithSchemaNode(ret.toInstance, schemaNode, mountPoints.last) + return iiWithSchemaNode } - private def findModule(SchemaContext context,String argument) { - checkNotNull(argument); - val startModule = argument.toModuleName(); - return context.getLatestModule(startModule) - } - - private def getLatestModule(SchemaContext schema,String moduleName) { + private def getLatestModule(SchemaContext schema, String moduleName) { checkArgument(schema !== null); checkArgument(moduleName !== null && !moduleName.empty) 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,28 +114,29 @@ class ControllerContext implements SchemaServiceListener { } return latestModule } - + def findModuleByName(String moduleName) { checkPreconditions checkArgument(moduleName !== null && !moduleName.empty) return globalSchema.getLatestModule(moduleName) } - - def findModuleByName(String moduleName, InstanceIdentifier partialPath) { - checkArgument(moduleName !== null && !moduleName.empty && partialPath !== null && !partialPath.path.empty) - val mountPointSchema = mountService?.getMountPoint(partialPath)?.schemaContext; + + 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(URI namespace, InstanceIdentifier partialPath) { - checkArgument(namespace !== null && !namespace.toString.empty && partialPath !== null && !partialPath.path.empty) - val mountPointSchema = mountService?.getMountPoint(partialPath)?.schemaContext; + + def findModuleByNamespace(MountInstance mountPoint, URI namespace) { + checkArgument(namespace !== null && mountPoint !== null) + val mountPointSchema = mountPoint.schemaContext; val moduleSchemas = mountPointSchema?.findModuleByNamespace(namespace) return moduleSchemas?.filterLatestModule } @@ -170,29 +171,37 @@ class ControllerContext implements SchemaServiceListener { def findModuleNameByNamespace(URI namespace) { checkPreconditions - var module = uriToModuleName.get(namespace) - if (module === null) { - val moduleSchemas = globalSchema.findModuleByNamespace(namespace); - if(moduleSchemas === null) return null - var latestModule = moduleSchemas.filterLatestModule - if(latestModule === null) return null - uriToModuleName.put(namespace, latestModule.name) - module = latestModule.name; + var moduleName = uriToModuleName.get(namespace) + if (moduleName === null) { + val module = findModuleByNamespace(namespace) + if (module === null) return null + moduleName = module.name + uriToModuleName.put(namespace, moduleName) } - return module + return moduleName } - def findNamespaceByModuleName(String module) { - var namespace = moduleNameToUri.get(module) + def findModuleNameByNamespace(MountInstance mountPoint, URI namespace) { + val module = mountPoint.findModuleByNamespace(namespace); + return module?.name + } + + def findNamespaceByModuleName(String moduleName) { + var namespace = moduleNameToUri.get(moduleName) if (namespace === null) { - var latestModule = globalSchema.getLatestModule(module) - if(latestModule === null) return null - namespace = latestModule.namespace - uriToModuleName.put(namespace, latestModule.name) + var module = findModuleByName(moduleName) + if(module === null) return null + namespace = module.namespace + uriToModuleName.put(namespace, moduleName) } return namespace } + def findNamespaceByModuleName(MountInstance mountPoint, String moduleName) { + val module = mountPoint.findModuleByName(moduleName) + return module?.namespace + } + def CharSequence toRestconfIdentifier(QName qname) { checkPreconditions var module = uriToModuleName.get(qname.namespace) @@ -255,37 +264,90 @@ class ControllerContext implements SchemaServiceListener { return URLEncoder.encode(object.toString) } - private def DataSchemaNode collectPathArguments(InstanceIdentifierBuilder builder, List strings, - DataNodeContainer parentNode, List mountPoints) { + private def InstanceIdWithSchemaNode collectPathArguments(InstanceIdentifierBuilder builder, List strings, + DataNodeContainer parentNode, MountInstance mountPoint) { checkNotNull(strings) if (parentNode === null) { return null; } if (strings.empty) { - return parentNode as DataSchemaNode; + return new InstanceIdWithSchemaNode(builder.toInstance, parentNode as DataSchemaNode, mountPoint) } - val nodeRef = strings.head; - val nodeName = nodeRef.toNodeName; - var targetNode = parentNode.findInstanceDataChild(nodeName); - if (targetNode instanceof ChoiceNode) { - return null - } - - if (targetNode === null) { - // Node is possibly in other mount point - val partialPath = builder.toInstance; - val mountPointSchema = mountService?.getMountPoint(partialPath)?.schemaContext; - if(mountPointSchema !== null) { - val module = mountPointSchema.findModule(strings.head) - if (module !== null) { - mountPoints.add(partialPath) + val nodeName = strings.head.toNodeName + val moduleName = strings.head.toModuleName + var DataSchemaNode targetNode = null + if (!moduleName.nullOrEmpty) { + // if it is mount point + if (moduleName == MOUNT_MODULE && nodeName == MOUNT_NODE) { + 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. " + + "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.") } - return builder.collectPathArguments(strings, module, mountPoints); + + 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) + if (module === null) { + throw new ResponseException(BAD_REQUEST, + "URI has bad format. \"" + moduleName + "\" module does not exist.") + } + } else { + module = mountPoint.schemaContext?.getLatestModule(moduleName) + if (module === null) { + throw new ResponseException(BAD_REQUEST, + "URI has bad format. \"" + moduleName + "\" module does not exist in mount point.") + } + } + targetNode = parentNode.findInstanceDataChild(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) + if (targetNode === null) { + throw new ResponseException(BAD_REQUEST, "URI has bad format. \"" + nodeName + "\" was not found in parent data node.\n") } - return null } - // Number of consumed elements var consumed = 1; @@ -295,7 +357,7 @@ class ControllerContext implements SchemaServiceListener { // every key has to be filled if ((strings.length - consumed) < keysSize) { - return null; + throw new ResponseException(BAD_REQUEST,"Missing key for list \"" + listNode.QName.localName + "\".") } val uriKeyValues = strings.subList(consumed, consumed + keysSize); val keyValues = new HashMap(); @@ -305,7 +367,9 @@ class ControllerContext implements SchemaServiceListener { // key value cannot be NULL if (uriKeyValue.equals(NULL_VALUE)) { - return null + throw new ResponseException(BAD_REQUEST, "URI has bad format. List \"" + listNode.QName.localName + + "\" cannot contain \"null\" value as a key." + ) } keyValues.addKeyValue(listNode.getDataChildByName(key), uriKeyValue); i = i + 1; @@ -319,29 +383,34 @@ class ControllerContext implements SchemaServiceListener { } if (targetNode instanceof DataNodeContainer) { val remaining = strings.subList(consumed, strings.length); - val result = builder.collectPathArguments(remaining, targetNode as DataNodeContainer, mountPoints); + val result = builder.collectPathArguments(remaining, targetNode as DataNodeContainer, mountPoint); return result } - return targetNode + return new InstanceIdWithSchemaNode(builder.toInstance, targetNode, mountPoint) } - - static def DataSchemaNode findInstanceDataChild(DataNodeContainer container, String name) { - // FIXME: Add namespace comparison - var potentialNode = container.getDataChildByName(name); - if(potentialNode.instantiatedDataSchema) { + + 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; } val allCases = container.childNodes.filter(ChoiceNode).map[cases].flatten for (caze : allCases) { - potentialNode = caze.findInstanceDataChild(name); - if(potentialNode !== null) { + potentialNode = caze.findInstanceDataChild(name, moduleNamespace); + if (potentialNode !== null) { return potentialNode; } } return null; } - + static def boolean isInstantiatedDataSchema(DataSchemaNode node) { switch node { LeafSchemaNode: return true @@ -357,7 +426,7 @@ class ControllerContext implements SchemaServiceListener { 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) @@ -372,21 +441,21 @@ class ControllerContext implements SchemaServiceListener { checkNotNull(str) if (str.contains(":")) { val args = str.split(":"); - checkArgument(args.size === 2); - return args.get(0); - } else { - return null; + if (args.size === 2) { + return args.get(0); + } } + return null; } private def String toNodeName(String str) { if (str.contains(":")) { val args = str.split(":"); - checkArgument(args.size === 2); - return args.get(1); - } else { - return str; + if (args.size === 2) { + return args.get(1); + } } + return str; } private def QName toQName(String name) {