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=fed56fe297a8ed9cc929437329701799ce06ccfb;hb=03abf047ba966c53f4901d36ae5198156d66dc05;hp=419ca50ee995a032e5a63b3dc7ea1f50d79ba50e;hpb=25563418e1867be44ab8d829db30360df60ee1c9;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 419ca50ee9..fed56fe297 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 @@ -8,6 +8,10 @@ import java.net.URLEncoder 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.controller.sal.rest.impl.RestconfProvider import org.opendaylight.yangtools.yang.common.QName import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.InstanceIdentifierBuilder @@ -21,18 +25,47 @@ import org.opendaylight.yangtools.yang.model.api.DataNodeContainer import org.opendaylight.yangtools.yang.model.api.DataSchemaNode import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode import org.opendaylight.yangtools.yang.model.api.ListSchemaNode +import org.opendaylight.yangtools.yang.model.api.RpcDefinition import org.opendaylight.yangtools.yang.model.api.SchemaContext +import org.opendaylight.yangtools.yang.model.api.SchemaNode +import org.opendaylight.yangtools.yang.model.api.type.LeafrefTypeDefinition +import org.opendaylight.yangtools.yang.model.util.SchemaContextUtil import static com.google.common.base.Preconditions.* -import java.util.Date +import org.opendaylight.yangtools.yang.data.impl.codec.TypeDefinitionAwareCodec +import org.opendaylight.yangtools.yang.model.api.type.IdentityrefTypeDefinition -class ControllerContext { +class ControllerContext implements SchemaServiceListener { - @Property - SchemaContext schemas; + val static ControllerContext INSTANCE = new ControllerContext + + val static NULL_VALUE = "null" + + var SchemaContext schemas; private val BiMap uriToModuleName = HashBiMap.create(); private val Map moduleNameToUri = uriToModuleName.inverse(); + private val Map qnameToRpc = new ConcurrentHashMap(); + + private new() { + if (INSTANCE !== null) { + throw new IllegalStateException("Already instantiated"); + } + } + + static def getInstance() { + return INSTANCE + } + + private def void checkPreconditions() { + if (schemas === null) { + throw new ResponseException(Response.Status.SERVICE_UNAVAILABLE, RestconfProvider::NOT_INITALIZED_MSG) + } + } + + def setSchemas(SchemaContext schemas) { + onGlobalContextUpdated(schemas) + } public def InstanceIdWithSchemaNode toInstanceIdentifier(String restconfInstance) { val ret = InstanceIdentifier.builder(); @@ -40,11 +73,18 @@ class ControllerContext { if (pathArgs.empty) { return null; } + if (pathArgs.head.empty) { + pathArgs.remove(0) + } val schemaNode = ret.collectPathArguments(pathArgs, restconfInstance.findModule); - new InstanceIdWithSchemaNode(ret.toInstance, schemaNode) + if (schemaNode === null) { + return null + } + return new InstanceIdWithSchemaNode(ret.toInstance, schemaNode) } - def findModule(String restconfInstance) { + private def findModule(String restconfInstance) { + checkPreconditions checkNotNull(restconfInstance); val pathArgs = restconfInstance.split("/"); if (pathArgs.empty) { @@ -52,13 +92,13 @@ class ControllerContext { } val modulWithFirstYangStatement = pathArgs.filter[s|s.contains(":")].head val startModule = modulWithFirstYangStatement.toModuleName(); - schemas.getLatestModule(startModule) + return getLatestModule(startModule) } - private def getLatestModule(SchemaContext schema, String moduleName) { - checkNotNull(schema) - checkArgument(moduleName != null && !moduleName.empty) - val modules = schema.modules.filter[m|m.name == moduleName] + private def getLatestModule(String moduleName) { + checkPreconditions + checkArgument(moduleName !== null && !moduleName.empty) + val modules = schemas.modules.filter[m|m.name == moduleName] var latestModule = modules.head for (module : modules) { if (module.revision.after(latestModule.revision)) { @@ -69,6 +109,7 @@ class ControllerContext { } def String toFullRestconfIdentifier(InstanceIdentifier path) { + checkPreconditions val elements = path.path; val ret = new StringBuilder(); val startQName = elements.get(0).nodeType; @@ -95,11 +136,31 @@ class ControllerContext { throw new IllegalArgumentException("Conversion of generic path argument is not supported"); } - public def CharSequence toRestconfIdentifier(QName qname) { + def findModuleByNamespace(URI namespace) { + checkPreconditions + var module = uriToModuleName.get(namespace) + if (module === null) { + val moduleSchemas = schemas.findModuleByNamespace(namespace); + if(moduleSchemas === null) throw new IllegalArgumentException() + var latestModule = moduleSchemas.head + for (m : moduleSchemas) { + if (m.revision.after(latestModule.revision)) { + latestModule = m + } + } + if(latestModule === null) throw new IllegalArgumentException() + uriToModuleName.put(namespace, latestModule.name) + module = latestModule.name; + } + return module + } + + def CharSequence toRestconfIdentifier(QName qname) { + checkPreconditions var module = uriToModuleName.get(qname.namespace) - if (module == null) { + if (module === null) { val moduleSchema = schemas.findModuleByNamespaceAndRevision(qname.namespace, qname.revision); - if(moduleSchema == null) throw new IllegalArgumentException() + if(moduleSchema === null) throw new IllegalArgumentException() uriToModuleName.put(qname.namespace, moduleSchema.name) module = moduleSchema.name; } @@ -152,22 +213,38 @@ class ControllerContext { } private def toUriString(Object object) { - if(object == null) return ""; + if(object === null) return ""; return URLEncoder.encode(object.toString) } - def DataSchemaNode collectPathArguments(InstanceIdentifierBuilder builder, List strings, + private def DataSchemaNode collectPathArguments(InstanceIdentifierBuilder builder, List strings, DataNodeContainer parentNode) { checkNotNull(strings) + if (parentNode === null) { + return null; + } if (strings.empty) { return parentNode as DataSchemaNode; } val nodeRef = strings.head; - //val moduleName = nodeRef.toModuleName(); val nodeName = nodeRef.toNodeName(); val targetNode = parentNode.getDataChildByName(nodeName); - if (targetNode == 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 + } + } + } + return null + } + if (targetNode instanceof ChoiceNode) { return null } @@ -176,11 +253,21 @@ class ControllerContext { if (targetNode instanceof ListSchemaNode) { val listNode = targetNode as ListSchemaNode; val keysSize = listNode.keyDefinition.size + + // every key has to be filled + if ((strings.length - consumed) < keysSize) { + return null; + } val uriKeyValues = strings.subList(consumed, consumed + keysSize); val keyValues = new HashMap(); var i = 0; for (key : listNode.keyDefinition) { val uriKeyValue = uriKeyValues.get(i); + + // key value cannot be NULL + if (uriKeyValue.equals(NULL_VALUE)) { + return null + } keyValues.addKeyValue(listNode.getDataChildByName(key), uriKeyValue); i = i + 1; } @@ -200,15 +287,25 @@ class ControllerContext { return targetNode } - def void addKeyValue(HashMap map, DataSchemaNode node, String uriValue) { + 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 = typedef + while (baseType.baseType != null) { + baseType = baseType.baseType; + } + if(baseType instanceof IdentityrefTypeDefinition) { + decoded = toQName(urlDecoded) + } + } map.put(node.QName, decoded); - } - def String toModuleName(String str) { + private def String toModuleName(String str) { checkNotNull(str) if (str.contains(":")) { val args = str.split(":"); @@ -219,7 +316,7 @@ class ControllerContext { } } - def String toNodeName(String str) { + private def String toNodeName(String str) { if (str.contains(":")) { val args = str.split(":"); checkArgument(args.size === 2); @@ -229,6 +326,54 @@ class ControllerContext { } } - public def QName toRpcQName(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); + } + + 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); + } + } + + /** + * Resolve target type from leafref type. + * + * According to RFC 6020 referenced element has to be leaf (chapter 9.9). + * Therefore if other element is referenced then null value is returned. + * + * Currently only cases without path-predicate are supported. + * + * @param leafRef + * @param schemaNode + * data schema node which contains reference + * @return type if leaf is referenced and it is possible to find referenced + * node in schema context. In other cases null value is returned + */ + def LeafSchemaNode resolveTypeFromLeafref(LeafrefTypeDefinition leafRef, DataSchemaNode schemaNode) { + val xPath = leafRef.getPathStatement(); + val module = SchemaContextUtil.findParentModule(schemas, schemaNode); + + var SchemaNode foundSchemaNode + if (xPath.isAbsolute()) { + foundSchemaNode = SchemaContextUtil.findDataSchemaNode(schemas, module, xPath); + } else { + foundSchemaNode = SchemaContextUtil.findDataSchemaNodeForRelativeXPath(schemas, module, schemaNode, xPath); + } + + if (foundSchemaNode instanceof LeafSchemaNode) { + return foundSchemaNode as LeafSchemaNode; + } + + return null; } }