2 * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
3 * Copyright (c) 2014 Brocade Communication Systems, Inc.
5 * This program and the accompanying materials are made available under the
6 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
7 * and is available at http://www.eclipse.org/legal/epl-v10.html
9 package org.opendaylight.controller.sal.restconf.impl;
11 import com.google.common.base.Objects;
12 import com.google.common.base.Preconditions;
13 import com.google.common.base.Splitter;
14 import com.google.common.base.Strings;
15 import com.google.common.collect.ImmutableList;
16 import com.google.common.collect.Iterables;
17 import com.google.common.collect.Lists;
20 import java.text.ParseException;
21 import java.text.SimpleDateFormat;
22 import java.util.ArrayList;
23 import java.util.Arrays;
24 import java.util.Collection;
25 import java.util.Collections;
26 import java.util.Date;
27 import java.util.HashMap;
28 import java.util.List;
30 import java.util.concurrent.Future;
32 import javax.ws.rs.core.Response;
33 import javax.ws.rs.core.Response.Status;
34 import javax.ws.rs.core.UriBuilder;
35 import javax.ws.rs.core.UriInfo;
37 import org.apache.commons.lang3.StringUtils;
38 import org.opendaylight.controller.md.sal.common.api.TransactionStatus;
39 import org.opendaylight.controller.sal.core.api.mount.MountInstance;
40 import org.opendaylight.controller.sal.rest.api.Draft02;
41 import org.opendaylight.controller.sal.rest.api.RestconfService;
42 import org.opendaylight.controller.sal.restconf.impl.RestconfError.ErrorTag;
43 import org.opendaylight.controller.sal.restconf.impl.RestconfError.ErrorType;
44 import org.opendaylight.controller.sal.restconf.rpc.impl.BrokerRpcExecutor;
45 import org.opendaylight.controller.sal.restconf.rpc.impl.MountPointRpcExecutor;
46 import org.opendaylight.controller.sal.restconf.rpc.impl.RpcExecutor;
47 import org.opendaylight.controller.sal.streams.listeners.ListenerAdapter;
48 import org.opendaylight.controller.sal.streams.listeners.Notificator;
49 import org.opendaylight.controller.sal.streams.websockets.WebSocketServer;
50 import org.opendaylight.yangtools.concepts.Codec;
51 import org.opendaylight.yangtools.yang.common.QName;
52 import org.opendaylight.yangtools.yang.common.RpcError;
53 import org.opendaylight.yangtools.yang.common.RpcResult;
54 import org.opendaylight.yangtools.yang.data.api.CompositeNode;
55 import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
56 import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.InstanceIdentifierBuilder;
57 import org.opendaylight.yangtools.yang.data.api.MutableCompositeNode;
58 import org.opendaylight.yangtools.yang.data.api.Node;
59 import org.opendaylight.yangtools.yang.data.api.SimpleNode;
60 import org.opendaylight.yangtools.yang.data.impl.ImmutableCompositeNode;
61 import org.opendaylight.yangtools.yang.data.impl.NodeFactory;
62 import org.opendaylight.yangtools.yang.model.api.AnyXmlSchemaNode;
63 import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
64 import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
65 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
66 import org.opendaylight.yangtools.yang.model.api.FeatureDefinition;
67 import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
68 import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
69 import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
70 import org.opendaylight.yangtools.yang.model.api.Module;
71 import org.opendaylight.yangtools.yang.model.api.RpcDefinition;
72 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
73 import org.opendaylight.yangtools.yang.model.api.SchemaPath;
74 import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
75 import org.opendaylight.yangtools.yang.model.api.type.IdentityrefTypeDefinition;
76 import org.opendaylight.yangtools.yang.model.util.EmptyType;
77 import org.opendaylight.yangtools.yang.parser.builder.impl.ContainerSchemaNodeBuilder;
78 import org.opendaylight.yangtools.yang.parser.builder.impl.LeafSchemaNodeBuilder;
80 public class RestconfImpl implements RestconfService {
81 private final static RestconfImpl INSTANCE = new RestconfImpl();
83 private static final int CHAR_NOT_FOUND = -1;
85 private final static String MOUNT_POINT_MODULE_NAME = "ietf-netconf";
87 private final static SimpleDateFormat REVISION_FORMAT = new SimpleDateFormat("yyyy-MM-dd");
89 private final static String SAL_REMOTE_NAMESPACE = "urn:opendaylight:params:xml:ns:yang:controller:md:sal:remote";
91 private final static String SAL_REMOTE_RPC_SUBSRCIBE = "create-data-change-event-subscription";
93 private BrokerFacade broker;
95 private ControllerContext controllerContext;
97 public void setBroker(final BrokerFacade broker) {
101 public void setControllerContext(final ControllerContext controllerContext) {
102 this.controllerContext = controllerContext;
105 private RestconfImpl() {
108 public static RestconfImpl getInstance() {
113 public StructuredData getModules() {
114 final Module restconfModule = this.getRestconfModule();
116 final List<Node<?>> modulesAsData = new ArrayList<Node<?>>();
117 final DataSchemaNode moduleSchemaNode = controllerContext.getRestconfModuleRestConfSchemaNode(
118 restconfModule, Draft02.RestConfModule.MODULE_LIST_SCHEMA_NODE);
120 Set<Module> allModules = this.controllerContext.getAllModules();
121 for (final Module module : allModules) {
122 CompositeNode moduleCompositeNode = this.toModuleCompositeNode(module, moduleSchemaNode);
123 modulesAsData.add(moduleCompositeNode);
126 final DataSchemaNode modulesSchemaNode = controllerContext.getRestconfModuleRestConfSchemaNode(
127 restconfModule, Draft02.RestConfModule.MODULES_CONTAINER_SCHEMA_NODE);
128 QName qName = modulesSchemaNode.getQName();
129 final CompositeNode modulesNode = NodeFactory.createImmutableCompositeNode(qName, null, modulesAsData);
130 return new StructuredData(modulesNode, modulesSchemaNode, null);
134 public StructuredData getAvailableStreams() {
135 Set<String> availableStreams = Notificator.getStreamNames();
137 final List<Node<?>> streamsAsData = new ArrayList<Node<?>>();
138 Module restconfModule = this.getRestconfModule();
139 final DataSchemaNode streamSchemaNode = controllerContext.getRestconfModuleRestConfSchemaNode(
140 restconfModule, Draft02.RestConfModule.STREAM_LIST_SCHEMA_NODE);
141 for (final String streamName : availableStreams) {
142 streamsAsData.add(this.toStreamCompositeNode(streamName, streamSchemaNode));
145 final DataSchemaNode streamsSchemaNode = controllerContext.getRestconfModuleRestConfSchemaNode(
146 restconfModule, Draft02.RestConfModule.STREAMS_CONTAINER_SCHEMA_NODE);
147 QName qName = streamsSchemaNode.getQName();
148 final CompositeNode streamsNode = NodeFactory.createImmutableCompositeNode(qName, null, streamsAsData);
149 return new StructuredData(streamsNode, streamsSchemaNode, null);
153 public StructuredData getModules(final String identifier) {
154 Set<Module> modules = null;
155 MountInstance mountPoint = null;
156 if (identifier.contains(ControllerContext.MOUNT)) {
157 InstanceIdWithSchemaNode mountPointIdentifier =
158 this.controllerContext.toMountPointIdentifier(identifier);
159 mountPoint = mountPointIdentifier.getMountPoint();
160 modules = this.controllerContext.getAllModules(mountPoint);
163 throw new RestconfDocumentedException(
164 "URI has bad format. If modules behind mount point should be showed, URI has to end with " +
165 ControllerContext.MOUNT, ErrorType.PROTOCOL, ErrorTag.INVALID_VALUE );
168 final List<Node<?>> modulesAsData = new ArrayList<Node<?>>();
169 Module restconfModule = this.getRestconfModule();
170 final DataSchemaNode moduleSchemaNode = controllerContext.getRestconfModuleRestConfSchemaNode(
171 restconfModule, Draft02.RestConfModule.MODULE_LIST_SCHEMA_NODE);
173 for (final Module module : modules) {
174 modulesAsData.add(this.toModuleCompositeNode(module, moduleSchemaNode));
177 final DataSchemaNode modulesSchemaNode = controllerContext.getRestconfModuleRestConfSchemaNode(
178 restconfModule, Draft02.RestConfModule.MODULES_CONTAINER_SCHEMA_NODE);
179 QName qName = modulesSchemaNode.getQName();
180 final CompositeNode modulesNode = NodeFactory.createImmutableCompositeNode(qName, null, modulesAsData);
181 return new StructuredData(modulesNode, modulesSchemaNode, mountPoint);
185 public StructuredData getModule(final String identifier) {
186 final QName moduleNameAndRevision = this.getModuleNameAndRevision(identifier);
187 Module module = null;
188 MountInstance mountPoint = null;
189 if (identifier.contains(ControllerContext.MOUNT)) {
190 InstanceIdWithSchemaNode mountPointIdentifier =
191 this.controllerContext.toMountPointIdentifier(identifier);
192 mountPoint = mountPointIdentifier.getMountPoint();
193 module = this.controllerContext.findModuleByNameAndRevision(mountPoint, moduleNameAndRevision);
196 module = this.controllerContext.findModuleByNameAndRevision(moduleNameAndRevision);
199 if (module == null) {
200 throw new RestconfDocumentedException(
201 "Module with name '" + moduleNameAndRevision.getLocalName() + "' and revision '" +
202 moduleNameAndRevision.getRevision() + "' was not found.",
203 ErrorType.PROTOCOL, ErrorTag.UNKNOWN_ELEMENT );
206 Module restconfModule = this.getRestconfModule();
207 final DataSchemaNode moduleSchemaNode = controllerContext.getRestconfModuleRestConfSchemaNode(
208 restconfModule, Draft02.RestConfModule.MODULE_LIST_SCHEMA_NODE);
209 final CompositeNode moduleNode = this.toModuleCompositeNode(module, moduleSchemaNode);
210 return new StructuredData(moduleNode, moduleSchemaNode, mountPoint);
214 public StructuredData getOperations() {
215 Set<Module> allModules = this.controllerContext.getAllModules();
216 return this.operationsFromModulesToStructuredData(allModules, null);
220 public StructuredData getOperations(final String identifier) {
221 Set<Module> modules = null;
222 MountInstance mountPoint = null;
223 if (identifier.contains(ControllerContext.MOUNT)) {
224 InstanceIdWithSchemaNode mountPointIdentifier =
225 this.controllerContext.toMountPointIdentifier(identifier);
226 mountPoint = mountPointIdentifier.getMountPoint();
227 modules = this.controllerContext.getAllModules(mountPoint);
230 throw new RestconfDocumentedException(
231 "URI has bad format. If operations behind mount point should be showed, URI has to end with " +
232 ControllerContext.MOUNT, ErrorType.PROTOCOL, ErrorTag.INVALID_VALUE );
235 return this.operationsFromModulesToStructuredData(modules, mountPoint);
238 private StructuredData operationsFromModulesToStructuredData(final Set<Module> modules,
239 final MountInstance mountPoint) {
240 final List<Node<?>> operationsAsData = new ArrayList<Node<?>>();
241 Module restconfModule = this.getRestconfModule();
242 final DataSchemaNode operationsSchemaNode = controllerContext.getRestconfModuleRestConfSchemaNode(
243 restconfModule, Draft02.RestConfModule.OPERATIONS_CONTAINER_SCHEMA_NODE);
244 QName qName = operationsSchemaNode.getQName();
245 SchemaPath path = operationsSchemaNode.getPath();
246 ContainerSchemaNodeBuilder containerSchemaNodeBuilder =
247 new ContainerSchemaNodeBuilder(Draft02.RestConfModule.NAME, 0, qName, path);
248 final ContainerSchemaNodeBuilder fakeOperationsSchemaNode = containerSchemaNodeBuilder;
249 for (final Module module : modules) {
250 Set<RpcDefinition> rpcs = module.getRpcs();
251 for (final RpcDefinition rpc : rpcs) {
252 QName rpcQName = rpc.getQName();
253 SimpleNode<Object> immutableSimpleNode =
254 NodeFactory.<Object>createImmutableSimpleNode(rpcQName, null, null);
255 operationsAsData.add(immutableSimpleNode);
257 String name = module.getName();
258 LeafSchemaNodeBuilder leafSchemaNodeBuilder = new LeafSchemaNodeBuilder(name, 0, rpcQName,
259 SchemaPath.create(true, QName.create("dummy")));
260 final LeafSchemaNodeBuilder fakeRpcSchemaNode = leafSchemaNodeBuilder;
261 fakeRpcSchemaNode.setAugmenting(true);
263 EmptyType instance = EmptyType.getInstance();
264 fakeRpcSchemaNode.setType(instance);
265 fakeOperationsSchemaNode.addChildNode(fakeRpcSchemaNode.build());
269 final CompositeNode operationsNode =
270 NodeFactory.createImmutableCompositeNode(qName, null, operationsAsData);
271 ContainerSchemaNode schemaNode = fakeOperationsSchemaNode.build();
272 return new StructuredData(operationsNode, schemaNode, mountPoint);
275 private Module getRestconfModule() {
276 Module restconfModule = controllerContext.getRestconfModule();
277 if (restconfModule == null) {
278 throw new RestconfDocumentedException(
279 "ietf-restconf module was not found.", ErrorType.APPLICATION,
280 ErrorTag.OPERATION_NOT_SUPPORTED );
283 return restconfModule;
286 private QName getModuleNameAndRevision(final String identifier) {
287 final int mountIndex = identifier.indexOf(ControllerContext.MOUNT);
288 String moduleNameAndRevision = "";
289 if (mountIndex >= 0) {
290 moduleNameAndRevision = identifier.substring(mountIndex + ControllerContext.MOUNT.length());
293 moduleNameAndRevision = identifier;
296 Splitter splitter = Splitter.on("/").omitEmptyStrings();
297 Iterable<String> split = splitter.split(moduleNameAndRevision);
298 final List<String> pathArgs = Lists.<String>newArrayList(split);
299 if (pathArgs.size() < 2) {
300 throw new RestconfDocumentedException(
301 "URI has bad format. End of URI should be in format \'moduleName/yyyy-MM-dd\'",
302 ErrorType.PROTOCOL, ErrorTag.INVALID_VALUE );
306 final String moduleName = pathArgs.get( 0 );
307 String revision = pathArgs.get(1);
308 final Date moduleRevision = REVISION_FORMAT.parse(revision);
309 return QName.create(null, moduleRevision, moduleName);
311 catch (ParseException e) {
312 throw new RestconfDocumentedException(
313 "URI has bad format. It should be \'moduleName/yyyy-MM-dd\'",
314 ErrorType.PROTOCOL, ErrorTag.INVALID_VALUE );
318 private CompositeNode toStreamCompositeNode(final String streamName, final DataSchemaNode streamSchemaNode) {
319 final List<Node<?>> streamNodeValues = new ArrayList<Node<?>>();
320 List<DataSchemaNode> instanceDataChildrenByName =
321 this.controllerContext.findInstanceDataChildrenByName(((DataNodeContainer) streamSchemaNode),
323 final DataSchemaNode nameSchemaNode = Iterables.getFirst(instanceDataChildrenByName, null);
324 streamNodeValues.add(NodeFactory.<String>createImmutableSimpleNode(nameSchemaNode.getQName(), null,
327 instanceDataChildrenByName = this.controllerContext.findInstanceDataChildrenByName(
328 ((DataNodeContainer) streamSchemaNode), "description");
329 final DataSchemaNode descriptionSchemaNode = Iterables.getFirst(instanceDataChildrenByName, null);
330 streamNodeValues.add(NodeFactory.<String>createImmutableSimpleNode(descriptionSchemaNode.getQName(), null,
331 "DESCRIPTION_PLACEHOLDER"));
333 instanceDataChildrenByName = this.controllerContext.findInstanceDataChildrenByName(
334 ((DataNodeContainer) streamSchemaNode), "replay-support");
335 final DataSchemaNode replaySupportSchemaNode = Iterables.getFirst(instanceDataChildrenByName, null);
336 streamNodeValues.add(NodeFactory.<Boolean>createImmutableSimpleNode(replaySupportSchemaNode.getQName(), null,
337 Boolean.valueOf(true)));
339 instanceDataChildrenByName = this.controllerContext.findInstanceDataChildrenByName(
340 ((DataNodeContainer) streamSchemaNode), "replay-log-creation-time");
341 final DataSchemaNode replayLogCreationTimeSchemaNode = Iterables.getFirst(instanceDataChildrenByName, null);
342 streamNodeValues.add(NodeFactory.<String>createImmutableSimpleNode(replayLogCreationTimeSchemaNode.getQName(),
345 instanceDataChildrenByName = this.controllerContext.findInstanceDataChildrenByName(
346 ((DataNodeContainer) streamSchemaNode), "events");
347 final DataSchemaNode eventsSchemaNode = Iterables.getFirst(instanceDataChildrenByName, null);
348 streamNodeValues.add(NodeFactory.<String>createImmutableSimpleNode(eventsSchemaNode.getQName(),
351 return NodeFactory.createImmutableCompositeNode(streamSchemaNode.getQName(), null, streamNodeValues);
354 private CompositeNode toModuleCompositeNode(final Module module, final DataSchemaNode moduleSchemaNode) {
355 final List<Node<?>> moduleNodeValues = new ArrayList<Node<?>>();
356 List<DataSchemaNode> instanceDataChildrenByName =
357 this.controllerContext.findInstanceDataChildrenByName(((DataNodeContainer) moduleSchemaNode), "name");
358 final DataSchemaNode nameSchemaNode = Iterables.getFirst(instanceDataChildrenByName, null);
359 moduleNodeValues.add(NodeFactory.<String>createImmutableSimpleNode(nameSchemaNode.getQName(),
360 null, module.getName()));
362 instanceDataChildrenByName = this.controllerContext.findInstanceDataChildrenByName(
363 ((DataNodeContainer) moduleSchemaNode), "revision");
364 final DataSchemaNode revisionSchemaNode = Iterables.getFirst(instanceDataChildrenByName, null);
365 Date _revision = module.getRevision();
366 moduleNodeValues.add(NodeFactory.<String>createImmutableSimpleNode(revisionSchemaNode.getQName(), null,
367 REVISION_FORMAT.format(_revision)));
369 instanceDataChildrenByName = this.controllerContext.findInstanceDataChildrenByName(
370 ((DataNodeContainer) moduleSchemaNode), "namespace");
371 final DataSchemaNode namespaceSchemaNode = Iterables.getFirst(instanceDataChildrenByName, null);
372 moduleNodeValues.add(NodeFactory.<String>createImmutableSimpleNode(namespaceSchemaNode.getQName(), null,
373 module.getNamespace().toString()));
375 instanceDataChildrenByName = this.controllerContext.findInstanceDataChildrenByName(
376 ((DataNodeContainer) moduleSchemaNode), "feature");
377 final DataSchemaNode featureSchemaNode = Iterables.getFirst(instanceDataChildrenByName, null);
378 for (final FeatureDefinition feature : module.getFeatures()) {
379 moduleNodeValues.add(NodeFactory.<String>createImmutableSimpleNode(featureSchemaNode.getQName(), null,
380 feature.getQName().getLocalName()));
383 return NodeFactory.createImmutableCompositeNode(moduleSchemaNode.getQName(), null, moduleNodeValues);
387 public Object getRoot() {
392 public StructuredData invokeRpc(final String identifier, final CompositeNode payload) {
393 final RpcExecutor rpc = this.resolveIdentifierInInvokeRpc(identifier);
394 QName rpcName = rpc.getRpcDefinition().getQName();
395 URI rpcNamespace = rpcName.getNamespace();
396 if (Objects.equal(rpcNamespace.toString(), SAL_REMOTE_NAMESPACE) &&
397 Objects.equal(rpcName.getLocalName(), SAL_REMOTE_RPC_SUBSRCIBE)) {
398 return invokeSalRemoteRpcSubscribeRPC(payload, rpc.getRpcDefinition());
401 validateInput( rpc.getRpcDefinition().getInput(), payload );
403 return callRpc(rpc, payload);
406 private void validateInput(final DataSchemaNode inputSchema, final CompositeNode payload) {
407 if( inputSchema != null && payload == null )
409 //expected a non null payload
410 throw new RestconfDocumentedException( "Input is required.",
412 ErrorTag.MALFORMED_MESSAGE );
414 else if( inputSchema == null && payload != null )
416 //did not expect any input
417 throw new RestconfDocumentedException( "No input expected.",
419 ErrorTag.MALFORMED_MESSAGE );
423 //TODO: Validate "mandatory" and "config" values here??? Or should those be
424 // validate in a more central location inside MD-SAL core.
428 private StructuredData invokeSalRemoteRpcSubscribeRPC(final CompositeNode payload,
429 final RpcDefinition rpc) {
430 final CompositeNode value = this.normalizeNode(payload, rpc.getInput(), null);
431 final SimpleNode<? extends Object> pathNode = value == null ? null :
432 value.getFirstSimpleByName( QName.create(rpc.getQName(), "path") );
433 final Object pathValue = pathNode == null ? null : pathNode.getValue();
435 if (!(pathValue instanceof InstanceIdentifier)) {
436 throw new RestconfDocumentedException(
437 "Instance identifier was not normalized correctly.",
438 ErrorType.APPLICATION, ErrorTag.OPERATION_FAILED );
441 final InstanceIdentifier pathIdentifier = ((InstanceIdentifier) pathValue);
442 String streamName = null;
443 if (!Iterables.isEmpty(pathIdentifier.getPathArguments())) {
444 String fullRestconfIdentifier = this.controllerContext.toFullRestconfIdentifier(pathIdentifier);
445 streamName = Notificator.createStreamNameFromUri(fullRestconfIdentifier);
448 if (Strings.isNullOrEmpty(streamName)) {
449 throw new RestconfDocumentedException(
450 "Path is empty or contains data node which is not Container or List build-in type.",
451 ErrorType.PROTOCOL, ErrorTag.INVALID_VALUE );
454 final SimpleNode<String> streamNameNode = NodeFactory.<String>createImmutableSimpleNode(
455 QName.create(rpc.getOutput().getQName(), "stream-name"), null, streamName);
456 final List<Node<?>> output = new ArrayList<Node<?>>();
457 output.add(streamNameNode);
459 final MutableCompositeNode responseData = NodeFactory.createMutableCompositeNode(
460 rpc.getOutput().getQName(), null, output, null, null);
462 if (!Notificator.existListenerFor(pathIdentifier)) {
463 Notificator.createListener(pathIdentifier, streamName);
466 return new StructuredData(responseData, rpc.getOutput(), null);
470 public StructuredData invokeRpc(final String identifier, final String noPayload) {
471 if (StringUtils.isNotBlank(noPayload)) {
472 throw new RestconfDocumentedException(
473 "Content must be empty.", ErrorType.PROTOCOL, ErrorTag.INVALID_VALUE );
475 return invokeRpc( identifier, (CompositeNode)null );
478 private RpcExecutor resolveIdentifierInInvokeRpc(final String identifier) {
479 String identifierEncoded = null;
480 MountInstance mountPoint = null;
481 if (identifier.contains(ControllerContext.MOUNT)) {
482 // mounted RPC call - look up mount instance.
483 InstanceIdWithSchemaNode mountPointId = controllerContext
484 .toMountPointIdentifier(identifier);
485 mountPoint = mountPointId.getMountPoint();
487 int startOfRemoteRpcName = identifier.lastIndexOf(ControllerContext.MOUNT)
488 + ControllerContext.MOUNT.length() + 1;
489 String remoteRpcName = identifier.substring(startOfRemoteRpcName);
490 identifierEncoded = remoteRpcName;
492 } else if (identifier.indexOf("/") != CHAR_NOT_FOUND) {
493 final String slashErrorMsg = String
494 .format("Identifier %n%s%ncan\'t contain slash "
495 + "character (/).%nIf slash is part of identifier name then use %%2F placeholder.",
497 throw new RestconfDocumentedException(
498 slashErrorMsg, ErrorType.PROTOCOL, ErrorTag.INVALID_VALUE );
500 identifierEncoded = identifier;
503 final String identifierDecoded = controllerContext.urlPathArgDecode(identifierEncoded);
504 RpcDefinition rpc = controllerContext.getRpcDefinition(identifierDecoded);
507 throw new RestconfDocumentedException(
508 "RPC does not exist.", ErrorType.RPC, ErrorTag.UNKNOWN_ELEMENT );
511 if (mountPoint == null) {
512 return new BrokerRpcExecutor(rpc, broker);
514 return new MountPointRpcExecutor(rpc, mountPoint);
519 private StructuredData callRpc(final RpcExecutor rpcExecutor, final CompositeNode payload) {
520 if (rpcExecutor == null) {
521 throw new RestconfDocumentedException(
522 "RPC does not exist.", ErrorType.RPC, ErrorTag.UNKNOWN_ELEMENT );
525 CompositeNode rpcRequest = null;
526 RpcDefinition rpc = rpcExecutor.getRpcDefinition();
527 QName rpcName = rpc.getQName();
529 if (payload == null) {
530 rpcRequest = NodeFactory.createMutableCompositeNode(rpcName, null, null, null, null);
532 final CompositeNode value = this.normalizeNode(payload, rpc.getInput(), null);
533 List<Node<?>> input = Collections.<Node<?>> singletonList(value);
534 rpcRequest = NodeFactory.createMutableCompositeNode(rpcName, null, input, null, null);
537 RpcResult<CompositeNode> rpcResult = rpcExecutor.invokeRpc(rpcRequest);
539 checkRpcSuccessAndThrowException(rpcResult);
541 if (rpcResult.getResult() == null) {
545 if( rpc.getOutput() == null )
547 return null; //no output, nothing to send back.
550 return new StructuredData(rpcResult.getResult(), rpc.getOutput(), null);
553 private void checkRpcSuccessAndThrowException(final RpcResult<CompositeNode> rpcResult) {
554 if (rpcResult.isSuccessful() == false) {
556 Collection<RpcError> rpcErrors = rpcResult.getErrors();
557 if( rpcErrors == null || rpcErrors.isEmpty() ) {
558 throw new RestconfDocumentedException(
559 "The operation was not successful and there were no RPC errors returned",
560 ErrorType.RPC, ErrorTag.OPERATION_FAILED );
563 List<RestconfError> errorList = Lists.newArrayList();
564 for( RpcError rpcError: rpcErrors ) {
565 errorList.add( new RestconfError( rpcError ) );
568 throw new RestconfDocumentedException( errorList );
573 public StructuredData readConfigurationData(final String identifier, final UriInfo info) {
574 final InstanceIdWithSchemaNode iiWithData = this.controllerContext.toInstanceIdentifier(identifier);
575 CompositeNode data = null;
576 MountInstance mountPoint = iiWithData.getMountPoint();
577 if (mountPoint != null) {
578 data = broker.readConfigurationDataBehindMountPoint(mountPoint, iiWithData.getInstanceIdentifier());
581 data = broker.readConfigurationData(iiWithData.getInstanceIdentifier());
584 data = pruneDataAtDepth( data, parseDepthParameter( info ) );
585 return new StructuredData(data, iiWithData.getSchemaNode(), iiWithData.getMountPoint());
588 @SuppressWarnings("unchecked")
589 private <T extends Node<?>> T pruneDataAtDepth( final T node, final Integer depth ) {
590 if( depth == null ) {
594 if( node instanceof CompositeNode ) {
595 ImmutableList.Builder<Node<?>> newChildNodes = ImmutableList.<Node<?>> builder();
597 for( Node<?> childNode: ((CompositeNode)node).getValue() ) {
598 newChildNodes.add( pruneDataAtDepth( childNode, depth - 1 ) );
602 return (T) ImmutableCompositeNode.create( node.getNodeType(), newChildNodes.build() );
609 private Integer parseDepthParameter( final UriInfo info ) {
610 String param = info.getQueryParameters( false ).getFirst( "depth" );
611 if( Strings.isNullOrEmpty( param ) || "unbounded".equals( param ) ) {
616 Integer depth = Integer.valueOf( param );
618 throw new RestconfDocumentedException( new RestconfError(
619 ErrorType.PROTOCOL, ErrorTag.INVALID_VALUE, "Invalid depth parameter: " + depth,
620 null, "The depth parameter must be an integer > 1 or \"unbounded\"" ) );
625 catch( NumberFormatException e ) {
626 throw new RestconfDocumentedException( new RestconfError(
627 ErrorType.PROTOCOL, ErrorTag.INVALID_VALUE,
628 "Invalid depth parameter: " + e.getMessage(),
629 null, "The depth parameter must be an integer > 1 or \"unbounded\"" ) );
634 public StructuredData readOperationalData(final String identifier, final UriInfo info) {
635 final InstanceIdWithSchemaNode iiWithData = this.controllerContext.toInstanceIdentifier(identifier);
636 CompositeNode data = null;
637 MountInstance mountPoint = iiWithData.getMountPoint();
638 if (mountPoint != null) {
639 data = broker.readOperationalDataBehindMountPoint(mountPoint, iiWithData.getInstanceIdentifier());
642 data = broker.readOperationalData(iiWithData.getInstanceIdentifier());
645 data = pruneDataAtDepth( data, parseDepthParameter( info ) );
646 return new StructuredData(data, iiWithData.getSchemaNode(), mountPoint);
650 public Response updateConfigurationData(final String identifier, final CompositeNode payload) {
651 final InstanceIdWithSchemaNode iiWithData = this.controllerContext.toInstanceIdentifier(identifier);
653 validateInput(iiWithData.getSchemaNode(), payload);
655 MountInstance mountPoint = iiWithData.getMountPoint();
656 final CompositeNode value = this.normalizeNode(payload, iiWithData.getSchemaNode(), mountPoint);
657 RpcResult<TransactionStatus> status = null;
660 if (mountPoint != null) {
661 status = broker.commitConfigurationDataPutBehindMountPoint(
662 mountPoint, iiWithData.getInstanceIdentifier(), value).get();
664 status = broker.commitConfigurationDataPut(iiWithData.getInstanceIdentifier(), value).get();
667 catch( Exception e ) {
668 throw new RestconfDocumentedException( "Error updating data", e );
671 if( status.getResult() == TransactionStatus.COMMITED ) {
672 return Response.status(Status.OK).build();
675 return Response.status(Status.INTERNAL_SERVER_ERROR).build();
679 public Response createConfigurationData(final String identifier, final CompositeNode payload) {
680 if( payload == null ) {
681 throw new RestconfDocumentedException( "Input is required.",
683 ErrorTag.MALFORMED_MESSAGE );
686 URI payloadNS = this.namespace(payload);
687 if (payloadNS == null) {
688 throw new RestconfDocumentedException(
689 "Data has bad format. Root element node must have namespace (XML format) or module name(JSON format)",
690 ErrorType.PROTOCOL, ErrorTag.UNKNOWN_NAMESPACE );
693 InstanceIdWithSchemaNode iiWithData = null;
694 CompositeNode value = null;
695 if (this.representsMountPointRootData(payload)) {
696 // payload represents mount point data and URI represents path to the mount point
698 if (this.endsWithMountPoint(identifier)) {
699 throw new RestconfDocumentedException(
700 "URI has bad format. URI should be without \"" + ControllerContext.MOUNT +
701 "\" for POST operation.",
702 ErrorType.PROTOCOL, ErrorTag.INVALID_VALUE );
705 final String completeIdentifier = this.addMountPointIdentifier(identifier);
706 iiWithData = this.controllerContext.toInstanceIdentifier(completeIdentifier);
708 value = this.normalizeNode(payload, iiWithData.getSchemaNode(), iiWithData.getMountPoint());
711 final InstanceIdWithSchemaNode incompleteInstIdWithData =
712 this.controllerContext.toInstanceIdentifier(identifier);
713 final DataNodeContainer parentSchema = (DataNodeContainer) incompleteInstIdWithData.getSchemaNode();
714 MountInstance mountPoint = incompleteInstIdWithData.getMountPoint();
715 final Module module = this.findModule(mountPoint, payload);
716 if (module == null) {
717 throw new RestconfDocumentedException(
718 "Module was not found for \"" + payloadNS + "\"",
719 ErrorType.PROTOCOL, ErrorTag.UNKNOWN_ELEMENT );
722 String payloadName = this.getName(payload);
723 final DataSchemaNode schemaNode = this.controllerContext.findInstanceDataChildByNameAndNamespace(
724 parentSchema, payloadName, module.getNamespace());
725 value = this.normalizeNode(payload, schemaNode, mountPoint);
727 iiWithData = this.addLastIdentifierFromData(incompleteInstIdWithData, value, schemaNode);
730 RpcResult<TransactionStatus> status = null;
731 MountInstance mountPoint = iiWithData.getMountPoint();
733 if (mountPoint != null) {
734 Future<RpcResult<TransactionStatus>> future =
735 broker.commitConfigurationDataPostBehindMountPoint(
736 mountPoint, iiWithData.getInstanceIdentifier(), value);
737 status = future == null ? null : future.get();
740 Future<RpcResult<TransactionStatus>> future =
741 broker.commitConfigurationDataPost(iiWithData.getInstanceIdentifier(), value);
742 status = future == null ? null : future.get();
745 catch( Exception e ) {
746 throw new RestconfDocumentedException( "Error creating data", e );
749 if (status == null) {
750 return Response.status(Status.ACCEPTED).build();
753 if( status.getResult() == TransactionStatus.COMMITED ) {
754 return Response.status(Status.NO_CONTENT).build();
757 return Response.status(Status.INTERNAL_SERVER_ERROR).build();
761 public Response createConfigurationData(final CompositeNode payload) {
762 if( payload == null ) {
763 throw new RestconfDocumentedException( "Input is required.",
765 ErrorTag.MALFORMED_MESSAGE );
768 URI payloadNS = this.namespace(payload);
769 if (payloadNS == null) {
770 throw new RestconfDocumentedException(
771 "Data has bad format. Root element node must have namespace (XML format) or module name(JSON format)",
772 ErrorType.PROTOCOL, ErrorTag.UNKNOWN_NAMESPACE );
775 final Module module = this.findModule(null, payload);
776 if (module == null) {
777 throw new RestconfDocumentedException(
778 "Data has bad format. Root element node has incorrect namespace (XML format) or module name(JSON format)",
779 ErrorType.PROTOCOL, ErrorTag.UNKNOWN_NAMESPACE );
782 String payloadName = this.getName(payload);
783 final DataSchemaNode schemaNode = this.controllerContext.findInstanceDataChildByNameAndNamespace(
784 module, payloadName, module.getNamespace());
785 final CompositeNode value = this.normalizeNode(payload, schemaNode, null);
786 final InstanceIdWithSchemaNode iiWithData = this.addLastIdentifierFromData(null, value, schemaNode);
787 RpcResult<TransactionStatus> status = null;
788 MountInstance mountPoint = iiWithData.getMountPoint();
791 if (mountPoint != null) {
792 Future<RpcResult<TransactionStatus>> future =
793 broker.commitConfigurationDataPostBehindMountPoint(
794 mountPoint, iiWithData.getInstanceIdentifier(), value);
795 status = future == null ? null : future.get();
798 Future<RpcResult<TransactionStatus>> future =
799 broker.commitConfigurationDataPost(iiWithData.getInstanceIdentifier(), value);
800 status = future == null ? null : future.get();
803 catch( Exception e ) {
804 throw new RestconfDocumentedException( "Error creating data", e );
807 if (status == null) {
808 return Response.status(Status.ACCEPTED).build();
811 if( status.getResult() == TransactionStatus.COMMITED ) {
812 return Response.status(Status.NO_CONTENT).build();
815 return Response.status(Status.INTERNAL_SERVER_ERROR).build();
819 public Response deleteConfigurationData(final String identifier) {
820 final InstanceIdWithSchemaNode iiWithData = this.controllerContext.toInstanceIdentifier(identifier);
821 RpcResult<TransactionStatus> status = null;
822 MountInstance mountPoint = iiWithData.getMountPoint();
825 if (mountPoint != null) {
826 status = broker.commitConfigurationDataDeleteBehindMountPoint(
827 mountPoint, iiWithData.getInstanceIdentifier()).get();
830 status = broker.commitConfigurationDataDelete(iiWithData.getInstanceIdentifier()).get();
833 catch( Exception e ) {
834 throw new RestconfDocumentedException( "Error creating data", e );
837 if( status.getResult() == TransactionStatus.COMMITED ) {
838 return Response.status(Status.OK).build();
841 return Response.status(Status.INTERNAL_SERVER_ERROR).build();
845 public Response subscribeToStream(final String identifier, final UriInfo uriInfo) {
846 final String streamName = Notificator.createStreamNameFromUri(identifier);
847 if (Strings.isNullOrEmpty(streamName)) {
848 throw new RestconfDocumentedException(
849 "Stream name is empty.", ErrorType.PROTOCOL, ErrorTag.INVALID_VALUE );
852 final ListenerAdapter listener = Notificator.getListenerFor(streamName);
853 if (listener == null) {
854 throw new RestconfDocumentedException(
855 "Stream was not found.", ErrorType.PROTOCOL, ErrorTag.UNKNOWN_ELEMENT );
858 broker.registerToListenDataChanges(listener);
860 final UriBuilder uriBuilder = uriInfo.getAbsolutePathBuilder();
861 UriBuilder port = uriBuilder.port(WebSocketServer.PORT);
862 final URI uriToWebsocketServer = port.replacePath(streamName).build();
864 return Response.status(Status.OK).location(uriToWebsocketServer).build();
867 private Module findModule(final MountInstance mountPoint, final CompositeNode data) {
868 if (data instanceof CompositeNodeWrapper) {
869 return findModule(mountPoint, (CompositeNodeWrapper)data);
871 else if (data != null) {
872 URI namespace = data.getNodeType().getNamespace();
873 if (mountPoint != null) {
874 return this.controllerContext.findModuleByNamespace(mountPoint, namespace);
877 return this.controllerContext.findModuleByNamespace(namespace);
881 throw new IllegalArgumentException("Unhandled parameter types: " +
882 Arrays.<Object>asList(mountPoint, data).toString());
886 private Module findModule(final MountInstance mountPoint, final CompositeNodeWrapper data) {
887 URI namespace = data.getNamespace();
888 Preconditions.<URI>checkNotNull(namespace);
890 Module module = null;
891 if (mountPoint != null) {
892 module = this.controllerContext.findModuleByNamespace(mountPoint, namespace);
893 if (module == null) {
894 module = this.controllerContext.findModuleByName(mountPoint, namespace.toString());
898 module = this.controllerContext.findModuleByNamespace(namespace);
899 if (module == null) {
900 module = this.controllerContext.findModuleByName(namespace.toString());
907 private InstanceIdWithSchemaNode addLastIdentifierFromData(
908 final InstanceIdWithSchemaNode identifierWithSchemaNode,
909 final CompositeNode data, final DataSchemaNode schemaOfData) {
910 InstanceIdentifier instanceIdentifier = null;
911 if (identifierWithSchemaNode != null) {
912 instanceIdentifier = identifierWithSchemaNode.getInstanceIdentifier();
915 final InstanceIdentifier iiOriginal = instanceIdentifier;
916 InstanceIdentifierBuilder iiBuilder = null;
917 if (iiOriginal == null) {
918 iiBuilder = InstanceIdentifier.builder();
921 iiBuilder = InstanceIdentifier.builder(iiOriginal);
924 if ((schemaOfData instanceof ListSchemaNode)) {
925 HashMap<QName,Object> keys = this.resolveKeysFromData(((ListSchemaNode) schemaOfData), data);
926 iiBuilder.nodeWithKey(schemaOfData.getQName(), keys);
929 iiBuilder.node(schemaOfData.getQName());
932 InstanceIdentifier instance = iiBuilder.toInstance();
933 MountInstance mountPoint = null;
934 if (identifierWithSchemaNode != null) {
935 mountPoint=identifierWithSchemaNode.getMountPoint();
938 return new InstanceIdWithSchemaNode(instance, schemaOfData, mountPoint);
941 private HashMap<QName,Object> resolveKeysFromData(final ListSchemaNode listNode,
942 final CompositeNode dataNode) {
943 final HashMap<QName,Object> keyValues = new HashMap<QName, Object>();
944 List<QName> _keyDefinition = listNode.getKeyDefinition();
945 for (final QName key : _keyDefinition) {
946 SimpleNode<? extends Object> head = null;
947 String localName = key.getLocalName();
948 List<SimpleNode<? extends Object>> simpleNodesByName = dataNode.getSimpleNodesByName(localName);
949 if (simpleNodesByName != null) {
950 head = Iterables.getFirst(simpleNodesByName, null);
953 Object dataNodeKeyValueObject = null;
955 dataNodeKeyValueObject = head.getValue();
958 if (dataNodeKeyValueObject == null) {
959 throw new RestconfDocumentedException(
960 "Data contains list \"" + dataNode.getNodeType().getLocalName() +
961 "\" which does not contain key: \"" + key.getLocalName() + "\"",
962 ErrorType.PROTOCOL, ErrorTag.INVALID_VALUE );
965 keyValues.put(key, dataNodeKeyValueObject);
971 private boolean endsWithMountPoint(final String identifier) {
972 return identifier.endsWith(ControllerContext.MOUNT) ||
973 identifier.endsWith(ControllerContext.MOUNT + "/");
976 private boolean representsMountPointRootData(final CompositeNode data) {
977 URI namespace = this.namespace(data);
978 return (SchemaContext.NAME.getNamespace().equals( namespace ) /* ||
979 MOUNT_POINT_MODULE_NAME.equals( namespace.toString() )*/ ) &&
980 SchemaContext.NAME.getLocalName().equals( this.localName(data) );
983 private String addMountPointIdentifier(final String identifier) {
984 boolean endsWith = identifier.endsWith("/");
986 return (identifier + ControllerContext.MOUNT);
989 return identifier + "/" + ControllerContext.MOUNT;
992 private CompositeNode normalizeNode(final CompositeNode node, final DataSchemaNode schema,
993 final MountInstance mountPoint) {
994 if (schema == null) {
995 QName nodeType = node == null ? null : node.getNodeType();
996 String localName = nodeType == null ? null : nodeType.getLocalName();
998 throw new RestconfDocumentedException(
999 "Data schema node was not found for " + localName,
1000 ErrorType.PROTOCOL, ErrorTag.INVALID_VALUE );
1003 if (!(schema instanceof DataNodeContainer)) {
1004 throw new RestconfDocumentedException(
1005 "Root element has to be container or list yang datatype.",
1006 ErrorType.PROTOCOL, ErrorTag.INVALID_VALUE );
1009 if ((node instanceof CompositeNodeWrapper)) {
1010 boolean isChangeAllowed = ((CompositeNodeWrapper) node).isChangeAllowed();
1011 if (isChangeAllowed) {
1013 this.normalizeNode(((CompositeNodeWrapper) node), schema, null, mountPoint);
1015 catch (IllegalArgumentException e) {
1016 throw new RestconfDocumentedException(
1017 e.getMessage(), ErrorType.PROTOCOL, ErrorTag.INVALID_VALUE );
1021 return ((CompositeNodeWrapper) node).unwrap();
1027 private void normalizeNode(final NodeWrapper<? extends Object> nodeBuilder,
1028 final DataSchemaNode schema, final QName previousAugment,
1029 final MountInstance mountPoint) {
1030 if (schema == null) {
1031 throw new RestconfDocumentedException(
1032 "Data has bad format.\n\"" + nodeBuilder.getLocalName() +
1033 "\" does not exist in yang schema.",
1034 ErrorType.PROTOCOL, ErrorTag.INVALID_VALUE );
1037 QName currentAugment = null;
1038 if (nodeBuilder.getQname() != null) {
1039 currentAugment = previousAugment;
1042 currentAugment = this.normalizeNodeName(nodeBuilder, schema, previousAugment, mountPoint);
1043 if (nodeBuilder.getQname() == null) {
1044 throw new RestconfDocumentedException(
1045 "Data has bad format.\nIf data is in XML format then namespace for \"" +
1046 nodeBuilder.getLocalName() +
1047 "\" should be \"" + schema.getQName().getNamespace() + "\".\n" +
1048 "If data is in JSON format then module name for \"" + nodeBuilder.getLocalName() +
1049 "\" should be corresponding to namespace \"" +
1050 schema.getQName().getNamespace() + "\".",
1051 ErrorType.PROTOCOL, ErrorTag.INVALID_VALUE );
1055 if ( nodeBuilder instanceof CompositeNodeWrapper ) {
1056 if( schema instanceof DataNodeContainer ) {
1057 normalizeCompositeNode( (CompositeNodeWrapper)nodeBuilder, (DataNodeContainer)schema,
1058 mountPoint, currentAugment );
1060 else if( schema instanceof AnyXmlSchemaNode ) {
1061 normalizeAnyXmlNode( (CompositeNodeWrapper)nodeBuilder, (AnyXmlSchemaNode)schema );
1064 else if ( nodeBuilder instanceof SimpleNodeWrapper ) {
1065 normalizeSimpleNode( (SimpleNodeWrapper) nodeBuilder, schema, mountPoint );
1067 else if ((nodeBuilder instanceof EmptyNodeWrapper)) {
1068 normalizeEmptyNode( (EmptyNodeWrapper) nodeBuilder, schema );
1072 private void normalizeAnyXmlNode( final CompositeNodeWrapper compositeNode, final AnyXmlSchemaNode schema ) {
1073 List<NodeWrapper<?>> children = compositeNode.getValues();
1074 for( NodeWrapper<? extends Object> child : children ) {
1075 child.setNamespace( schema.getQName().getNamespace() );
1076 if( child instanceof CompositeNodeWrapper ) {
1077 normalizeAnyXmlNode( (CompositeNodeWrapper)child, schema );
1082 private void normalizeEmptyNode( final EmptyNodeWrapper emptyNodeBuilder, final DataSchemaNode schema ) {
1083 if ((schema instanceof LeafSchemaNode)) {
1084 emptyNodeBuilder.setComposite(false);
1087 if ((schema instanceof ContainerSchemaNode)) {
1088 // FIXME: Add presence check
1089 emptyNodeBuilder.setComposite(true);
1094 private void normalizeSimpleNode( final SimpleNodeWrapper simpleNode, final DataSchemaNode schema,
1095 final MountInstance mountPoint ) {
1096 final Object value = simpleNode.getValue();
1097 Object inputValue = value;
1098 TypeDefinition<? extends Object> typeDefinition = this.typeDefinition(schema);
1099 if ((typeDefinition instanceof IdentityrefTypeDefinition)) {
1100 if ((value instanceof String)) {
1101 inputValue = new IdentityValuesDTO( simpleNode.getNamespace().toString(),
1102 (String) value, null, (String) value );
1103 } // else value is already instance of IdentityValuesDTO
1106 Object outputValue = inputValue;
1108 if( typeDefinition != null ) {
1109 Codec<Object,Object> codec = RestCodec.from(typeDefinition, mountPoint);
1110 outputValue = codec == null ? null : codec.deserialize(inputValue);
1113 simpleNode.setValue(outputValue);
1116 private void normalizeCompositeNode( final CompositeNodeWrapper compositeNodeBuilder,
1117 final DataNodeContainer schema, final MountInstance mountPoint,
1118 final QName currentAugment ) {
1119 final List<NodeWrapper<?>> children = compositeNodeBuilder.getValues();
1120 for (final NodeWrapper<? extends Object> child : children) {
1121 final List<DataSchemaNode> potentialSchemaNodes =
1122 this.controllerContext.findInstanceDataChildrenByName(
1123 schema, child.getLocalName());
1125 if (potentialSchemaNodes.size() > 1 && child.getNamespace() == null) {
1126 StringBuilder builder = new StringBuilder();
1127 for (final DataSchemaNode potentialSchemaNode : potentialSchemaNodes) {
1128 builder.append(" ").append(potentialSchemaNode.getQName().getNamespace().toString())
1132 throw new RestconfDocumentedException(
1133 "Node \"" + child.getLocalName() +
1134 "\" is added as augment from more than one module. " +
1135 "Therefore node must have namespace (XML format) or module name (JSON format)." +
1136 "\nThe node is added as augment from modules with namespaces:\n" + builder,
1137 ErrorType.PROTOCOL, ErrorTag.INVALID_VALUE );
1140 boolean rightNodeSchemaFound = false;
1141 for (final DataSchemaNode potentialSchemaNode : potentialSchemaNodes) {
1142 if (!rightNodeSchemaFound) {
1143 final QName potentialCurrentAugment =
1144 this.normalizeNodeName(child, potentialSchemaNode, currentAugment, mountPoint);
1145 if (child.getQname() != null ) {
1146 this.normalizeNode(child, potentialSchemaNode, potentialCurrentAugment, mountPoint);
1147 rightNodeSchemaFound = true;
1152 if (!rightNodeSchemaFound) {
1153 throw new RestconfDocumentedException(
1154 "Schema node \"" + child.getLocalName() + "\" was not found in module.",
1155 ErrorType.APPLICATION, ErrorTag.UNKNOWN_ELEMENT );
1159 if ((schema instanceof ListSchemaNode)) {
1160 ListSchemaNode listSchemaNode = (ListSchemaNode)schema;
1161 final List<QName> listKeys = listSchemaNode.getKeyDefinition();
1162 for (final QName listKey : listKeys) {
1163 boolean foundKey = false;
1164 for (final NodeWrapper<? extends Object> child : children) {
1165 if (Objects.equal(child.unwrap().getNodeType().getLocalName(), listKey.getLocalName())) {
1171 throw new RestconfDocumentedException(
1172 "Missing key in URI \"" + listKey.getLocalName() +
1173 "\" of list \"" + listSchemaNode.getQName().getLocalName() + "\"",
1174 ErrorType.PROTOCOL, ErrorTag.INVALID_VALUE );
1180 private QName normalizeNodeName(final NodeWrapper<? extends Object> nodeBuilder,
1181 final DataSchemaNode schema, final QName previousAugment,
1182 final MountInstance mountPoint) {
1183 QName validQName = schema.getQName();
1184 QName currentAugment = previousAugment;
1185 if (schema.isAugmenting()) {
1186 currentAugment = schema.getQName();
1188 else if (previousAugment != null &&
1189 !Objects.equal( schema.getQName().getNamespace(), previousAugment.getNamespace())) {
1190 validQName = QName.create(currentAugment, schema.getQName().getLocalName());
1193 String moduleName = null;
1194 if (mountPoint == null) {
1195 moduleName = controllerContext.findModuleNameByNamespace(validQName.getNamespace());
1198 moduleName = controllerContext.findModuleNameByNamespace(mountPoint, validQName.getNamespace());
1201 if (nodeBuilder.getNamespace() == null ||
1202 Objects.equal(nodeBuilder.getNamespace(), validQName.getNamespace()) ||
1203 Objects.equal(nodeBuilder.getNamespace().toString(), moduleName) /*||
1204 Note: this check is wrong - can never be true as it compares a URI with a String
1205 not sure what the intention is so commented out...
1206 Objects.equal(nodeBuilder.getNamespace(), MOUNT_POINT_MODULE_NAME)*/ ) {
1208 nodeBuilder.setQname(validQName);
1211 return currentAugment;
1214 private URI namespace(final CompositeNode data) {
1215 if (data instanceof CompositeNodeWrapper) {
1216 return ((CompositeNodeWrapper)data).getNamespace();
1218 else if (data != null) {
1219 return data.getNodeType().getNamespace();
1222 throw new IllegalArgumentException("Unhandled parameter types: " +
1223 Arrays.<Object>asList(data).toString());
1227 private String localName(final CompositeNode data) {
1228 if (data instanceof CompositeNodeWrapper) {
1229 return ((CompositeNodeWrapper)data).getLocalName();
1231 else if (data != null) {
1232 return data.getNodeType().getLocalName();
1235 throw new IllegalArgumentException("Unhandled parameter types: " +
1236 Arrays.<Object>asList(data).toString());
1240 private String getName(final CompositeNode data) {
1241 if (data instanceof CompositeNodeWrapper) {
1242 return ((CompositeNodeWrapper)data).getLocalName();
1244 else if (data != null) {
1245 return data.getNodeType().getLocalName();
1248 throw new IllegalArgumentException("Unhandled parameter types: " +
1249 Arrays.<Object>asList(data).toString());
1253 private TypeDefinition<? extends Object> _typeDefinition(final LeafSchemaNode node) {
1254 TypeDefinition<?> baseType = node.getType();
1255 while (baseType.getBaseType() != null) {
1256 baseType = baseType.getBaseType();
1262 private TypeDefinition<? extends Object> typeDefinition(final LeafListSchemaNode node) {
1263 TypeDefinition<?> baseType = node.getType();
1264 while (baseType.getBaseType() != null) {
1265 baseType = baseType.getBaseType();
1271 private TypeDefinition<? extends Object> typeDefinition(final DataSchemaNode node) {
1272 if (node instanceof LeafListSchemaNode) {
1273 return typeDefinition((LeafListSchemaNode)node);
1275 else if (node instanceof LeafSchemaNode) {
1276 return _typeDefinition((LeafSchemaNode)node);
1278 else if (node instanceof AnyXmlSchemaNode) {
1282 throw new IllegalArgumentException("Unhandled parameter types: " +
1283 Arrays.<Object>asList(node).toString());