import java.util.ArrayList
import java.util.HashMap
import java.util.List
-import java.util.Set
import javax.ws.rs.core.Response
import org.opendaylight.controller.md.sal.common.api.TransactionStatus
import org.opendaylight.controller.sal.core.api.mount.MountInstance
import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.InstanceIdentifierBuilder
import org.opendaylight.yangtools.yang.data.api.Node
import org.opendaylight.yangtools.yang.data.impl.NodeFactory
-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.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.TypeDefinition
import org.opendaylight.yangtools.yang.model.api.type.IdentityrefTypeDefinition
class RestconfImpl implements RestconfService {
val static RestconfImpl INSTANCE = new RestconfImpl
+ val static MOUNT_POINT_MODULE_NAME = "ietf-netconf"
@Property
BrokerFacade broker
}
override readAllData() {
-// return broker.readOperationalData("".toInstanceIdentifier.getInstanceIdentifier);
+
+ // return broker.readOperationalData("".toInstanceIdentifier.getInstanceIdentifier);
throw new UnsupportedOperationException("Reading all data is currently not supported.")
}
override invokeRpc(String identifier, CompositeNode payload) {
return callRpc(identifier.rpcDefinition, payload)
}
-
+
override invokeRpc(String identifier) {
return callRpc(identifier.rpcDefinition, null)
}
-
+
private def StructuredData callRpc(RpcDefinition rpc, CompositeNode payload) {
if (rpc === null) {
throw new ResponseException(NOT_FOUND, "RPC does not exist.");
throw new ResponseException(BAD_REQUEST,
"Data has bad format. Root element node must have namespace (XML format) or module name(JSON format)");
}
- val uncompleteInstIdWithData = identifier.toInstanceIdentifier
- val schemaNode = uncompleteInstIdWithData.mountPoint.findModule(payload)?.getSchemaChildNode(payload)
- val value = normalizeNode(payload, schemaNode, uncompleteInstIdWithData.mountPoint)
- val completeInstIdWithData = uncompleteInstIdWithData.addLastIdentifierFromData(value, schemaNode)
+ var InstanceIdWithSchemaNode iiWithData;
+ var CompositeNode value;
+ if (payload.representsMountPointRootData) { // payload represents mount point data and URI represents path to the mount point
+ if (identifier.endsWithMountPoint) {
+ throw new ResponseException(BAD_REQUEST,
+ "URI has bad format. URI should be without \"" + ControllerContext.MOUNT + "\" for POST operation.");
+ }
+ val completIdentifier = identifier.addMountPointIdentifier
+ iiWithData = completIdentifier.toInstanceIdentifier
+ value = normalizeNode(payload, iiWithData.schemaNode, iiWithData.mountPoint)
+ } else {
+ val uncompleteInstIdWithData = identifier.toInstanceIdentifier
+ val parentSchema = uncompleteInstIdWithData.schemaNode as DataNodeContainer
+ val module = uncompleteInstIdWithData.mountPoint.findModule(payload)
+ if (module === null) {
+ throw new ResponseException(BAD_REQUEST, "Module was not found for \"" + payload.namespace + "\"")
+ }
+ val schemaNode = parentSchema.findInstanceDataChildByNameAndNamespace(payload.name, module.namespace)
+ value = normalizeNode(payload, schemaNode, uncompleteInstIdWithData.mountPoint)
+ iiWithData = uncompleteInstIdWithData.addLastIdentifierFromData(value, schemaNode)
+ }
var RpcResult<TransactionStatus> status = null
- if (completeInstIdWithData.mountPoint !== null) {
- status = broker.commitConfigurationDataPostBehindMountPoint(completeInstIdWithData.mountPoint,
- completeInstIdWithData.instanceIdentifier, value)?.get();
+ if (iiWithData.mountPoint !== null) {
+ status = broker.commitConfigurationDataPostBehindMountPoint(iiWithData.mountPoint,
+ iiWithData.instanceIdentifier, value)?.get();
} else {
- status = broker.commitConfigurationDataPost(completeInstIdWithData.instanceIdentifier, value)?.get();
+ status = broker.commitConfigurationDataPost(iiWithData.instanceIdentifier, value)?.get();
}
if (status === null) {
return Response.status(ACCEPTED).build
default: Response.status(INTERNAL_SERVER_ERROR).build
}
}
-
+
override createConfigurationData(CompositeNode payload) {
if (payload.namespace === null) {
throw new ResponseException(BAD_REQUEST,
"Data has bad format. Root element node must have namespace (XML format) or module name(JSON format)");
}
- val schemaNode = findModule(null, payload)?.getSchemaChildNode(payload)
+ val module = findModule(null, payload)
+ if (module === null) {
+ throw new ResponseException(BAD_REQUEST,
+ "Data has bad format. Root element node has incorrect namespace (XML format) or module name(JSON format)");
+ }
+ val schemaNode = module.findInstanceDataChildByNameAndNamespace(payload.name, module.namespace)
val value = normalizeNode(payload, schemaNode, null)
val iiWithData = addLastIdentifierFromData(null, value, schemaNode)
var RpcResult<TransactionStatus> status = null
default: Response.status(INTERNAL_SERVER_ERROR).build
}
}
-
+
override deleteConfigurationData(String identifier) {
val iiWithData = identifier.toInstanceIdentifier
var RpcResult<TransactionStatus> status = null
default: Response.status(INTERNAL_SERVER_ERROR).build
}
}
-
+
private def dispatch URI namespace(CompositeNode data) {
return data.nodeType.namespace
}
-
+
private def dispatch URI namespace(CompositeNodeWrapper data) {
return data.namespace
}
+ private def dispatch String localName(CompositeNode data) {
+ return data.nodeType.localName
+ }
+
+ private def dispatch String localName(CompositeNodeWrapper data) {
+ return data.localName
+ }
+
private def dispatch Module findModule(MountInstance mountPoint, CompositeNode data) {
if (mountPoint !== null) {
return mountPoint.findModuleByNamespace(data.nodeType.namespace)
}
return module
}
-
- private def dispatch DataSchemaNode getSchemaChildNode(DataNodeContainer parentSchemaNode, CompositeNode data) {
- return parentSchemaNode?.getDataChildByName(data.nodeType.localName)
+
+ private def dispatch getName(CompositeNode data) {
+ return data.nodeType.localName
}
-
- private def dispatch DataSchemaNode getSchemaChildNode(DataNodeContainer parentSchemaNode, CompositeNodeWrapper data) {
- return parentSchemaNode?.getDataChildByName(data.localName)
+
+ private def dispatch getName(CompositeNodeWrapper data) {
+ return data.localName
}
private def InstanceIdWithSchemaNode addLastIdentifierFromData(InstanceIdWithSchemaNode identifierWithSchemaNode,
return keyValues
}
+ private def endsWithMountPoint(String identifier) {
+ return (identifier.endsWith(ControllerContext.MOUNT) || identifier.endsWith(ControllerContext.MOUNT + "/"))
+ }
+
+ private def representsMountPointRootData(CompositeNode data) {
+ return ((data.namespace == SchemaContext.NAME.namespace || data.namespace == MOUNT_POINT_MODULE_NAME) &&
+ data.localName == SchemaContext.NAME.localName)
+ }
+
+ private def addMountPointIdentifier(String identifier) {
+ if (identifier.endsWith("/")) {
+ return identifier + ControllerContext.MOUNT
+ }
+ return identifier + "/" + ControllerContext.MOUNT
+ }
+
private def CompositeNode normalizeNode(CompositeNode node, DataSchemaNode schema, MountInstance mountPoint) {
if (schema === null) {
- throw new ResponseException(INTERNAL_SERVER_ERROR, "Data schema node was not found for " + node?.nodeType?.localName)
+ throw new ResponseException(INTERNAL_SERVER_ERROR,
+ "Data schema node was not found for " + node?.nodeType?.localName)
}
if (!(schema instanceof DataNodeContainer)) {
throw new ResponseException(BAD_REQUEST, "Root element has to be container or list yang datatype.");
throw new ResponseException(BAD_REQUEST,
"Data has bad format.\n\"" + nodeBuilder.localName + "\" does not exist in yang schema.");
}
- var validQName = schema.QName
- var currentAugment = previousAugment;
- if (schema.augmenting) {
- currentAugment = schema.QName
- } else if (previousAugment !== null && schema.QName.namespace !== previousAugment.namespace) {
- validQName = QName.create(currentAugment, schema.QName.localName);
- }
- var String moduleName = null;
- if (mountPoint === null) {
- moduleName = controllerContext.findModuleNameByNamespace(validQName.namespace);
- } else {
- moduleName = controllerContext.findModuleNameByNamespace(mountPoint, validQName.namespace)
- }
- if (nodeBuilder.namespace === null || nodeBuilder.namespace == validQName.namespace ||
- nodeBuilder.namespace.toString == moduleName) {
- nodeBuilder.qname = validQName
+
+ var QName currentAugment;
+ if (nodeBuilder.qname !== null) {
+ currentAugment = previousAugment
} else {
- throw new ResponseException(BAD_REQUEST,
- "Data has bad format.\nIf data is in XML format then namespace for \"" + nodeBuilder.localName +
- "\" should be \"" + schema.QName.namespace + "\".\nIf data is in Json format then module name for \"" +
- nodeBuilder.localName + "\" should be \"" + moduleName + "\".");
+ currentAugment = normalizeNodeName(nodeBuilder, schema, previousAugment, mountPoint)
+ if (nodeBuilder.qname === null) {
+ throw new ResponseException(BAD_REQUEST,
+ "Data has bad format.\nIf data is in XML format then namespace for \"" + nodeBuilder.localName +
+ "\" should be \"" + schema.QName.namespace + "\".\n" +
+ "If data is in JSON format then module name for \"" + nodeBuilder.localName +
+ "\" should be corresponding to namespace \"" + schema.QName.namespace + "\".");
+ }
}
if (nodeBuilder instanceof CompositeNodeWrapper) {
val List<NodeWrapper<?>> children = (nodeBuilder as CompositeNodeWrapper).getValues
for (child : children) {
- normalizeNode(child,
- findFirstSchemaByLocalName(child.localName, (schema as DataNodeContainer).childNodes),
- currentAugment, mountPoint)
+ val potentialSchemaNodes = (schema as DataNodeContainer).findInstanceDataChildrenByName(child.localName)
+ if (potentialSchemaNodes.size > 1 && child.namespace === null) {
+ val StringBuilder namespacesOfPotentialModules = new StringBuilder;
+ for (potentialSchemaNode : potentialSchemaNodes) {
+ namespacesOfPotentialModules.append(" ").append(potentialSchemaNode.QName.namespace.toString).append("\n")
+ }
+ throw new ResponseException(BAD_REQUEST,
+ "Node \"" + child.localName + "\" is added as augment from more than one module. "
+ + "Therefore node must have namespace (XML format) or module name (JSON format)."
+ + "\nThe node is added as augment from modules with namespaces:\n" + namespacesOfPotentialModules)
+ }
+ var rightNodeSchemaFound = false
+ for (potentialSchemaNode : potentialSchemaNodes) {
+ if (!rightNodeSchemaFound) {
+ val potentialCurrentAugment = normalizeNodeName(child, potentialSchemaNode, currentAugment,
+ mountPoint)
+ if (child.qname !== null) {
+ normalizeNode(child, potentialSchemaNode, potentialCurrentAugment, mountPoint)
+ rightNodeSchemaFound = true
+ }
+ }
+ }
+ if (!rightNodeSchemaFound) {
+ throw new ResponseException(BAD_REQUEST,
+ "Schema node \"" + child.localName + "\" was not found in module.")
+ }
}
- if(schema instanceof ListSchemaNode) {
+ if (schema instanceof ListSchemaNode) {
val listKeys = (schema as ListSchemaNode).keyDefinition
for (listKey : listKeys) {
var foundKey = false
}
if (!foundKey) {
throw new ResponseException(BAD_REQUEST,
- "Missing key in URI \"" + listKey.localName + "\" of list \"" + schema.QName.localName + "\"")
+ "Missing key in URI \"" + listKey.localName + "\" of list \"" + schema.QName.localName +
+ "\"")
}
}
}
val simpleNode = (nodeBuilder as SimpleNodeWrapper)
val value = simpleNode.value
var inputValue = value;
-
+
if (schema.typeDefinition instanceof IdentityrefTypeDefinition) {
if (value instanceof String) {
- inputValue = new IdentityValuesDTO(validQName.namespace.toString, value as String, null)
- } // else value is instance of ValuesDTO
+ inputValue = new IdentityValuesDTO(nodeBuilder.namespace.toString, value as String, null)
+ } // else value is already instance of IdentityValuesDTO
}
val outputValue = RestCodec.from(schema.typeDefinition, mountPoint)?.deserialize(inputValue);
}
baseType
}
-
- private def DataSchemaNode findFirstSchemaByLocalName(String localName, Set<DataSchemaNode> schemas) {
- for (schema : schemas) {
- if (schema instanceof ChoiceNode) {
- for (caze : (schema as ChoiceNode).cases) {
- val result = findFirstSchemaByLocalName(localName, caze.childNodes)
- if (result !== null) {
- return result
- }
- }
- } else {
- val result = schemas.findFirst[n|n.QName.localName.equals(localName)]
- if (result !== null) {
- return result;
-
- }
- }
+
+ private def QName normalizeNodeName(NodeWrapper<?> nodeBuilder, DataSchemaNode schema, QName previousAugment,
+ MountInstance mountPoint) {
+ var validQName = schema.QName
+ var currentAugment = previousAugment;
+ if (schema.augmenting) {
+ currentAugment = schema.QName
+ } else if (previousAugment !== null && schema.QName.namespace !== previousAugment.namespace) {
+ validQName = QName.create(currentAugment, schema.QName.localName);
+ }
+ var String moduleName = null;
+ if (mountPoint === null) {
+ moduleName = controllerContext.findModuleNameByNamespace(validQName.namespace);
+ } else {
+ moduleName = controllerContext.findModuleNameByNamespace(mountPoint, validQName.namespace)
+ }
+ if (nodeBuilder.namespace === null || nodeBuilder.namespace == validQName.namespace ||
+ nodeBuilder.namespace.toString == moduleName || nodeBuilder.namespace == MOUNT_POINT_MODULE_NAME) {
+ nodeBuilder.qname = validQName
}
- return null
+ return currentAugment
}
}