X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?p=controller.git;a=blobdiff_plain;f=opendaylight%2Fmd-sal%2Fsal-rest-connector%2Fsrc%2Fmain%2Fjava%2Forg%2Fopendaylight%2Fcontroller%2Fsal%2Frestconf%2Fimpl%2FControllerContext.xtend;h=308975c8c599a595d24f928cd6dbe4f4c76b8b9b;hp=c2b0ae8bdbb716580b1197108d0e91168b3d6ef0;hb=54bed4dd6dfbada9a8e2ddf70ca84952aec3f55a;hpb=2b1001dfcf3db4afe6ca8b028c84a83f11457ff6 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 c2b0ae8bdb..308975c8c5 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,6 +1,7 @@ package org.opendaylight.controller.sal.restconf.impl 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 @@ -9,9 +10,10 @@ import java.util.HashMap import java.util.List import java.util.Map import java.util.concurrent.ConcurrentHashMap -import javax.ws.rs.WebApplicationException import javax.ws.rs.core.Response import org.opendaylight.controller.sal.core.api.model.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 import org.opendaylight.yangtools.yang.common.QName import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier @@ -19,31 +21,38 @@ import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.InstanceIdent import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeIdentifier import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeIdentifierWithPredicates import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.PathArgument +import org.opendaylight.yangtools.yang.data.impl.codec.TypeDefinitionAwareCodec import org.opendaylight.yangtools.yang.model.api.ChoiceCaseNode import org.opendaylight.yangtools.yang.model.api.ChoiceNode import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode import org.opendaylight.yangtools.yang.model.api.DataNodeContainer import org.opendaylight.yangtools.yang.model.api.DataSchemaNode +import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode 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.type.IdentityrefTypeDefinition +import org.slf4j.LoggerFactory import static com.google.common.base.Preconditions.* +import java.util.ArrayList class ControllerContext implements SchemaServiceListener { - + val static LOG = LoggerFactory.getLogger(ControllerContext) val static ControllerContext INSTANCE = new ControllerContext - val static NULL_VALUE = "null" @Property - SchemaContext schemas; + var SchemaContext globalSchema; + + @Property + var MountService mountService; private val BiMap uriToModuleName = HashBiMap.create(); private val Map moduleNameToUri = uriToModuleName.inverse(); - private val Map qnameToRpc = new ConcurrentHashMap(); - + private val Map qnameToRpc = new ConcurrentHashMap(); private new() { if (INSTANCE !== null) { @@ -54,15 +63,19 @@ class ControllerContext implements SchemaServiceListener { static def getInstance() { return INSTANCE } - + private def void checkPreconditions() { - if (schemas === null) { - throw new WebApplicationException(Response.status(Response.Status.SERVICE_UNAVAILABLE) - .entity(RestconfProvider::NOT_INITALIZED_MSG).build()) + if (globalSchema === null) { + throw new ResponseException(Response.Status.SERVICE_UNAVAILABLE, RestconfProvider::NOT_INITALIZED_MSG) } } + def setSchemas(SchemaContext schemas) { + onGlobalContextUpdated(schemas) + } + public def InstanceIdWithSchemaNode toInstanceIdentifier(String restconfInstance) { + checkPreconditions val ret = InstanceIdentifier.builder(); val pathArgs = restconfInstance.split("/"); if (pathArgs.empty) { @@ -71,29 +84,28 @@ class ControllerContext implements SchemaServiceListener { if (pathArgs.head.empty) { pathArgs.remove(0) } - val schemaNode = ret.collectPathArguments(pathArgs, restconfInstance.findModule); + val mountPoints = new ArrayList + val schemaNode = ret.collectPathArguments(pathArgs, globalSchema.findModule(pathArgs.head), mountPoints); if (schemaNode === null) { return null } - new InstanceIdWithSchemaNode(ret.toInstance, schemaNode) + return new InstanceIdWithSchemaNode(ret.toInstance, schemaNode, mountPoints.last) } - private def findModule(String restconfInstance) { - checkPreconditions - checkNotNull(restconfInstance); - val pathArgs = restconfInstance.split("/"); - if (pathArgs.empty) { - return null; - } - val modulWithFirstYangStatement = pathArgs.filter[s|s.contains(":")].head - val startModule = modulWithFirstYangStatement.toModuleName(); - schemas.getLatestModule(startModule) + private def findModule(SchemaContext context,String argument) { + checkNotNull(argument); + val startModule = argument.toModuleName(); + return context.getLatestModule(startModule) } - - private def getLatestModule(SchemaContext schema, String moduleName) { - checkNotNull(schema) + + 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) { if (module.revision.after(latestModule.revision)) { @@ -102,13 +114,38 @@ 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; + return mountPointSchema?.getLatestModule(moduleName); + } + + def findModuleByNamespace(URI namespace) { + checkPreconditions + 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; + val moduleSchemas = mountPointSchema?.findModuleByNamespace(namespace) + return moduleSchemas?.filterLatestModule + } def String toFullRestconfIdentifier(InstanceIdentifier path) { checkPreconditions val elements = path.path; val ret = new StringBuilder(); val startQName = elements.get(0).nodeType; - val initialModule = schemas.findModuleByNamespaceAndRevision(startQName.namespace, startQName.revision) + val initialModule = globalSchema.findModuleByNamespaceAndRevision(startQName.namespace, startQName.revision) var node = initialModule as DataSchemaNode; for (element : elements) { node = node.childByQName(element.nodeType); @@ -131,11 +168,36 @@ class ControllerContext implements SchemaServiceListener { throw new IllegalArgumentException("Conversion of generic path argument is not supported"); } + 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; + } + return module + } + + def findNamespaceByModuleName(String module) { + var namespace = moduleNameToUri.get(module) + if (namespace === null) { + var latestModule = globalSchema.getLatestModule(module) + if(latestModule === null) return null + namespace = latestModule.namespace + uriToModuleName.put(namespace, latestModule.name) + } + return namespace + } + def CharSequence toRestconfIdentifier(QName qname) { checkPreconditions var module = uriToModuleName.get(qname.namespace) if (module === null) { - val moduleSchema = schemas.findModuleByNamespaceAndRevision(qname.namespace, qname.revision); + val moduleSchema = globalSchema.findModuleByNamespaceAndRevision(qname.namespace, qname.revision); if(moduleSchema === null) throw new IllegalArgumentException() uriToModuleName.put(qname.namespace, moduleSchema.name) module = moduleSchema.name; @@ -194,32 +256,36 @@ class ControllerContext implements SchemaServiceListener { } private def DataSchemaNode collectPathArguments(InstanceIdentifierBuilder builder, List strings, - DataNodeContainer parentNode) { + DataNodeContainer parentNode, List mountPoints) { checkNotNull(strings) + if (parentNode === null) { + return null; + } if (strings.empty) { return parentNode as DataSchemaNode; } val nodeRef = strings.head; - val nodeName = nodeRef.toNodeName(); - val targetNode = parentNode.getDataChildByName(nodeName); + val nodeName = nodeRef.toNodeName; + var targetNode = parentNode.findInstanceDataChild(nodeName); + if (targetNode instanceof ChoiceNode) { + return null + } + if (targetNode === null) { - val children = parentNode.childNodes - for (child : children) { - if (child instanceof ChoiceNode) { - val choice = child as ChoiceNode - for (caze : choice.cases) { - val result = builder.collectPathArguments(strings, caze as DataNodeContainer); - if (result !== null) - return result - } + // 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) } + return builder.collectPathArguments(strings, module, mountPoints); } return null } - if (targetNode instanceof ChoiceNode) { - return null - } + // Number of consumed elements var consumed = 1; @@ -253,22 +319,56 @@ class ControllerContext implements SchemaServiceListener { } if (targetNode instanceof DataNodeContainer) { val remaining = strings.subList(consumed, strings.length); - val result = builder.collectPathArguments(remaining, targetNode as DataNodeContainer); + val result = builder.collectPathArguments(remaining, targetNode as DataNodeContainer, mountPoints); return result } return targetNode } + + static def DataSchemaNode findInstanceDataChild(DataNodeContainer container, String name) { + // FIXME: Add namespace comparison + var potentialNode = container.getDataChildByName(name); + if(potentialNode.instantiatedDataSchema) { + return potentialNode; + } + val allCases = container.childNodes.filter(ChoiceNode).map[cases].flatten + for (caze : allCases) { + potentialNode = caze.findInstanceDataChild(name); + if(potentialNode !== null) { + return potentialNode; + } + } + return null; + } + + static def boolean isInstantiatedDataSchema(DataSchemaNode node) { + switch node { + LeafSchemaNode: return true + LeafListSchemaNode: return true + ContainerSchemaNode: return true + ListSchemaNode: return true + default: return false + } + } private def void addKeyValue(HashMap map, DataSchemaNode node, String uriValue) { checkNotNull(uriValue); checkArgument(node instanceof LeafSchemaNode); - val decoded = URLDecoder.decode(uriValue); + 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) + if(baseType instanceof IdentityrefTypeDefinition) { + decoded = toQName(urlDecoded) + } + } map.put(node.QName, decoded); - } - private def String toModuleName(String str) { + private static def String toModuleName(String str) { checkNotNull(str) if (str.contains(":")) { val args = str.split(":"); @@ -289,27 +389,25 @@ class ControllerContext implements SchemaServiceListener { } } - public def QName toQName(String name) { + private def QName toQName(String name) { val module = name.toModuleName; val node = name.toNodeName; - val namespace = moduleNameToUri.get(module); - return new QName(namespace,null,node); + val namespace = FluentIterable.from(globalSchema.modules.sort[o1,o2 | o1.revision.compareTo(o2.revision)]) // + .transform[QName.create(namespace,revision,it.name)].findFirst[module == localName] + ; + return QName.create(namespace,node); + } + + def getRpcDefinition(String name) { + return qnameToRpc.get(name.toQName) } override onGlobalContextUpdated(SchemaContext context) { - this.schemas = context; - for(operation : context.operations) { - val qname = new QName(operation.QName.namespace,null,operation.QName.localName); - qnameToRpc.put(qname,operation); + this.globalSchema = context; + for (operation : context.operations) { + val qname = operation.QName; + qnameToRpc.put(qname, operation); } } - - def ContainerSchemaNode getRpcOutputSchema(QName name) { - qnameToRpc.get(name)?.output; - } - - def ContainerSchemaNode getRpcInputSchema(QName name) { - qnameToRpc.get(name)?.input; - } }