Merge "Reduce/enhance logging in AbstractLeader"
[controller.git] / opendaylight / md-sal / sal-rest-connector / src / main / java / org / opendaylight / controller / sal / restconf / impl / RestconfImpl.java
index e9a87090a7d0bcc317c66f413f289e9248b09680..5f5b9bafe10239dc9eb3df60e6435b916b54bd8a 100644 (file)
@@ -19,6 +19,7 @@ import com.google.common.collect.ImmutableList;
 import com.google.common.collect.Iterables;
 import com.google.common.collect.Lists;
 import com.google.common.util.concurrent.CheckedFuture;
+import com.google.common.util.concurrent.Futures;
 import java.math.BigInteger;
 import java.net.URI;
 import java.net.URISyntaxException;
@@ -50,6 +51,7 @@ import org.opendaylight.controller.md.sal.dom.api.DOMMountPoint;
 import org.opendaylight.controller.md.sal.dom.api.DOMRpcException;
 import org.opendaylight.controller.md.sal.dom.api.DOMRpcResult;
 import org.opendaylight.controller.md.sal.dom.api.DOMRpcService;
+import org.opendaylight.controller.md.sal.dom.spi.DefaultDOMRpcResult;
 import org.opendaylight.controller.sal.rest.api.Draft02;
 import org.opendaylight.controller.sal.rest.api.RestconfService;
 import org.opendaylight.controller.sal.restconf.impl.RestconfError.ErrorTag;
@@ -65,7 +67,6 @@ import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.common.QNameModule;
 import org.opendaylight.yangtools.yang.common.RpcResult;
 import org.opendaylight.yangtools.yang.data.api.CompositeNode;
-import org.opendaylight.yangtools.yang.data.api.MutableCompositeNode;
 import org.opendaylight.yangtools.yang.data.api.Node;
 import org.opendaylight.yangtools.yang.data.api.SimpleNode;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
@@ -74,6 +75,7 @@ import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdent
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
 import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
+import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
 import org.opendaylight.yangtools.yang.data.api.schema.LeafSetEntryNode;
 import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
 import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
@@ -83,9 +85,11 @@ import org.opendaylight.yangtools.yang.data.composite.node.schema.cnsn.parser.Cn
 import org.opendaylight.yangtools.yang.data.impl.ImmutableCompositeNode;
 import org.opendaylight.yangtools.yang.data.impl.NodeFactory;
 import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
+import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
 import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.CollectionNodeBuilder;
 import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContainerNodeAttrBuilder;
 import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.ListNodeBuilder;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableContainerNodeBuilder;
 import org.opendaylight.yangtools.yang.model.api.AnyXmlSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
@@ -469,7 +473,7 @@ public class RestconfImpl implements RestconfService {
         instanceDataChildrenByName = ControllerContext.findInstanceDataChildrenByName(
                 ((DataNodeContainer) streamSchemaNode), "events");
         final DataSchemaNode eventsSchemaNode = Iterables.getFirst(instanceDataChildrenByName, null);
-        streamNodeValues.add(NodeFactory.<String> createImmutableSimpleNode(eventsSchemaNode.getQName(), null, ""));
+        streamNodeValues.add(NodeFactory.<String>createImmutableSimpleNode(eventsSchemaNode.getQName(), null, ""));
 
         return NodeFactory.createImmutableCompositeNode(streamSchemaNode.getQName(), null, streamNodeValues);
     }
@@ -523,6 +527,7 @@ public class RestconfImpl implements RestconfService {
     @Override
     public NormalizedNodeContext invokeRpc(final String identifier, final NormalizedNodeContext payload, final UriInfo uriInfo) {
         final SchemaPath type = payload.getInstanceIdentifierContext().getSchemaNode().getPath();
+        final URI namespace = payload.getInstanceIdentifierContext().getSchemaNode().getQName().getNamespace();
         final CheckedFuture<DOMRpcResult, DOMRpcException> response;
         final DOMMountPoint mountPoint = payload.getInstanceIdentifierContext().getMountPoint();
         final SchemaContext schemaContext;
@@ -534,22 +539,24 @@ public class RestconfImpl implements RestconfService {
             schemaContext = mountPoint.getSchemaContext();
             response = mountRpcServices.get().invokeRpc(type, payload.getData());
         } else {
-            response = broker.invokeRpc(type, payload.getData());
+            if (namespace.toString().equals(SAL_REMOTE_NAMESPACE)) {
+                response = invokeSalRemoteRpcSubscribeRPC(payload);
+            } else {
+                response = broker.invokeRpc(type, payload.getData());
+            }
             schemaContext = controllerContext.getGlobalSchema();
         }
 
         final DOMRpcResult result = checkRpcResponse(response);
 
-        DataSchemaNode resultNodeSchema = null;
-        NormalizedNode<?, ?> resultData = null;
+        RpcDefinition resultNodeSchema = null;
+        final NormalizedNode<?, ?> resultData = result.getResult();
         if (result != null && result.getResult() != null) {
-            resultData = result.getResult();
-            final ContainerSchemaNode rpcDataSchemaNode = SchemaContextUtil.getRpcDataSchema(schemaContext, type);
-            resultNodeSchema = rpcDataSchemaNode.getDataChildByName(result.getResult().getNodeType());
+            resultNodeSchema = (RpcDefinition) payload.getInstanceIdentifierContext().getSchemaNode();
         }
 
-        return new NormalizedNodeContext(new InstanceIdentifierContext(null, resultNodeSchema, mountPoint,
-                schemaContext), resultData);
+        return new NormalizedNodeContext(new InstanceIdentifierContext<RpcDefinition>(null,
+                resultNodeSchema, mountPoint, schemaContext), resultData);
     }
 
     private DOMRpcResult checkRpcResponse(final CheckedFuture<DOMRpcResult, DOMRpcException> response) {
@@ -592,7 +599,7 @@ public class RestconfImpl implements RestconfService {
         }
     }
 
-    private void validateInput(final DataSchemaNode inputSchema, final NormalizedNodeContext payload) {
+    private void validateInput(final SchemaNode inputSchema, final NormalizedNodeContext payload) {
         if (inputSchema != null && payload.getData() == null) {
             // expected a non null payload
             throw new RestconfDocumentedException("Input is required.", ErrorType.PROTOCOL, ErrorTag.MALFORMED_MESSAGE);
@@ -631,16 +638,12 @@ public class RestconfImpl implements RestconfService {
         // }
     }
 
-    /**
-     * @deprecated method wil be removed for Lithium release
-     */
-    @Deprecated
-    private StructuredData invokeSalRemoteRpcSubscribeRPC(final CompositeNode payload, final RpcDefinition rpc,
-            final boolean prettyPrint) {
-        final CompositeNode value = this.normalizeNode(payload, rpc.getInput(), null);
-        final SimpleNode<? extends Object> pathNode = value == null ? null : value.getFirstSimpleByName(QName.create(
-                rpc.getQName(), "path"));
-        final Object pathValue = pathNode == null ? null : pathNode.getValue();
+    private CheckedFuture<DOMRpcResult, DOMRpcException> invokeSalRemoteRpcSubscribeRPC(final NormalizedNodeContext payload) {
+        final ContainerNode value = (ContainerNode) payload.getData();
+        final QName rpcQName = payload.getInstanceIdentifierContext().getSchemaNode().getQName();
+        final Optional<DataContainerChild<? extends PathArgument, ?>> path = value.getChild(new NodeIdentifier(
+                QName.create(payload.getInstanceIdentifierContext().getSchemaNode().getQName(), "path")));
+        final Object pathValue = path.isPresent() ? path.get().getValue() : null;
 
         if (!(pathValue instanceof YangInstanceIdentifier)) {
             throw new RestconfDocumentedException("Instance identifier was not normalized correctly.",
@@ -665,46 +668,96 @@ public class RestconfImpl implements RestconfService {
 
         if (Strings.isNullOrEmpty(streamName)) {
             throw new RestconfDocumentedException(
-                    "Path is empty or contains data node which is not Container or List build-in type.",
+                    "Path is empty or contains value node which is not Container or List build-in type.",
                     ErrorType.PROTOCOL, ErrorTag.INVALID_VALUE);
         }
 
-        final SimpleNode<String> streamNameNode = NodeFactory.<String> createImmutableSimpleNode(
-                QName.create(rpc.getOutput().getQName(), "stream-name"), null, streamName);
-        final List<Node<?>> output = new ArrayList<Node<?>>();
-        output.add(streamNameNode);
+        final QName outputQname = QName.create(rpcQName, "output");
+        final QName streamNameQname = QName.create(rpcQName, "stream-name");
 
-        final MutableCompositeNode responseData = NodeFactory.createMutableCompositeNode(rpc.getOutput().getQName(),
-                null, output, null, null);
+        final ContainerNode output = ImmutableContainerNodeBuilder.create().withNodeIdentifier(new NodeIdentifier(outputQname))
+                .withChild(ImmutableNodes.leafNode(streamNameQname, streamName)).build();
 
         if (!Notificator.existListenerFor(streamName)) {
-            Notificator.createListener(pathIdentifier, streamName);
+            final YangInstanceIdentifier normalizedPathIdentifier = controllerContext.toNormalized(pathIdentifier);
+            Notificator.createListener(normalizedPathIdentifier, streamName);
         }
 
-        return new StructuredData(responseData, rpc.getOutput(), null, prettyPrint);
+        final DOMRpcResult defaultDOMRpcResult = new DefaultDOMRpcResult(output);
+
+        return Futures.immediateCheckedFuture(defaultDOMRpcResult);
     }
 
     @Override
-    public StructuredData invokeRpc(final String identifier, final String noPayload, final UriInfo uriInfo) {
+    public NormalizedNodeContext invokeRpc(final String identifier, final String noPayload, final UriInfo uriInfo) {
         if (StringUtils.isNotBlank(noPayload)) {
             throw new RestconfDocumentedException("Content must be empty.", ErrorType.PROTOCOL, ErrorTag.INVALID_VALUE);
         }
-        final CompositeNode payload = null;
-        final RpcExecutor rpc = resolveIdentifierInInvokeRpc(identifier);
-        final QName rpcName = rpc.getRpcDefinition().getQName();
-        final URI rpcNamespace = rpcName.getNamespace();
-        if (Objects.equal(rpcNamespace.toString(), SAL_REMOTE_NAMESPACE)
-                && Objects.equal(rpcName.getLocalName(), SAL_REMOTE_RPC_SUBSRCIBE)) {
-            return invokeSalRemoteRpcSubscribeRPC(payload, rpc.getRpcDefinition(), parsePrettyPrintParameter(uriInfo));
+
+        String identifierEncoded = null;
+        DOMMountPoint mountPoint = null;
+        final SchemaContext schemaContext;
+        if (identifier.contains(ControllerContext.MOUNT)) {
+            // mounted RPC call - look up mount instance.
+            final InstanceIdentifierContext mountPointId = controllerContext.toMountPointIdentifier(identifier);
+            mountPoint = mountPointId.getMountPoint();
+            schemaContext = mountPoint.getSchemaContext();
+            final int startOfRemoteRpcName = identifier.lastIndexOf(ControllerContext.MOUNT)
+                    + ControllerContext.MOUNT.length() + 1;
+            final String remoteRpcName = identifier.substring(startOfRemoteRpcName);
+            identifierEncoded = remoteRpcName;
+
+        } else if (identifier.indexOf("/") != CHAR_NOT_FOUND) {
+            final String slashErrorMsg = String.format("Identifier %n%s%ncan\'t contain slash "
+                    + "character (/).%nIf slash is part of identifier name then use %%2F placeholder.", identifier);
+            throw new RestconfDocumentedException(slashErrorMsg, ErrorType.PROTOCOL, ErrorTag.INVALID_VALUE);
+        } else {
+            identifierEncoded = identifier;
+            schemaContext = controllerContext.getGlobalSchema();
+        }
+
+        final String identifierDecoded = controllerContext.urlPathArgDecode(identifierEncoded);
+
+        RpcDefinition rpc = null;
+        if (mountPoint == null) {
+            rpc = controllerContext.getRpcDefinition(identifierDecoded);
+        } else {
+            rpc = findRpc(mountPoint.getSchemaContext(), identifierDecoded);
         }
 
-        validateInput(rpc.getRpcDefinition().getInput(), payload);
+        if (rpc == null) {
+            throw new RestconfDocumentedException("RPC does not exist.", ErrorType.RPC, ErrorTag.UNKNOWN_ELEMENT);
+        }
 
-        return callRpc(rpc, payload, parsePrettyPrintParameter(uriInfo));
-    }
+        if (rpc.getInput() != null) {
+            // FIXME : find a correct Error from specification
+            throw new IllegalStateException("RPC " + rpc + " does'n need input value!");
+        }
 
-    private void resolveInvokeRpc(final String identifier, final DOMMountPoint mountPoint) {
+        final CheckedFuture<DOMRpcResult, DOMRpcException> response;
+        if (mountPoint != null) {
+            final Optional<DOMRpcService> mountRpcServices = mountPoint.getService(DOMRpcService.class);
+            if ( ! mountRpcServices.isPresent()) {
+                throw new RestconfDocumentedException("Rpc service is missing.");
+            }
+            response = mountRpcServices.get().invokeRpc(rpc.getPath(), null);
+        } else {
+            response = broker.invokeRpc(rpc.getPath(), null);
+        }
+
+        final DOMRpcResult result = checkRpcResponse(response);
+
+        DataSchemaNode resultNodeSchema = null;
+        NormalizedNode<?, ?> resultData = null;
+        if (result != null && result.getResult() != null) {
+            resultData = result.getResult();
+            final ContainerSchemaNode rpcDataSchemaNode =
+                    SchemaContextUtil.getRpcDataSchema(schemaContext, rpc.getOutput().getPath());
+            resultNodeSchema = rpcDataSchemaNode.getDataChildByName(result.getResult().getNodeType());
+        }
 
+        return new NormalizedNodeContext(new InstanceIdentifierContext(null, resultNodeSchema, mountPoint,
+                schemaContext), resultData);
     }
 
     private RpcExecutor resolveIdentifierInInvokeRpc(final String identifier) {
@@ -817,15 +870,17 @@ public class RestconfImpl implements RestconfService {
         final InstanceIdentifierContext iiWithData = controllerContext.toInstanceIdentifier(identifier);
         final DOMMountPoint mountPoint = iiWithData.getMountPoint();
         NormalizedNode<?, ?> data = null;
-        YangInstanceIdentifier normalizedII;
+        final YangInstanceIdentifier normalizedII = iiWithData.getInstanceIdentifier();
         if (mountPoint != null) {
-            normalizedII = new DataNormalizer(mountPoint.getSchemaContext()).toNormalized(iiWithData
-                    .getInstanceIdentifier());
             data = broker.readConfigurationData(mountPoint, normalizedII);
         } else {
-            normalizedII = controllerContext.toNormalized(iiWithData.getInstanceIdentifier());
             data = broker.readConfigurationData(normalizedII);
         }
+        if(data == null) {
+            throw new RestconfDocumentedException(
+                "Request could not be completed because the relevant data model content does not exist.",
+                ErrorType.APPLICATION, ErrorTag.DATA_MISSING);
+        }
         return new NormalizedNodeContext(iiWithData, data);
     }
 
@@ -876,16 +931,17 @@ public class RestconfImpl implements RestconfService {
         final InstanceIdentifierContext iiWithData = controllerContext.toInstanceIdentifier(identifier);
         final DOMMountPoint mountPoint = iiWithData.getMountPoint();
         NormalizedNode<?, ?> data = null;
-        YangInstanceIdentifier normalizedII;
+        final YangInstanceIdentifier normalizedII = iiWithData.getInstanceIdentifier();
         if (mountPoint != null) {
-            normalizedII = new DataNormalizer(mountPoint.getSchemaContext()).toNormalized(iiWithData
-                    .getInstanceIdentifier());
             data = broker.readOperationalData(mountPoint, normalizedII);
         } else {
-            normalizedII = controllerContext.toNormalized(iiWithData.getInstanceIdentifier());
             data = broker.readOperationalData(normalizedII);
         }
-
+        if(data == null) {
+            throw new RestconfDocumentedException(
+                "Request could not be completed because the relevant data model content does not exist.",
+                ErrorType.APPLICATION, ErrorTag.DATA_MISSING);
+        }
         return new NormalizedNodeContext(iiWithData, data);
     }
 
@@ -897,7 +953,8 @@ public class RestconfImpl implements RestconfService {
     @Override
     public Response updateConfigurationData(final String identifier, final NormalizedNodeContext payload) {
         Preconditions.checkNotNull(identifier);
-        final InstanceIdentifierContext<DataSchemaNode> iiWithData = controllerContext.toInstanceIdentifier(identifier);
+        final InstanceIdentifierContext<DataSchemaNode> iiWithData =
+                (InstanceIdentifierContext<DataSchemaNode>) payload.getInstanceIdentifierContext();
 
         validateInput(iiWithData.getSchemaNode(), payload);
         validateTopLevelNodeName(payload, iiWithData.getInstanceIdentifier());
@@ -1007,7 +1064,7 @@ public class RestconfImpl implements RestconfService {
      *             if key values or key count in payload and URI isn't equal
      *
      */
-    private void validateListKeysEqualityInPayloadAndUri(final InstanceIdentifierContext iiWithData,
+    private void validateListKeysEqualityInPayloadAndUri(final InstanceIdentifierContext<DataSchemaNode> iiWithData,
             final NormalizedNode<?, ?> payload) {
         if (iiWithData.getSchemaNode() instanceof ListSchemaNode) {
             final List<QName> keyDefinitions = ((ListSchemaNode) iiWithData.getSchemaNode()).getKeyDefinition();
@@ -1103,43 +1160,7 @@ public class RestconfImpl implements RestconfService {
 
     @Override
     public Response createConfigurationData(final String identifier, final NormalizedNodeContext payload, final UriInfo uriInfo) {
-        if (payload == null) {
-            throw new RestconfDocumentedException("Input is required.", ErrorType.PROTOCOL, ErrorTag.MALFORMED_MESSAGE);
-        }
-
-        final URI payloadNS = payload.getData().getNodeType().getNamespace();
-        if (payloadNS == null) {
-            throw new RestconfDocumentedException(
-                    "Data has bad format. Root element node must have namespace (XML format) or module name(JSON format)",
-                    ErrorType.PROTOCOL, ErrorTag.UNKNOWN_NAMESPACE);
-        }
-
-        final DOMMountPoint mountPoint = payload.getInstanceIdentifierContext().getMountPoint();
-
-        final InstanceIdentifierContext iiWithData = mountPoint != null
-                ? controllerContext.toMountPointIdentifier(identifier)
-                : controllerContext.toInstanceIdentifier(identifier);
-        final YangInstanceIdentifier normalizedII = iiWithData.getInstanceIdentifier();
-
-        try {
-            if (mountPoint != null) {
-                broker.commitConfigurationDataPost(mountPoint, normalizedII, payload.getData());
-            } else {
-                broker.commitConfigurationDataPost(normalizedII, payload.getData());
-            }
-        } catch(final RestconfDocumentedException e) {
-            throw e;
-        } catch (final Exception e) {
-            throw new RestconfDocumentedException("Error creating data", e);
-        }
-
-
-        final ResponseBuilder responseBuilder = Response.status(Status.NO_CONTENT);
-        final URI location = resolveLocation(uriInfo, "config", mountPoint, normalizedII);
-        if (location != null) {
-            responseBuilder.location(location);
-        }
-        return responseBuilder.build();
+       return createConfigurationData(payload, uriInfo);
     }
 
     // FIXME create RestconfIdetifierHelper and move this method there
@@ -1186,9 +1207,9 @@ public class RestconfImpl implements RestconfService {
         }
 
         final DOMMountPoint mountPoint = payload.getInstanceIdentifierContext().getMountPoint();
-        final InstanceIdentifierContext iiWithData = payload.getInstanceIdentifierContext();
+        final InstanceIdentifierContext<DataSchemaNode> iiWithData = (InstanceIdentifierContext<DataSchemaNode>) payload.getInstanceIdentifierContext();
         final YangInstanceIdentifier normalizedII = iiWithData.getInstanceIdentifier();
-
+        final YangInstanceIdentifier resultII;
         try {
             if (mountPoint != null) {
                 broker.commitConfigurationDataPost(mountPoint, normalizedII, payload.getData());
@@ -1203,6 +1224,7 @@ public class RestconfImpl implements RestconfService {
         }
 
         final ResponseBuilder responseBuilder = Response.status(Status.NO_CONTENT);
+        // FIXME: Provide path to result.
         final URI location = resolveLocation(uriInfo, "", mountPoint, normalizedII);
         if (location != null) {
             responseBuilder.location(location);
@@ -1224,17 +1246,14 @@ public class RestconfImpl implements RestconfService {
 
     @Override
     public Response deleteConfigurationData(final String identifier) {
-        final InstanceIdentifierContext iiWithData = controllerContext.toInstanceIdentifier(identifier);
+        final InstanceIdentifierContext<DataSchemaNode> iiWithData = controllerContext.toInstanceIdentifier(identifier);
         final DOMMountPoint mountPoint = iiWithData.getMountPoint();
-        YangInstanceIdentifier normalizedII;
+        final YangInstanceIdentifier normalizedII = iiWithData.getInstanceIdentifier();
 
         try {
             if (mountPoint != null) {
-                normalizedII = new DataNormalizer(mountPoint.getSchemaContext()).toNormalized(iiWithData
-                        .getInstanceIdentifier());
                 broker.commitConfigurationDataDelete(mountPoint, normalizedII);
             } else {
-                normalizedII = controllerContext.toNormalized(iiWithData.getInstanceIdentifier());
                 broker.commitConfigurationDataDelete(normalizedII).get();
             }
         } catch (final Exception e) {
@@ -1292,8 +1311,8 @@ public class RestconfImpl implements RestconfService {
         } catch (final NullPointerException e) {
             WebSocketServer.createInstance(NOTIFICATION_PORT);
         }
-        final UriBuilder port = uriBuilder.port(notificationPort);
-        final URI uriToWebsocketServer = port.replacePath(streamName).build();
+        final UriBuilder uriToWebsocketServerBuilder = uriBuilder.port(notificationPort).scheme("ws");
+        final URI uriToWebsocketServer = uriToWebsocketServerBuilder.replacePath(streamName).build();
 
         return Response.status(Status.OK).location(uriToWebsocketServer).build();
     }
@@ -1305,15 +1324,16 @@ public class RestconfImpl implements RestconfService {
      *            contains value
      * @return enum object if its string value is equal to {@code paramName}. In other cases null.
      */
-    private <T> T parseEnumTypeParameter(final CompositeNode compNode, final Class<T> classDescriptor,
+    private <T> T parseEnumTypeParameter(final ContainerNode value, final Class<T> classDescriptor,
             final String paramName) {
         final QNameModule salRemoteAugment = QNameModule.create(NAMESPACE_EVENT_SUBSCRIPTION_AUGMENT,
                 EVENT_SUBSCRIPTION_AUGMENT_REVISION);
-        final SimpleNode<?> simpleNode = compNode.getFirstSimpleByName(QName.create(salRemoteAugment, paramName));
-        if (simpleNode == null) {
+        final Optional<DataContainerChild<? extends PathArgument, ?>> enumNode = value.getChild(new NodeIdentifier(
+                QName.create(salRemoteAugment, paramName)));
+        if (!enumNode.isPresent()) {
             return null;
         }
-        final Object rawValue = simpleNode.getValue();
+        final Object rawValue = enumNode.get().getValue();
         if (!(rawValue instanceof String)) {
             return null;
         }
@@ -1468,7 +1488,7 @@ public class RestconfImpl implements RestconfService {
          * || MOUNT_POINT_MODULE_NAME .equals( namespace .
          * toString( ) )
          */)
-         && SchemaContext.NAME.getLocalName().equals(localName(data));
+                && SchemaContext.NAME.getLocalName().equals(localName(data));
     }
 
     private String addMountPointIdentifier(final String identifier) {
@@ -1911,8 +1931,47 @@ public class RestconfImpl implements RestconfService {
 
     protected MapEntryNode toModuleEntryNode(final Module module, final DataSchemaNode moduleSchemaNode) {
         Preconditions.checkArgument(moduleSchemaNode instanceof ListSchemaNode,
-                "moduleSchemaNode has to be of type ListSchemaNode");\r        final ListSchemaNode listModuleSchemaNode = (ListSchemaNode) moduleSchemaNode;\r        final DataContainerNodeAttrBuilder<NodeIdentifierWithPredicates, MapEntryNode> moduleNodeValues = Builders\r                .mapEntryBuilder(listModuleSchemaNode);\r\r        List<DataSchemaNode> instanceDataChildrenByName = ControllerContext.findInstanceDataChildrenByName(\r                (listModuleSchemaNode), "name");\r        final DataSchemaNode nameSchemaNode = Iterables.getFirst(instanceDataChildrenByName, null);\r        Preconditions.checkState(nameSchemaNode instanceof LeafSchemaNode);\r        moduleNodeValues.withChild(Builders.leafBuilder((LeafSchemaNode) nameSchemaNode).withValue(module.getName())\r                .build());\r\r        instanceDataChildrenByName = ControllerContext.findInstanceDataChildrenByName(\r                (listModuleSchemaNode), "revision");\r        final DataSchemaNode revisionSchemaNode = Iterables.getFirst(instanceDataChildrenByName, null);\r        Preconditions.checkState(revisionSchemaNode instanceof LeafSchemaNode);\r        final String revision = REVISION_FORMAT.format(module.getRevision());\r        moduleNodeValues.withChild(Builders.leafBuilder((LeafSchemaNode) revisionSchemaNode).withValue(revision)\r                .build());\r\r        instanceDataChildrenByName = ControllerContext.findInstanceDataChildrenByName(\r                (listModuleSchemaNode), "namespace");\r        final DataSchemaNode namespaceSchemaNode = Iterables.getFirst(instanceDataChildrenByName, null);\r        Preconditions.checkState(namespaceSchemaNode instanceof LeafSchemaNode);\r        moduleNodeValues.withChild(Builders.leafBuilder((LeafSchemaNode) namespaceSchemaNode)\r                .withValue(module.getNamespace().toString()).build());\r\r        instanceDataChildrenByName = ControllerContext.findInstanceDataChildrenByName(\r                (listModuleSchemaNode), "feature");\r        final DataSchemaNode featureSchemaNode = Iterables.getFirst(instanceDataChildrenByName, null);\r        Preconditions.checkState(featureSchemaNode instanceof LeafListSchemaNode);\r        final ListNodeBuilder<Object, LeafSetEntryNode<Object>> featuresBuilder = Builders\r                .leafSetBuilder((LeafListSchemaNode) featureSchemaNode);\r        for (final FeatureDefinition feature : module.getFeatures()) {\r            featuresBuilder.withChild(Builders.leafSetEntryBuilder(((LeafListSchemaNode) featureSchemaNode))\r                    .withValue(feature.getQName().getLocalName()).build());\r        }\r        moduleNodeValues.withChild(featuresBuilder.build());
-\r        return moduleNodeValues.build();\r    }
+                "moduleSchemaNode has to be of type ListSchemaNode");
+        final ListSchemaNode listModuleSchemaNode = (ListSchemaNode) moduleSchemaNode;
+        final DataContainerNodeAttrBuilder<NodeIdentifierWithPredicates, MapEntryNode> moduleNodeValues = Builders
+                .mapEntryBuilder(listModuleSchemaNode);
+
+        List<DataSchemaNode> instanceDataChildrenByName = ControllerContext.findInstanceDataChildrenByName(
+                (listModuleSchemaNode), "name");
+        final DataSchemaNode nameSchemaNode = Iterables.getFirst(instanceDataChildrenByName, null);
+        Preconditions.checkState(nameSchemaNode instanceof LeafSchemaNode);
+        moduleNodeValues.withChild(Builders.leafBuilder((LeafSchemaNode) nameSchemaNode).withValue(module.getName())
+                .build());
+
+        instanceDataChildrenByName = ControllerContext.findInstanceDataChildrenByName(
+                (listModuleSchemaNode), "revision");
+        final DataSchemaNode revisionSchemaNode = Iterables.getFirst(instanceDataChildrenByName, null);
+        Preconditions.checkState(revisionSchemaNode instanceof LeafSchemaNode);
+        final String revision = REVISION_FORMAT.format(module.getRevision());
+        moduleNodeValues.withChild(Builders.leafBuilder((LeafSchemaNode) revisionSchemaNode).withValue(revision)
+                .build());
+
+        instanceDataChildrenByName = ControllerContext.findInstanceDataChildrenByName(
+                (listModuleSchemaNode), "namespace");
+        final DataSchemaNode namespaceSchemaNode = Iterables.getFirst(instanceDataChildrenByName, null);
+        Preconditions.checkState(namespaceSchemaNode instanceof LeafSchemaNode);
+        moduleNodeValues.withChild(Builders.leafBuilder((LeafSchemaNode) namespaceSchemaNode)
+                .withValue(module.getNamespace().toString()).build());
+
+        instanceDataChildrenByName = ControllerContext.findInstanceDataChildrenByName(
+                (listModuleSchemaNode), "feature");
+        final DataSchemaNode featureSchemaNode = Iterables.getFirst(instanceDataChildrenByName, null);
+        Preconditions.checkState(featureSchemaNode instanceof LeafListSchemaNode);
+        final ListNodeBuilder<Object, LeafSetEntryNode<Object>> featuresBuilder = Builders
+                .leafSetBuilder((LeafListSchemaNode) featureSchemaNode);
+        for (final FeatureDefinition feature : module.getFeatures()) {
+            featuresBuilder.withChild(Builders.leafSetEntryBuilder(((LeafListSchemaNode) featureSchemaNode))
+                    .withValue(feature.getQName().getLocalName()).build());
+        }
+        moduleNodeValues.withChild(featuresBuilder.build());
+
+        return moduleNodeValues.build();
+    }
 
     protected MapEntryNode toStreamEntryNode(final String streamName, final DataSchemaNode streamSchemaNode) {
         Preconditions.checkArgument(streamSchemaNode instanceof ListSchemaNode,