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=2dfe5062c89af5b2f0151dfee3721d0ba7486521;hb=80887bb706a758b78cae70fcdb7531661139256c;hp=9a61b43df51467dbe76e40a6f10709e60089e4a0;hpb=07c30f447bd1366ba18e6f0f41ac768a16dbc901;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 9a61b43df5..2dfe5062c8 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,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.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 +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) @@ -49,7 +58,7 @@ class ControllerContext implements SchemaServiceListener { @Property var SchemaContext globalSchema; - + @Property var MountService mountService; @@ -104,7 +113,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 +123,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 +189,7 @@ class ControllerContext implements SchemaServiceListener { } return moduleName } - + def findModuleNameByNamespace(MountInstance mountPoint, URI namespace) { val module = mountPoint.findModuleByNamespace(namespace); return module?.name @@ -196,7 +205,7 @@ class ControllerContext implements SchemaServiceListener { } return namespace } - + def findNamespaceByModuleName(MountInstance mountPoint, String moduleName) { val module = mountPoint.findModuleByName(moduleName) return module?.namespace @@ -207,13 +216,20 @@ class ControllerContext implements SchemaServiceListener { var module = uriToModuleName.get(qname.namespace) if (module === null) { val moduleSchema = globalSchema.findModuleByNamespaceAndRevision(qname.namespace, qname.revision); - if(moduleSchema === null) throw new IllegalArgumentException() + if(moduleSchema === null) return null uriToModuleName.put(qname.namespace, moduleSchema.name) module = moduleSchema.name; } return '''«module»:«qname.localName»'''; } + def CharSequence toRestconfIdentifier(MountInstance mountPoint, QName qname) { + val moduleSchema = mountPoint?.schemaContext.findModuleByNamespaceAndRevision(qname.namespace, qname.revision); + if(moduleSchema === null) return null + val module = moduleSchema.name; + return '''«module»:«qname.localName»'''; + } + private static dispatch def DataSchemaNode childByQName(ChoiceNode container, QName name) { for (caze : container.cases) { val ret = caze.childByQName(name) @@ -263,7 +279,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 +289,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 +299,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 +352,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 +396,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 +419,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 +457,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)