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 org.opendaylight.yangtools.yang.data.impl.codec.TypeDefinitionAwareCodec
+import org.opendaylight.yangtools.yang.model.api.type.IdentityrefTypeDefinition
class ControllerContext implements SchemaServiceListener {
val static NULL_VALUE = "null"
- @Property
- SchemaContext schemas;
+ var SchemaContext schemas;
private val BiMap<URI, String> uriToModuleName = HashBiMap.create();
private val Map<String, URI> moduleNameToUri = uriToModuleName.inverse();
- private val Map<QName,RpcDefinition> qnameToRpc = new ConcurrentHashMap();
-
+ private val Map<QName, RpcDefinition> qnameToRpc = new ConcurrentHashMap();
private new() {
if (INSTANCE !== null) {
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();
val pathArgs = restconfInstance.split("/");
if (schemaNode === null) {
return null
}
- new InstanceIdWithSchemaNode(ret.toInstance, schemaNode)
+ return new InstanceIdWithSchemaNode(ret.toInstance, schemaNode)
}
private def findModule(String restconfInstance) {
}
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)
+ private def getLatestModule(String moduleName) {
+ checkPreconditions
checkArgument(moduleName !== null && !moduleName.empty)
- val modules = schema.modules.filter[m|m.name == moduleName]
+ val modules = schemas.modules.filter[m|m.name == moduleName]
var latestModule = modules.head
for (module : modules) {
if (module.revision.after(latestModule.revision)) {
throw new IllegalArgumentException("Conversion of generic path argument is not supported");
}
+ 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)
private def void addKeyValue(HashMap<QName, Object> 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);
-
}
private def String toModuleName(String str) {
}
}
- 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);
+ 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);
+ for (operation : context.operations) {
+ val qname = new QName(operation.QName.namespace, null, operation.QName.localName);
+ qnameToRpc.put(qname, operation);
}
}
-
- def ContainerSchemaNode getRpcOutputSchema(QName name) {
- qnameToRpc.get(name)?.output;
- }
-
- def ContainerSchemaNode getRpcInputSchema(QName name) {
- qnameToRpc.get(name)?.input;
- }
+ /**
+ * 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;
+ }
}