1 package org.opendaylight.controller.sal.restconf.impl
3 import java.util.ArrayList
6 import javax.ws.rs.core.Response
7 import org.opendaylight.controller.md.sal.common.api.TransactionStatus
8 import org.opendaylight.controller.sal.rest.api.RestconfService
9 import org.opendaylight.yangtools.yang.data.api.CompositeNode
10 import org.opendaylight.yangtools.yang.data.api.Node
11 import org.opendaylight.yangtools.yang.data.impl.NodeFactory
12 import org.opendaylight.yangtools.yang.model.api.ChoiceNode
13 import org.opendaylight.yangtools.yang.model.api.DataNodeContainer
14 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode
15 import org.opendaylight.yangtools.yang.data.impl.codec.TypeDefinitionAwareCodec
16 import org.opendaylight.yangtools.yang.model.api.TypeDefinition
17 import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode
18 import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode
19 import org.opendaylight.yangtools.yang.common.QName
20 import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode
22 class RestconfImpl implements RestconfService {
24 val static RestconfImpl INSTANCE = new RestconfImpl
30 extension ControllerContext controllerContext
33 if (INSTANCE !== null) {
34 throw new IllegalStateException("Already instantiated");
38 static def getInstance() {
42 override readAllData() {
43 // return broker.readOperationalData("".toInstanceIdentifier.getInstanceIdentifier);
44 throw new UnsupportedOperationException("Reading all data is currently not supported.")
47 override getModules() {
48 throw new UnsupportedOperationException("TODO: auto-generated method stub")
55 override readData(String identifier) {
56 val instanceIdentifierWithSchemaNode = identifier.resolveInstanceIdentifier
57 val data = broker.readOperationalData(instanceIdentifierWithSchemaNode.getInstanceIdentifier);
58 return new StructuredData(data, instanceIdentifierWithSchemaNode.schemaNode)
61 override createConfigurationData(String identifier, CompositeNode payload) {
62 val identifierWithSchemaNode = identifier.resolveInstanceIdentifier
63 val value = normalizeNode(payload, identifierWithSchemaNode.schemaNode)
64 val status = broker.commitConfigurationDataPut(identifierWithSchemaNode.instanceIdentifier,value).get();
65 switch status.result {
66 case TransactionStatus.COMMITED: Response.status(Response.Status.OK).build
67 default: Response.status(Response.Status.INTERNAL_SERVER_ERROR).build
71 override updateConfigurationData(String identifier, CompositeNode payload) {
72 val identifierWithSchemaNode = identifier.resolveInstanceIdentifier
73 val value = normalizeNode(payload, identifierWithSchemaNode.schemaNode)
74 val status = broker.commitConfigurationDataPut(identifierWithSchemaNode.instanceIdentifier,value).get();
75 switch status.result {
76 case TransactionStatus.COMMITED: Response.status(Response.Status.NO_CONTENT).build
77 default: Response.status(Response.Status.INTERNAL_SERVER_ERROR).build
81 override invokeRpc(String identifier, CompositeNode payload) {
82 val rpc = identifier.rpcDefinition
84 throw new ResponseException(Response.Status.NOT_FOUND, "RPC does not exist.");
86 val value = normalizeNode(payload, rpc.input)
87 val List<Node<?>> input = new ArrayList
89 val rpcRequest = NodeFactory.createMutableCompositeNode(rpc.QName, null, input, null, null)
90 val rpcResult = broker.invokeRpc(rpc.QName, rpcRequest);
91 return new StructuredData(rpcResult.result, rpc.output);
94 override readConfigurationData(String identifier) {
95 val instanceIdentifierWithSchemaNode = identifier.resolveInstanceIdentifier
96 val data = broker.readConfigurationData(instanceIdentifierWithSchemaNode.getInstanceIdentifier);
97 return new StructuredData(data, instanceIdentifierWithSchemaNode.schemaNode)
100 override readOperationalData(String identifier) {
101 val instanceIdentifierWithSchemaNode = identifier.resolveInstanceIdentifier
102 val data = broker.readOperationalData(instanceIdentifierWithSchemaNode.getInstanceIdentifier);
103 return new StructuredData(data, instanceIdentifierWithSchemaNode.schemaNode)
106 override updateConfigurationDataLegacy(String identifier, CompositeNode payload) {
107 updateConfigurationData(identifier,payload);
110 override createConfigurationDataLegacy(String identifier, CompositeNode payload) {
111 createConfigurationData(identifier,payload);
114 private def InstanceIdWithSchemaNode resolveInstanceIdentifier(String identifier) {
115 val identifierWithSchemaNode = identifier.toInstanceIdentifier
116 if (identifierWithSchemaNode === null) {
117 throw new ResponseException(Response.Status.BAD_REQUEST, "URI has bad format");
119 return identifierWithSchemaNode
122 private def CompositeNode normalizeNode(CompositeNode node, DataSchemaNode schema) {
123 if (node instanceof CompositeNodeWrapper) {
124 normalizeNode(node as CompositeNodeWrapper, schema,null)
125 return (node as CompositeNodeWrapper).unwrap()
130 private def void normalizeNode(NodeWrapper<?> nodeBuilder, DataSchemaNode schema,QName previousAugment) {
131 if (schema === null) {
132 throw new ResponseException(Response.Status.BAD_REQUEST,
133 "Data has bad format\n" + nodeBuilder.localName + " does not exist in yang schema.");
135 var validQName = schema.QName
136 var currentAugment = previousAugment;
137 if(schema.augmenting) {
138 currentAugment = schema.QName
139 } else if(previousAugment !== null && schema.QName.namespace !== previousAugment.namespace) {
140 validQName = QName.create(currentAugment,schema.QName.localName);
142 val moduleName = controllerContext.findModuleByNamespace(validQName.namespace);
143 if (nodeBuilder.namespace === null || nodeBuilder.namespace == validQName.namespace ||
144 nodeBuilder.namespace.path == moduleName) {
145 nodeBuilder.qname = validQName
147 throw new ResponseException(Response.Status.BAD_REQUEST,
148 "Data has bad format\nIf data is in XML format then namespace for " + nodeBuilder.localName +
149 " should be " + schema.QName.namespace + ".\n If data is in Json format then module name for " +
150 nodeBuilder.localName + " should be " + moduleName + ".");
153 if (nodeBuilder instanceof CompositeNodeWrapper) {
154 val List<NodeWrapper<?>> children = (nodeBuilder as CompositeNodeWrapper).getValues
155 for (child : children) {
157 findFirstSchemaByLocalName(child.localName, (schema as DataNodeContainer).childNodes),currentAugment)
159 } else if (nodeBuilder instanceof SimpleNodeWrapper) {
160 val simpleNode = (nodeBuilder as SimpleNodeWrapper)
161 val stringValue = simpleNode.value as String;
163 val objectValue = TypeDefinitionAwareCodec.from(schema.typeDefinition)?.deserialize(stringValue);
164 simpleNode.setValue(objectValue)
165 } else if (nodeBuilder instanceof EmptyNodeWrapper) {
166 val emptyNodeBuilder = nodeBuilder as EmptyNodeWrapper
167 if(schema instanceof LeafSchemaNode) {
168 emptyNodeBuilder.setComposite(false);
169 } else if(schema instanceof ContainerSchemaNode) {
170 // FIXME: Add presence check
171 emptyNodeBuilder.setComposite(true);
176 private def dispatch TypeDefinition<?> typeDefinition(LeafSchemaNode node) {
180 private def dispatch TypeDefinition<?> typeDefinition(LeafListSchemaNode node) {
185 private def DataSchemaNode findFirstSchemaByLocalName(String localName, Set<DataSchemaNode> schemas) {
186 for (schema : schemas) {
187 if (schema instanceof ChoiceNode) {
188 for (caze : (schema as ChoiceNode).cases) {
189 val result = findFirstSchemaByLocalName(localName, caze.childNodes)
190 if (result !== null) {
195 val result = schemas.findFirst[n|n.QName.localName.equals(localName)]
196 if(result !== null) {