Bug 6679 - api explorer creates false examples 13/51713/1
authormiroslav.kovac <miroslav.kovac@pantheon.tech>
Mon, 10 Oct 2016 16:53:01 +0000 (18:53 +0200)
committerJakub Toth <jatoth@cisco.com>
Sat, 11 Feb 2017 01:33:04 +0000 (02:33 +0100)
Api explorer created false examples when yang has two data nodes with
same name in different containers or lists. It compared name of data
nodes rather than whole path to the data node which result to creting
examples of same types even if they should be different.

Fix examples by comparing the path to data node rather than just name
of the node.

Change-Id: I6f73fb37985fc78ad67ecc466ebfdfe569d7cd8d
Signed-off-by: miroslav.kovac <miroslav.kovac@pantheon.tech>
restconf/sal-rest-docgen/src/main/java/org/opendaylight/netconf/sal/rest/doc/impl/BaseYangSwaggerGenerator.java
restconf/sal-rest-docgen/src/main/java/org/opendaylight/netconf/sal/rest/doc/impl/ModelGenerator.java
restconf/sal-rest-docgen/src/main/java/org/opendaylight/netconf/sal/rest/doc/model/builder/OperationBuilder.java
restconf/sal-rest-docgen/src/test/java/org/opendaylight/controller/sal/rest/doc/impl/ApiDocGeneratorTest.java

index 7696ce6732baa6b4b2fc9756290fc5eeeeff75c0..abf560ea78fe9d44cffa322a12b62f456e295f09 100644 (file)
@@ -78,21 +78,21 @@ public class BaseYangSwaggerGenerator {
     /**
      * Return list of modules converted to swagger compliant resource list.
      */
-    public ResourceList getResourceListing(UriInfo uriInfo, SchemaContext schemaContext, String context) {
+    public ResourceList getResourceListing(final UriInfo uriInfo, final SchemaContext schemaContext, final String context) {
 
-        ResourceList resourceList = createResourceList();
+        final ResourceList resourceList = createResourceList();
 
-        Set<Module> modules = getSortedModules(schemaContext);
+        final Set<Module> modules = getSortedModules(schemaContext);
 
-        List<Resource> resources = new ArrayList<>(modules.size());
+        final List<Resource> resources = new ArrayList<>(modules.size());
 
         LOG.info("Modules found [{}]", modules.size());
 
-        for (Module module : modules) {
-            String revisionString = SIMPLE_DATE_FORMAT.format(module.getRevision());
-            Resource resource = new Resource();
+        for (final Module module : modules) {
+            final String revisionString = SIMPLE_DATE_FORMAT.format(module.getRevision());
+            final Resource resource = new Resource();
             LOG.debug("Working on [{},{}]...", module.getName(), revisionString);
-            ApiDeclaration doc = getApiDeclaration(module.getName(), revisionString, uriInfo, schemaContext, context);
+            final ApiDeclaration doc = getApiDeclaration(module.getName(), revisionString, uriInfo, schemaContext, context);
 
             if (doc != null) {
                 resource.setPath(generatePath(uriInfo, module.getName(), revisionString));
@@ -108,30 +108,30 @@ public class BaseYangSwaggerGenerator {
     }
 
     protected ResourceList createResourceList() {
-        ResourceList resourceList = new ResourceList();
+        final ResourceList resourceList = new ResourceList();
         resourceList.setApiVersion(API_VERSION);
         resourceList.setSwaggerVersion(SWAGGER_VERSION);
         return resourceList;
     }
 
-    protected String generatePath(UriInfo uriInfo, String name, String revision) {
-        URI uri = uriInfo.getRequestUriBuilder().path(generateCacheKey(name, revision)).build();
+    protected String generatePath(final UriInfo uriInfo, final String name, final String revision) {
+        final URI uri = uriInfo.getRequestUriBuilder().path(generateCacheKey(name, revision)).build();
         return uri.toASCIIString();
     }
 
-    public ApiDeclaration getApiDeclaration(String moduleName, String revision, UriInfo uriInfo, SchemaContext schemaContext, String context) {
+    public ApiDeclaration getApiDeclaration(final String moduleName, final String revision, final UriInfo uriInfo, final SchemaContext schemaContext, final String context) {
         Date rev = null;
 
         try {
             if (revision != null && !revision.equals("0000-00-00")) {
                 rev = SIMPLE_DATE_FORMAT.parse(revision);
             }
-        } catch (ParseException e) {
+        } catch (final ParseException e) {
             throw new IllegalArgumentException(e);
         }
 
         if (rev != null) {
-            Calendar cal = new GregorianCalendar();
+            final Calendar cal = new GregorianCalendar();
 
             cal.setTime(rev);
 
@@ -140,44 +140,44 @@ public class BaseYangSwaggerGenerator {
             }
         }
 
-        Module module = schemaContext.findModuleByName(moduleName, rev);
+        final Module module = schemaContext.findModuleByName(moduleName, rev);
         Preconditions.checkArgument(module != null,
                 "Could not find module by name,revision: " + moduleName + "," + revision);
 
         return getApiDeclaration(module, rev, uriInfo, context, schemaContext);
     }
 
-    public ApiDeclaration getApiDeclaration(Module module, Date revision, UriInfo uriInfo, String context, SchemaContext schemaContext) {
-        String basePath = createBasePathFromUriInfo(uriInfo);
+    public ApiDeclaration getApiDeclaration(final Module module, final Date revision, final UriInfo uriInfo, final String context, final SchemaContext schemaContext) {
+        final String basePath = createBasePathFromUriInfo(uriInfo);
 
-        ApiDeclaration doc = getSwaggerDocSpec(module, basePath, context, schemaContext);
+        final ApiDeclaration doc = getSwaggerDocSpec(module, basePath, context, schemaContext);
         if (doc != null) {
             return doc;
         }
         return null;
     }
 
-    protected String createBasePathFromUriInfo(UriInfo uriInfo) {
+    protected String createBasePathFromUriInfo(final UriInfo uriInfo) {
         String portPart = "";
-        int port = uriInfo.getBaseUri().getPort();
+        final int port = uriInfo.getBaseUri().getPort();
         if (port != -1) {
             portPart = ":" + port;
         }
-        String basePath = new StringBuilder(uriInfo.getBaseUri().getScheme()).append("://")
+        final String basePath = new StringBuilder(uriInfo.getBaseUri().getScheme()).append("://")
                 .append(uriInfo.getBaseUri().getHost()).append(portPart).append("/").append(RESTCONF_CONTEXT_ROOT)
                 .toString();
         return basePath;
     }
 
-    public ApiDeclaration getSwaggerDocSpec(Module m, String basePath, String context, SchemaContext schemaContext) {
-        ApiDeclaration doc = createApiDeclaration(basePath);
+    public ApiDeclaration getSwaggerDocSpec(final Module m, final String basePath, final String context, final SchemaContext schemaContext) {
+        final ApiDeclaration doc = createApiDeclaration(basePath);
 
-        List<Api> apis = new ArrayList<>();
+        final List<Api> apis = new ArrayList<>();
         boolean hasAddRootPostLink = false;
 
-        Collection<DataSchemaNode> dataSchemaNodes = m.getChildNodes();
+        final Collection<DataSchemaNode> dataSchemaNodes = m.getChildNodes();
         LOG.debug("child nodes size [{}]", dataSchemaNodes.size());
-        for (DataSchemaNode node : dataSchemaNodes) {
+        for (final DataSchemaNode node : dataSchemaNodes) {
             if ((node instanceof ListSchemaNode) || (node instanceof ContainerSchemaNode)) {
                 LOG.debug("Is Configuration node [{}] [{}]", node.isConfiguration(), node.getQName().getLocalName());
 
@@ -201,18 +201,18 @@ public class BaseYangSwaggerGenerator {
                         hasAddRootPostLink = true;
                     }
 
-                    addApis(node, apis, resourcePath, pathParams, schemaContext, true);
+                    addApis(node, apis, resourcePath, pathParams, schemaContext, true, m.getName());
                 }
 
                 pathParams = new ArrayList<>();
                 resourcePath = getDataStorePath("/operational/", context);
-                addApis(node, apis, resourcePath, pathParams, schemaContext, false);
+                addApis(node, apis, resourcePath, pathParams, schemaContext, false, m.getName());
             }
         }
 
-        Set<RpcDefinition> rpcs = m.getRpcs();
-        for (RpcDefinition rpcDefinition : rpcs) {
-            String resourcePath = getDataStorePath("/operations/", context);
+        final Set<RpcDefinition> rpcs = m.getRpcs();
+        for (final RpcDefinition rpcDefinition : rpcs) {
+            final String resourcePath = getDataStorePath("/operations/", context);
             addRpcs(rpcDefinition, apis, resourcePath, schemaContext);
         }
 
@@ -238,18 +238,18 @@ public class BaseYangSwaggerGenerator {
     }
 
     private void addRootPostLink(final Module module, final DataNodeContainer node, final List<Parameter> pathParams,
-            final String resourcePath, final List<Api> apis) {
+                                 final String resourcePath, final List<Api> apis) {
         if (containsListOrContainer(module.getChildNodes())) {
             final Api apiForRootPostUri = new Api();
             apiForRootPostUri.setPath(resourcePath);
             apiForRootPostUri.setOperations(operationPost(module.getName() + MODULE_NAME_SUFFIX,
-                    module.getDescription(), module, pathParams, true));
+                    module.getDescription(), module, pathParams, true, ""));
             apis.add(apiForRootPostUri);
         }
     }
 
-    protected ApiDeclaration createApiDeclaration(String basePath) {
-        ApiDeclaration doc = new ApiDeclaration();
+    protected ApiDeclaration createApiDeclaration(final String basePath) {
+        final ApiDeclaration doc = new ApiDeclaration();
         doc.setApiVersion(API_VERSION);
         doc.setSwaggerVersion(SWAGGER_VERSION);
         doc.setBasePath(basePath);
@@ -257,45 +257,45 @@ public class BaseYangSwaggerGenerator {
         return doc;
     }
 
-    protected String getDataStorePath(String dataStore, String context) {
+    protected String getDataStorePath(final String dataStore, final String context) {
         return dataStore + context;
     }
 
-    private String generateCacheKey(String module, String revision) {
+    private String generateCacheKey(final String module, final String revision) {
         return module + "(" + revision + ")";
     }
 
-    private void addApis(DataSchemaNode node, List<Api> apis, String parentPath, List<Parameter> parentPathParams, SchemaContext schemaContext,
-            boolean addConfigApi) {
+    private void addApis(final DataSchemaNode node, final List<Api> apis, final String parentPath, final List<Parameter> parentPathParams, final SchemaContext schemaContext,
+                         final boolean addConfigApi, final String parentName) {
 
-        Api api = new Api();
-        List<Parameter> pathParams = new ArrayList<>(parentPathParams);
+        final Api api = new Api();
+        final List<Parameter> pathParams = new ArrayList<>(parentPathParams);
 
-        String resourcePath = parentPath + createPath(node, pathParams, schemaContext) + "/";
+        final String resourcePath = parentPath + createPath(node, pathParams, schemaContext) + "/";
         LOG.debug("Adding path: [{}]", resourcePath);
         api.setPath(resourcePath);
 
         Iterable<DataSchemaNode> childSchemaNodes = Collections.<DataSchemaNode>emptySet();
         if ((node instanceof ListSchemaNode) || (node instanceof ContainerSchemaNode)) {
-            DataNodeContainer dataNodeContainer = (DataNodeContainer) node;
+            final DataNodeContainer dataNodeContainer = (DataNodeContainer) node;
             childSchemaNodes = dataNodeContainer.getChildNodes();
         }
-        api.setOperations(operation(node, pathParams, addConfigApi, childSchemaNodes));
+        api.setOperations(operation(node, pathParams, addConfigApi, childSchemaNodes, parentName));
         apis.add(api);
 
-        for (DataSchemaNode childNode : childSchemaNodes) {
+        for (final DataSchemaNode childNode : childSchemaNodes) {
             if (childNode instanceof ListSchemaNode || childNode instanceof ContainerSchemaNode) {
                 // keep config and operation attributes separate.
                 if (childNode.isConfiguration() == addConfigApi) {
-                    addApis(childNode, apis, resourcePath, pathParams, schemaContext, addConfigApi);
+                    final String newParent = parentName + "/" + node.getQName().getLocalName();
+                    addApis(childNode, apis, resourcePath, pathParams, schemaContext, addConfigApi, newParent);
                 }
             }
         }
-
     }
 
     private boolean containsListOrContainer(final Iterable<DataSchemaNode> nodes) {
-        for (DataSchemaNode child : nodes) {
+        for (final DataSchemaNode child : nodes) {
             if (child instanceof ListSchemaNode || child instanceof ContainerSchemaNode) {
                 return true;
             }
@@ -303,54 +303,55 @@ public class BaseYangSwaggerGenerator {
         return false;
     }
 
-    private List<Operation> operation(DataSchemaNode node, List<Parameter> pathParams, boolean isConfig, Iterable<DataSchemaNode> childSchemaNodes) {
-        List<Operation> operations = new ArrayList<>();
+    private List<Operation> operation(final DataSchemaNode node, final List<Parameter> pathParams, final boolean isConfig,
+                                      final Iterable<DataSchemaNode> childSchemaNodes, final String parentName) {
+        final List<Operation> operations = new ArrayList<>();
 
-        Get getBuilder = new Get(node, isConfig);
+        final Get getBuilder = new Get(node, isConfig);
         operations.add(getBuilder.pathParams(pathParams).build());
 
         if (isConfig) {
-            Put putBuilder = new Put(node.getQName().getLocalName(),
-                    node.getDescription());
+            final Put putBuilder = new Put(node.getQName().getLocalName(), node.getDescription(), parentName);
             operations.add(putBuilder.pathParams(pathParams).build());
 
-            Delete deleteBuilder = new Delete(node);
+            final Delete deleteBuilder = new Delete(node);
             operations.add(deleteBuilder.pathParams(pathParams).build());
 
             if (containsListOrContainer(childSchemaNodes)) {
                 operations.addAll(operationPost(node.getQName().getLocalName(), node.getDescription(),
-                        (DataNodeContainer) node, pathParams, isConfig));
+                        (DataNodeContainer) node, pathParams, isConfig, parentName + "/"));
             }
         }
         return operations;
     }
 
-    private List<Operation> operationPost(final String name, final String description, final DataNodeContainer dataNodeContainer, List<Parameter> pathParams, boolean isConfig) {
-        List<Operation> operations = new ArrayList<>();
+    private List<Operation> operationPost(final String name, final String description, final DataNodeContainer dataNodeContainer,
+                                          final List<Parameter> pathParams, final boolean isConfig, final String parentName) {
+        final List<Operation> operations = new ArrayList<>();
         if (isConfig) {
-            Post postBuilder = new Post(name, description, dataNodeContainer);
+            final Post postBuilder = new Post(name, parentName + name, description, dataNodeContainer);
             operations.add(postBuilder.pathParams(pathParams).build());
         }
         return operations;
     }
 
-    private String createPath(final DataSchemaNode schemaNode, List<Parameter> pathParams, SchemaContext schemaContext) {
-        ArrayList<LeafSchemaNode> pathListParams = new ArrayList<>();
-        StringBuilder path = new StringBuilder();
-        String localName = resolvePathArgumentsName(schemaNode, schemaContext);
+    private String createPath(final DataSchemaNode schemaNode, final List<Parameter> pathParams, final SchemaContext schemaContext) {
+        final ArrayList<LeafSchemaNode> pathListParams = new ArrayList<>();
+        final StringBuilder path = new StringBuilder();
+        final String localName = resolvePathArgumentsName(schemaNode, schemaContext);
         path.append(localName);
 
         if ((schemaNode instanceof ListSchemaNode)) {
             final List<QName> listKeys = ((ListSchemaNode) schemaNode).getKeyDefinition();
             for (final QName listKey : listKeys) {
-                DataSchemaNode dataChildByName = ((DataNodeContainer) schemaNode).getDataChildByName(listKey);
+                final DataSchemaNode dataChildByName = ((DataNodeContainer) schemaNode).getDataChildByName(listKey);
                 pathListParams.add(((LeafSchemaNode) dataChildByName));
 
-                String pathParamIdentifier = new StringBuilder("/{").append(listKey.getLocalName()).append("}")
+                final String pathParamIdentifier = new StringBuilder("/{").append(listKey.getLocalName()).append("}")
                         .toString();
                 path.append(pathParamIdentifier);
 
-                Parameter pathParam = new Parameter();
+                final Parameter pathParam = new Parameter();
                 pathParam.setName(listKey.getLocalName());
                 pathParam.setDescription(dataChildByName.getDescription());
                 pathParam.setType("string");
@@ -362,22 +363,22 @@ public class BaseYangSwaggerGenerator {
         return path.toString();
     }
 
-    protected void addRpcs(RpcDefinition rpcDefn, List<Api> apis, String parentPath, SchemaContext schemaContext) {
-        Api rpc = new Api();
-        String resourcePath = parentPath + resolvePathArgumentsName(rpcDefn, schemaContext);
+    protected void addRpcs(final RpcDefinition rpcDefn, final List<Api> apis, final String parentPath, final SchemaContext schemaContext) {
+        final Api rpc = new Api();
+        final String resourcePath = parentPath + resolvePathArgumentsName(rpcDefn, schemaContext);
         rpc.setPath(resourcePath);
 
-        Operation operationSpec = new Operation();
+        final Operation operationSpec = new Operation();
         operationSpec.setMethod("POST");
         operationSpec.setNotes(rpcDefn.getDescription());
         operationSpec.setNickname(rpcDefn.getQName().getLocalName());
         if (rpcDefn.getOutput() != null) {
-            operationSpec.setType("(" + rpcDefn.getQName().getLocalName() + ")output");
+            operationSpec.setType("(" + rpcDefn.getQName().getLocalName() + ")output" + OperationBuilder.TOP);
         }
         if (rpcDefn.getInput() != null) {
-            Parameter payload = new Parameter();
+            final Parameter payload = new Parameter();
             payload.setParamType("body");
-            payload.setType("(" + rpcDefn.getQName().getLocalName() + ")input");
+            payload.setType("(" + rpcDefn.getQName().getLocalName() + ")input" + OperationBuilder.TOP);
             operationSpec.setParameters(Collections.singletonList(payload));
             operationSpec.setConsumes(OperationBuilder.CONSUMES_PUT_POST);
         }
@@ -387,18 +388,18 @@ public class BaseYangSwaggerGenerator {
         apis.add(rpc);
     }
 
-    protected SortedSet<Module> getSortedModules(SchemaContext schemaContext) {
+    protected SortedSet<Module> getSortedModules(final SchemaContext schemaContext) {
         if (schemaContext == null) {
             return new TreeSet<>();
         }
 
-        Set<Module> modules = schemaContext.getModules();
+        final Set<Module> modules = schemaContext.getModules();
 
-        SortedSet<Module> sortedModules = new TreeSet<>((module1, module2) -> {
+        final SortedSet<Module> sortedModules = new TreeSet<>((module1, module2) -> {
             int result = module1.getName().compareTo(module2.getName());
             if (result == 0) {
-                Date module1Revision = module1.getRevision() != null ? module1.getRevision() : new Date(0);
-                Date module2Revision = module2.getRevision() != null ? module2.getRevision() : new Date(0);
+                final Date module1Revision = module1.getRevision() != null ? module1.getRevision() : new Date(0);
+                final Date module2Revision = module2.getRevision() != null ? module2.getRevision() : new Date(0);
                 result = module1Revision.compareTo(module2Revision);
             }
             if (result == 0) {
@@ -406,7 +407,7 @@ public class BaseYangSwaggerGenerator {
             }
             return result;
         });
-        for (Module m : modules) {
+        for (final Module m : modules) {
             if (m != null) {
                 sortedModules.add(m);
             }
index fdbd7b4997120c5572fca34b79f6a4befd201ce4..24768e836864ff76261c9dff5a102153304cdd86 100644 (file)
@@ -20,7 +20,6 @@ import org.json.JSONException;
 import org.json.JSONObject;
 import org.opendaylight.netconf.sal.rest.doc.model.builder.OperationBuilder;
 import org.opendaylight.netconf.sal.rest.doc.model.builder.OperationBuilder.Post;
-import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.model.api.AnyXmlSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.ChoiceCaseNode;
 import org.opendaylight.yangtools.yang.model.api.ChoiceSchemaNode;
@@ -113,7 +112,7 @@ public class ModelGenerator {
     }
 
     public JSONObject convertToJsonSchema(final Module module, final SchemaContext schemaContext) throws IOException, JSONException {
-        JSONObject models = new JSONObject();
+        final JSONObject models = new JSONObject();
         topLevelModule = module;
         processModules(module, models);
         processContainersAndLists(module, models, schemaContext);
@@ -123,22 +122,22 @@ public class ModelGenerator {
     }
 
     private void processModules(final Module module, final JSONObject models) throws JSONException {
-        createConcreteModelForPost(models, module.getName() + BaseYangSwaggerGenerator.MODULE_NAME_SUFFIX, createPropertiesForPost(module));
+        createConcreteModelForPost(models, module.getName() + BaseYangSwaggerGenerator.MODULE_NAME_SUFFIX,
+                createPropertiesForPost(module, module.getName()));
     }
 
     private void processContainersAndLists(final Module module, final JSONObject models, final SchemaContext schemaContext)
             throws IOException, JSONException {
 
-        String moduleName = module.getName();
+        final String moduleName = module.getName();
 
-        for (DataSchemaNode childNode : module.getChildNodes()) {
+        for (final DataSchemaNode childNode : module.getChildNodes()) {
             // For every container and list in the module
             if (childNode instanceof ContainerSchemaNode || childNode instanceof ListSchemaNode) {
                 processDataNodeContainer((DataNodeContainer) childNode, moduleName, models, true, schemaContext);
                 processDataNodeContainer((DataNodeContainer) childNode, moduleName, models, false, schemaContext);
             }
         }
-
     }
 
     /**
@@ -151,30 +150,58 @@ public class ModelGenerator {
      */
     private void processRPCs(final Module module, final JSONObject models, final SchemaContext schemaContext) throws JSONException,
             IOException {
+        final Set<RpcDefinition> rpcs = module.getRpcs();
+        final String moduleName = module.getName();
+        for (final RpcDefinition rpc : rpcs) {
+            final ContainerSchemaNode input = rpc.getInput();
+            if (input != null) {
+                final JSONObject properties = processChildren(input.getChildNodes(), moduleName, models, true, schemaContext);
 
-        Set<RpcDefinition> rpcs = module.getRpcs();
-        String moduleName = module.getName();
-        for (RpcDefinition rpc : rpcs) {
+                final String filename = "(" + rpc.getQName().getLocalName() + ")input";
+                final JSONObject childSchema = getSchemaTemplate();
+                childSchema.put(TYPE_KEY, OBJECT_TYPE);
+                childSchema.put(PROPERTIES_KEY, properties);
+                childSchema.put("id", filename);
+                models.put(filename, childSchema);
 
-            ContainerSchemaNode input = rpc.getInput();
-            if (input != null) {
-                JSONObject inputJSON = processDataNodeContainer(input, moduleName, models, schemaContext);
-                String filename = "(" + rpc.getQName().getLocalName() + ")input";
-                inputJSON.put("id", filename);
-                // writeToFile(filename, inputJSON.toString(2), moduleName);
-                models.put(filename, inputJSON);
+                processTopData(filename, models, input);
             }
 
-            ContainerSchemaNode output = rpc.getOutput();
+            final ContainerSchemaNode output = rpc.getOutput();
             if (output != null) {
-                JSONObject outputJSON = processDataNodeContainer(output, moduleName, models, schemaContext);
-                String filename = "(" + rpc.getQName().getLocalName() + ")output";
-                outputJSON.put("id", filename);
-                models.put(filename, outputJSON);
+                final JSONObject properties = processChildren(output.getChildNodes(), moduleName, models, true, schemaContext);
+                final String filename = "(" + rpc.getQName().getLocalName() + ")output";
+                final JSONObject childSchema = getSchemaTemplate();
+                childSchema.put(TYPE_KEY, OBJECT_TYPE);
+                childSchema.put(PROPERTIES_KEY, properties);
+                childSchema.put("id", filename);
+                models.put(filename, childSchema);
+
+                processTopData(filename, models, output);
             }
         }
     }
 
+    private static JSONObject processTopData(final String filename, final JSONObject models, final SchemaNode schemaNode) {
+        final JSONObject items = new JSONObject();
+
+        items.put(REF_KEY, filename);
+        final JSONObject dataNodeProperties = new JSONObject();
+        dataNodeProperties.put(TYPE_KEY, schemaNode instanceof ListSchemaNode ? ARRAY_TYPE : OBJECT_TYPE);
+        dataNodeProperties.put(ITEMS_KEY, items);
+
+        dataNodeProperties.putOpt(DESCRIPTION_KEY, schemaNode.getDescription());
+        final JSONObject properties = new JSONObject();
+        properties.put(schemaNode.getQName().getLocalName(), dataNodeProperties);
+        final JSONObject finalChildSchema = getSchemaTemplate();
+        finalChildSchema.put(TYPE_KEY, OBJECT_TYPE);
+        finalChildSchema.put(PROPERTIES_KEY, properties);
+        finalChildSchema.put(ID_KEY, filename + OperationBuilder.TOP);
+        models.put(filename + OperationBuilder.TOP, finalChildSchema);
+
+        return dataNodeProperties;
+    }
+
     /**
      * Processes the 'identity' statement in a yang model and maps it to a 'model' in the Swagger JSON spec.
      *
@@ -185,31 +212,31 @@ public class ModelGenerator {
      */
     private static void processIdentities(final Module module, final JSONObject models) throws JSONException {
 
-        String moduleName = module.getName();
-        Set<IdentitySchemaNode> idNodes = module.getIdentities();
+        final String moduleName = module.getName();
+        final Set<IdentitySchemaNode> idNodes = module.getIdentities();
         LOG.debug("Processing Identities for module {} . Found {} identity statements", moduleName, idNodes.size());
 
-        for (IdentitySchemaNode idNode : idNodes) {
-            JSONObject identityObj = new JSONObject();
-            String identityName = idNode.getQName().getLocalName();
+        for (final IdentitySchemaNode idNode : idNodes) {
+            final JSONObject identityObj = new JSONObject();
+            final String identityName = idNode.getQName().getLocalName();
             LOG.debug("Processing Identity: {}", identityName);
 
             identityObj.put(ID_KEY, identityName);
             identityObj.put(DESCRIPTION_KEY, idNode.getDescription());
 
-            JSONObject props = new JSONObject();
-            IdentitySchemaNode baseId = idNode.getBaseIdentity();
+            final JSONObject props = new JSONObject();
+            final IdentitySchemaNode baseId = idNode.getBaseIdentity();
 
             if (baseId == null) {
                 /**
                  * This is a base identity. So lets see if it has sub types. If it does, then add them to the model
                  * definition.
                  */
-                Set<IdentitySchemaNode> derivedIds = idNode.getDerivedIdentities();
+                final Set<IdentitySchemaNode> derivedIds = idNode.getDerivedIdentities();
 
                 if (derivedIds != null) {
-                    JSONArray subTypes = new JSONArray();
-                    for (IdentitySchemaNode derivedId : derivedIds) {
+                    final JSONArray subTypes = new JSONArray();
+                    for (final IdentitySchemaNode derivedId : derivedIds) {
                         subTypes.put(derivedId.getQName().getLocalName());
                     }
                     identityObj.put(SUB_TYPES_KEY, subTypes);
@@ -227,117 +254,101 @@ public class ModelGenerator {
         }
     }
 
-    /**
-     * Processes the container and list nodes and populates the moduleJSON.
-     */
-    private JSONObject processDataNodeContainer(final DataNodeContainer dataNode, final String moduleName, final JSONObject models,
-            final SchemaContext schemaContext) throws JSONException, IOException {
-        return processDataNodeContainer(dataNode, moduleName, models, true, schemaContext);
-    }
-
-    private JSONObject processDataNodeContainer(final DataNodeContainer dataNode, final String moduleName, final JSONObject models,
-            final boolean isConfig, final SchemaContext schemaContext) throws JSONException, IOException {
+    private JSONObject processDataNodeContainer(final DataNodeContainer dataNode, final String parentName, final JSONObject models,
+                                                final boolean isConfig, final SchemaContext schemaContext) throws JSONException, IOException {
         if (dataNode instanceof ListSchemaNode || dataNode instanceof ContainerSchemaNode) {
             Preconditions.checkArgument(dataNode instanceof SchemaNode, "Data node should be also schema node");
-            Iterable<DataSchemaNode> containerChildren = dataNode.getChildNodes();
-            JSONObject properties = processChildren(containerChildren, ((SchemaNode) dataNode).getQName(), moduleName,
-                    models, isConfig, schemaContext);
-
-            String nodeName = (isConfig ? OperationBuilder.CONFIG : OperationBuilder.OPERATIONAL)
-                    + ((SchemaNode) dataNode).getQName().getLocalName();
+            final Iterable<DataSchemaNode> containerChildren = dataNode.getChildNodes();
+            final String localName = ((SchemaNode) dataNode).getQName().getLocalName();
+            final JSONObject properties = processChildren(containerChildren, parentName + "/" + localName, models, isConfig, schemaContext);
+            final String nodeName = parentName + (isConfig ? OperationBuilder.CONFIG : OperationBuilder.OPERATIONAL)
+                    + localName;
 
-            JSONObject childSchema = getSchemaTemplate();
+            final JSONObject childSchema = getSchemaTemplate();
             childSchema.put(TYPE_KEY, OBJECT_TYPE);
             childSchema.put(PROPERTIES_KEY, properties);
+
             childSchema.put("id", nodeName);
             models.put(nodeName, childSchema);
 
             if (isConfig) {
-                createConcreteModelForPost(models, ((SchemaNode) dataNode).getQName().getLocalName(),
-                        createPropertiesForPost(dataNode));
+                createConcreteModelForPost(models, localName,
+                        createPropertiesForPost(dataNode, parentName + "/" + localName));
             }
 
-            JSONObject items = new JSONObject();
-            items.put(REF_KEY, nodeName);
-            JSONObject dataNodeProperties = new JSONObject();
-            dataNodeProperties.put(TYPE_KEY, dataNode instanceof ListSchemaNode ? ARRAY_TYPE : OBJECT_TYPE);
-            dataNodeProperties.put(ITEMS_KEY, items);
-
-            return dataNodeProperties;
+            return processTopData(nodeName, models, (SchemaNode) dataNode);
         }
         return null;
     }
 
     private static void createConcreteModelForPost(final JSONObject models, final String localName,
             final JSONObject properties) throws JSONException {
-        String nodePostName = OperationBuilder.CONFIG + localName + Post.METHOD_NAME;
-        JSONObject postSchema = getSchemaTemplate();
+        final String nodePostName = OperationBuilder.CONFIG + localName + Post.METHOD_NAME;
+        final JSONObject postSchema = getSchemaTemplate();
         postSchema.put(TYPE_KEY, OBJECT_TYPE);
         postSchema.put("id", nodePostName);
         postSchema.put(PROPERTIES_KEY, properties);
         models.put(nodePostName, postSchema);
     }
 
-    private JSONObject createPropertiesForPost(final DataNodeContainer dataNodeContainer) throws JSONException {
-        JSONObject properties = new JSONObject();
-        for (DataSchemaNode childNode : dataNodeContainer.getChildNodes()) {
+    private JSONObject createPropertiesForPost(final DataNodeContainer dataNodeContainer, final String parentName)
+            throws JSONException {
+        final JSONObject properties = new JSONObject();
+        for (final DataSchemaNode childNode : dataNodeContainer.getChildNodes()) {
             if (childNode instanceof ListSchemaNode || childNode instanceof ContainerSchemaNode) {
-                JSONObject items = new JSONObject();
-                items.put(REF_KEY, "(config)" + childNode.getQName().getLocalName());
-                JSONObject property = new JSONObject();
+                final JSONObject items = new JSONObject();
+                items.put(REF_KEY, parentName + "(config)" + childNode.getQName().getLocalName());
+                final JSONObject property = new JSONObject();
                 property.put(TYPE_KEY, childNode instanceof ListSchemaNode ? ARRAY_TYPE : OBJECT_TYPE);
                 property.put(ITEMS_KEY, items);
                 properties.put(childNode.getQName().getLocalName(), property);
             } else if (childNode instanceof LeafSchemaNode) {
-                JSONObject property = processLeafNode((LeafSchemaNode)childNode);
+                final JSONObject property = processLeafNode((LeafSchemaNode) childNode);
                 properties.put(childNode.getQName().getLocalName(), property);
             }
         }
         return properties;
     }
 
-    private JSONObject processChildren(final Iterable<DataSchemaNode> nodes, final QName parentQName, final String moduleName,
-            final JSONObject models, final SchemaContext schemaContext) throws JSONException, IOException {
-        return processChildren(nodes, parentQName, moduleName, models, true, schemaContext);
+    private JSONObject processChildren(final Iterable<DataSchemaNode> nodes, final String moduleName,
+                                       final JSONObject models, final SchemaContext schemaContext) throws JSONException, IOException {
+        return processChildren(nodes, moduleName, models, true, schemaContext);
     }
 
     /**
      * Processes the nodes.
      */
-    private JSONObject processChildren(final Iterable<DataSchemaNode> nodes, final QName parentQName,
-            final String moduleName, final JSONObject models, final boolean isConfig, final SchemaContext schemaContext)
+    private JSONObject processChildren(final Iterable<DataSchemaNode> nodes, final String parentName, final JSONObject models,
+                                       final boolean isConfig, final SchemaContext schemaContext)
             throws JSONException, IOException {
-
-        JSONObject properties = new JSONObject();
-
-        for (DataSchemaNode node : nodes) {
+        final JSONObject properties = new JSONObject();
+        for (final DataSchemaNode node : nodes) {
             if (node.isConfiguration() == isConfig) {
-
-                String name = resolveNodesName(node, topLevelModule, schemaContext);
-                JSONObject property = null;
+                final String name = resolveNodesName(node, topLevelModule, schemaContext);
+                final JSONObject property;
                 if (node instanceof LeafSchemaNode) {
                     property = processLeafNode((LeafSchemaNode) node);
+
                 } else if (node instanceof ListSchemaNode) {
-                    property = processDataNodeContainer((ListSchemaNode) node, moduleName, models, isConfig,
+                    property = processDataNodeContainer((ListSchemaNode) node, parentName, models, isConfig,
                             schemaContext);
 
                 } else if (node instanceof LeafListSchemaNode) {
                     property = processLeafListNode((LeafListSchemaNode) node);
 
                 } else if (node instanceof ChoiceSchemaNode) {
-                    property = processChoiceNode((ChoiceSchemaNode) node, moduleName, models, schemaContext);
+                    property = processChoiceNode((ChoiceSchemaNode) node, parentName, models, schemaContext);
 
                 } else if (node instanceof AnyXmlSchemaNode) {
                     property = processAnyXMLNode((AnyXmlSchemaNode) node);
 
                 } else if (node instanceof ContainerSchemaNode) {
-                    property = processDataNodeContainer((ContainerSchemaNode) node, moduleName, models, isConfig,
+                    property = processDataNodeContainer((ContainerSchemaNode) node, parentName, models, isConfig,
                             schemaContext);
 
                 } else {
                     throw new IllegalArgumentException("Unknown DataSchemaNode type: " + node.getClass());
                 }
-
                 property.putOpt(DESCRIPTION_KEY, node.getDescription());
                 properties.put(name, property);
             }
@@ -346,36 +357,35 @@ public class ModelGenerator {
     }
 
     private JSONObject processLeafListNode(final LeafListSchemaNode listNode) throws JSONException {
-        JSONObject props = new JSONObject();
+        final JSONObject props = new JSONObject();
         props.put(TYPE_KEY, ARRAY_TYPE);
 
-        JSONObject itemsVal = new JSONObject();
+        final JSONObject itemsVal = new JSONObject();
         processTypeDef(listNode.getType(), itemsVal);
         props.put(ITEMS_KEY, itemsVal);
 
-        ConstraintDefinition constraints = listNode.getConstraints();
+        final ConstraintDefinition constraints = listNode.getConstraints();
         processConstraints(constraints, props);
 
         return props;
     }
 
-    private JSONObject processChoiceNode(final ChoiceSchemaNode choiceNode, final String moduleName, final JSONObject models,
-            final SchemaContext schemaContext) throws JSONException, IOException {
+    private JSONObject processChoiceNode(final ChoiceSchemaNode choiceNode, final String parentName, final JSONObject models,
+                                         final SchemaContext schemaContext) throws JSONException, IOException {
 
-        Set<ChoiceCaseNode> cases = choiceNode.getCases();
+        final Set<ChoiceCaseNode> cases = choiceNode.getCases();
 
-        JSONArray choiceProps = new JSONArray();
-        for (ChoiceCaseNode choiceCase : cases) {
-            String choiceName = choiceCase.getQName().getLocalName();
-            JSONObject choiceProp = processChildren(choiceCase.getChildNodes(), choiceCase.getQName(), moduleName,
-                    models, schemaContext);
-            JSONObject choiceObj = new JSONObject();
+        final JSONArray choiceProps = new JSONArray();
+        for (final ChoiceCaseNode choiceCase : cases) {
+            final String choiceName = choiceCase.getQName().getLocalName();
+            final JSONObject choiceProp = processChildren(choiceCase.getChildNodes(), parentName, models, schemaContext);
+            final JSONObject choiceObj = new JSONObject();
             choiceObj.put(choiceName, choiceProp);
             choiceObj.put(TYPE_KEY, OBJECT_TYPE);
             choiceProps.put(choiceObj);
         }
 
-        JSONObject oneOfProps = new JSONObject();
+        final JSONObject oneOfProps = new JSONObject();
         oneOfProps.put(ONE_OF_KEY, choiceProps);
         oneOfProps.put(TYPE_KEY, OBJECT_TYPE);
 
@@ -383,11 +393,11 @@ public class ModelGenerator {
     }
 
     private static void processConstraints(final ConstraintDefinition constraints, final JSONObject props) throws JSONException {
-        boolean isMandatory = constraints.isMandatory();
+        final boolean isMandatory = constraints.isMandatory();
         props.put(REQUIRED_KEY, isMandatory);
 
-        Integer minElements = constraints.getMinElements();
-        Integer maxElements = constraints.getMaxElements();
+        final Integer minElements = constraints.getMinElements();
+        final Integer maxElements = constraints.getMaxElements();
         if (minElements != null) {
             props.put(MIN_ITEMS, minElements);
         }
@@ -397,9 +407,9 @@ public class ModelGenerator {
     }
 
     private JSONObject processLeafNode(final LeafSchemaNode leafNode) throws JSONException {
-        JSONObject property = new JSONObject();
+        final JSONObject property = new JSONObject();
 
-        String leafDescription = leafNode.getDescription();
+        final String leafDescription = leafNode.getDescription();
         property.put(DESCRIPTION_KEY, leafDescription);
 
         processConstraints(leafNode.getConstraints(), property);
@@ -409,9 +419,9 @@ public class ModelGenerator {
     }
 
     private static JSONObject processAnyXMLNode(final AnyXmlSchemaNode leafNode) throws JSONException {
-        JSONObject property = new JSONObject();
+        final JSONObject property = new JSONObject();
 
-        String leafDescription = leafNode.getDescription();
+        final String leafDescription = leafNode.getDescription();
         property.put(DESCRIPTION_KEY, leafDescription);
 
         processConstraints(leafNode.getConstraints(), property);
@@ -444,15 +454,15 @@ public class ModelGenerator {
 
     private static void processBinaryType(final BinaryTypeDefinition binaryType, final JSONObject property) throws JSONException {
         property.put(TYPE_KEY, STRING);
-        JSONObject media = new JSONObject();
+        final JSONObject media = new JSONObject();
         media.put(BINARY_ENCODING_KEY, BASE_64);
         property.put(MEDIA_KEY, media);
     }
 
     private static void processEnumType(final EnumTypeDefinition enumLeafType, final JSONObject property) throws JSONException {
-        List<EnumPair> enumPairs = enumLeafType.getValues();
-        List<String> enumNames = new ArrayList<>();
-        for (EnumPair enumPair : enumPairs) {
+        final List<EnumPair> enumPairs = enumLeafType.getValues();
+        final List<String> enumNames = new ArrayList<>();
+        for (final EnumPair enumPair : enumPairs) {
             enumNames.add(enumPair.getName());
         }
         property.putOpt(ENUM, new JSONArray(enumNames));
@@ -462,13 +472,13 @@ public class ModelGenerator {
         property.put(TYPE_KEY, ARRAY_TYPE);
         property.put(MIN_ITEMS, 0);
         property.put(UNIQUE_ITEMS_KEY, true);
-        JSONArray enumValues = new JSONArray();
+        final JSONArray enumValues = new JSONArray();
 
-        List<Bit> bits = bitsType.getBits();
-        for (Bit bit : bits) {
+        final List<Bit> bits = bitsType.getBits();
+        for (final Bit bit : bits) {
             enumValues.put(bit.getName());
         }
-        JSONObject itemsValue = new JSONObject();
+        final JSONObject itemsValue = new JSONObject();
         itemsValue.put(ENUM, enumValues);
         property.put(ITEMS_KEY, itemsValue);
     }
@@ -483,9 +493,9 @@ public class ModelGenerator {
 
         // FIXME: json-schema is not expressive enough to capture min/max laternatives. We should find the true minimum
         //        and true maximum implied by the constraints and use that.
-        for (LengthConstraint lengthConstraint : lengthConstraints) {
-            Number min = lengthConstraint.getMin();
-            Number max = lengthConstraint.getMax();
+        for (final LengthConstraint lengthConstraint : lengthConstraints) {
+            final Number min = lengthConstraint.getMin();
+            final Number max = lengthConstraint.getMax();
             property.putOpt(MIN_LENGTH_KEY, min);
             property.putOpt(MAX_LENGTH_KEY, max);
         }
@@ -494,8 +504,8 @@ public class ModelGenerator {
     }
 
     private static void processUnionType(final UnionTypeDefinition unionType, final JSONObject property) throws JSONException {
-        StringBuilder type = new StringBuilder();
-        for (TypeDefinition<?> typeDef : unionType.getTypes()) {
+        final StringBuilder type = new StringBuilder();
+        for (final TypeDefinition<?> typeDef : unionType.getTypes()) {
             if (type.length() > 0) {
                 type.append(" or ");
             }
@@ -509,7 +519,7 @@ public class ModelGenerator {
      * Helper method to generate a pre-filled JSON schema object.
      */
     private static JSONObject getSchemaTemplate() throws JSONException {
-        JSONObject schemaJSON = new JSONObject();
+        final JSONObject schemaJSON = new JSONObject();
         schemaJSON.put(SCHEMA_KEY, SCHEMA_URL);
 
         return schemaJSON;
index 98f8af76d838163bf05d2eb938298dc2b6812955..d24636bfee060451de3cf7cda594036fbfc027e1 100644 (file)
@@ -20,6 +20,7 @@ public final class OperationBuilder {
 
     public static final String OPERATIONAL = "(operational)";
     public static final String CONFIG = "(config)";
+    public static final String TOP = "-TOP";
 
     public static final List<String> CONSUMES_PUT_POST = new ArrayList<>();
 
@@ -34,7 +35,7 @@ public final class OperationBuilder {
         protected DataSchemaNode schemaNode;
         private static final String METHOD_NAME = "GET";
 
-        public Get(DataSchemaNode node, boolean isConfig) {
+        public Get(final DataSchemaNode node, final boolean isConfig) {
             this.schemaNode = node;
             spec = new Operation();
             spec.setMethod(METHOD_NAME);
@@ -43,8 +44,8 @@ public final class OperationBuilder {
             spec.setNotes(node.getDescription());
         }
 
-        public Get pathParams(List<Parameter> params) {
-            List<Parameter> pathParameters = new ArrayList<>(params);
+        public Get pathParams(final List<Parameter> params) {
+            final List<Parameter> pathParameters = new ArrayList<>(params);
             spec.setParameters(pathParameters);
             return this;
         }
@@ -57,21 +58,24 @@ public final class OperationBuilder {
     public static class Put {
         protected Operation spec;
         protected String nodeName;
+        protected String parentName;
         private static final String METHOD_NAME = "PUT";
 
-        public Put(String nodeName, final String description) {
+        public Put(final String nodeName, final String description, final String parentName) {
             this.nodeName = nodeName;
+            this.parentName = parentName;
             spec = new Operation();
-            spec.setType(CONFIG + nodeName);
+            spec.setType(parentName + CONFIG + nodeName + TOP);
             spec.setNotes(description);
             spec.setConsumes(CONSUMES_PUT_POST);
         }
 
-        public Put pathParams(List<Parameter> params) {
-            List<Parameter> parameters = new ArrayList<>(params);
-            Parameter payload = new Parameter();
+        public Put pathParams(final List<Parameter> params) {
+            final List<Parameter> parameters = new ArrayList<>(params);
+            final Parameter payload = new Parameter();
             payload.setParamType("body");
-            payload.setType(CONFIG + nodeName);
+            payload.setType(parentName + CONFIG + nodeName + TOP);
+            payload.setName(CONFIG + nodeName);
             parameters.add(payload);
             spec.setParameters(parameters);
             return this;
@@ -89,8 +93,8 @@ public final class OperationBuilder {
         public static final String METHOD_NAME = "POST";
         private final DataNodeContainer dataNodeContainer;
 
-        public Post(final String nodeName, final String description, final DataNodeContainer dataNodeContainer) {
-            super(nodeName, description);
+        public Post(final String nodeName, final String parentName, final String description, final DataNodeContainer dataNodeContainer) {
+            super(nodeName, description, parentName.replace("_module", ""));
             this.dataNodeContainer = dataNodeContainer;
             spec.setType(CONFIG + nodeName + METHOD_NAME);
             spec.setConsumes(CONSUMES_PUT_POST);
@@ -104,20 +108,19 @@ public final class OperationBuilder {
         }
 
         @Override
-        public Put pathParams(List<Parameter> params) {
-            List<Parameter> parameters = new ArrayList<>(params);
-            for (DataSchemaNode node : dataNodeContainer.getChildNodes()) {
+        public Put pathParams(final List<Parameter> params) {
+            final List<Parameter> parameters = new ArrayList<>(params);
+            for (final DataSchemaNode node : dataNodeContainer.getChildNodes()) {
                 if (node instanceof ListSchemaNode || node instanceof ContainerSchemaNode) {
-                    Parameter payload = new Parameter();
+                    final Parameter payload = new Parameter();
                     payload.setParamType("body");
-                    payload.setType(CONFIG + node.getQName().getLocalName());
+                    payload.setType(parentName + CONFIG + node.getQName().getLocalName() + TOP);
                     payload.setName("**" + CONFIG + node.getQName().getLocalName());
                     parameters.add(payload);
                 }
             }
             spec.setParameters(parameters);
             return this;
-
         }
 
         public Post summary(final String summary) {
@@ -129,7 +132,7 @@ public final class OperationBuilder {
     public static final class Delete extends Get {
         private static final String METHOD_NAME = "DELETE";
 
-        public Delete(DataSchemaNode node) {
+        public Delete(final DataSchemaNode node) {
             super(node, false);
         }
 
index c72b5f019dff53a24c8ec22779c4ded342ceb5e7..020290508097db36cf21a3fb0f65fabd94d42b7b 100644 (file)
@@ -94,12 +94,14 @@ public class ApiDocGeneratorTest {
         final Api lstApi = findApi("/config/toaster2:lst/", doc);
         assertNotNull("Api /config/toaster2:lst/ wasn't found", lstApi);
         assertTrue("POST for cont1 in lst is missing",
-                findOperation(lstApi.getOperations(), "POST", "(config)lstPOST", "(config)lst1", "(config)cont1"));
+                findOperation(lstApi.getOperations(), "POST", "(config)lstPOST", "toaster2/lst(config)lst1-TOP",
+                        "toaster2/lst(config)cont1-TOP"));
 
         final Api cont1Api = findApi("/config/toaster2:lst/cont1/", doc);
         assertNotNull("Api /config/toaster2:lst/cont1/ wasn't found", cont1Api);
         assertTrue("POST for cont11 in cont1 is missing",
-                findOperation(cont1Api.getOperations(), "POST", "(config)cont1POST", "(config)cont11", "(config)lst11"));
+                findOperation(cont1Api.getOperations(), "POST", "(config)cont1POST", "toaster2/lst/cont1(config)cont11-TOP",
+                        "toaster2/lst/cont1(config)lst11-TOP"));
 
         // no POST URI
         final Api cont11Api = findApi("/config/toaster2:lst/cont1/cont11/", doc);
@@ -167,25 +169,47 @@ public class ApiDocGeneratorTest {
         final JSONObject models = doc.getModels();
         assertNotNull(models);
         try {
-            final JSONObject configLst = models.getJSONObject("(config)lst");
+            final JSONObject configLstTop = models.getJSONObject("toaster2(config)lst-TOP");
+            assertNotNull(configLstTop);
+
+            containsReferences(configLstTop, "lst", "toaster2(config)");
+
+            final JSONObject configLst = models.getJSONObject("toaster2(config)lst");
             assertNotNull(configLst);
 
-            containsReferences(configLst, "lst1");
-            containsReferences(configLst, "cont1");
+            containsReferences(configLst, "lst1", "toaster2/lst(config)");
+            containsReferences(configLst, "cont1", "toaster2/lst(config)");
+
+            final JSONObject configLst1Top = models.getJSONObject("toaster2/lst(config)lst1-TOP");
+            assertNotNull(configLst1Top);
 
-            final JSONObject configLst1 = models.getJSONObject("(config)lst1");
+            containsReferences(configLst1Top, "lst1", "toaster2/lst(config)");
+
+            final JSONObject configLst1 = models.getJSONObject("toaster2/lst(config)lst1");
             assertNotNull(configLst1);
 
-            final JSONObject configCont1 = models.getJSONObject("(config)cont1");
+            final JSONObject configCont1Top = models.getJSONObject("toaster2/lst(config)cont1-TOP");
+            assertNotNull(configCont1Top);
+
+            containsReferences(configCont1Top, "cont1", "toaster2/lst(config)");
+            final JSONObject configCont1 = models.getJSONObject("toaster2/lst(config)cont1");
             assertNotNull(configCont1);
 
-            containsReferences(configCont1, "cont11");
-            containsReferences(configCont1, "lst11");
+            containsReferences(configCont1, "cont11", "toaster2/lst/cont1(config)");
+            containsReferences(configCont1, "lst11", "toaster2/lst/cont1(config)");
+
+            final JSONObject configCont11Top = models.getJSONObject("toaster2/lst/cont1(config)cont11-TOP");
+            assertNotNull(configCont11Top);
 
-            final JSONObject configCont11 = models.getJSONObject("(config)cont11");
+            containsReferences(configCont11Top, "cont11", "toaster2/lst/cont1(config)");
+            final JSONObject configCont11 = models.getJSONObject("toaster2/lst/cont1(config)cont11");
             assertNotNull(configCont11);
 
-            final JSONObject configLst11 = models.getJSONObject("(config)lst11");
+            final JSONObject configlst11Top = models.getJSONObject("toaster2/lst/cont1(config)lst11-TOP");
+            assertNotNull(configlst11Top);
+
+            containsReferences(configlst11Top, "lst11", "toaster2/lst/cont1(config)");
+            final JSONObject configLst11 = models.getJSONObject("toaster2/lst/cont1(config)lst11");
             assertNotNull(configLst11);
         } catch (final JSONException e) {
             fail("JSONException wasn't expected");
@@ -196,7 +220,8 @@ public class ApiDocGeneratorTest {
     /**
      * Checks whether object {@code mainObject} contains in properties/items key $ref with concrete value.
      */
-    private void containsReferences(final JSONObject mainObject, final String childObject) throws JSONException {
+    private void containsReferences(final JSONObject mainObject, final String childObject, final String prefix)
+            throws JSONException {
         final JSONObject properties = mainObject.getJSONObject("properties");
         assertNotNull(properties);
 
@@ -207,7 +232,7 @@ public class ApiDocGeneratorTest {
         assertNotNull(itemsInNodeInProperties);
 
         final String itemRef = itemsInNodeInProperties.getString("$ref");
-        assertEquals("(config)" + childObject, itemRef);
+        assertEquals(prefix + childObject, itemRef);
     }
 
     @Test
@@ -229,6 +254,29 @@ public class ApiDocGeneratorTest {
         }
     }
 
+    @Test
+    public void testRPCsModel() throws Exception {
+        Preconditions.checkArgument(this.helper.getModules() != null, "No modules found");
+
+        for (final Module m : this.helper.getModules()) {
+            if (m.getQNameModule().getNamespace().toString().equals(NAMESPACE_2)
+                    && m.getQNameModule().getRevision().equals(REVISION_2)) {
+                final ApiDeclaration doc = this.generator.getSwaggerDocSpec(m, "http://localhost:8080/restconf", "",
+                        this.schemaContext);
+                assertNotNull(doc);
+
+                final JSONObject models = doc.getModels();
+                final JSONObject inputTop = models.getJSONObject("(make-toast)input-TOP");
+                final String testString = "{\"input\":{\"type\":\"object\",\"items\":{\"$ref\":\"(make-toast)input\"}}}";
+                assertEquals(testString, inputTop.getJSONObject("properties").toString());
+                final JSONObject input = models.getJSONObject("(make-toast)input");
+                final JSONObject properties = input.getJSONObject("properties");
+                assertTrue(properties.has("toasterDoneness"));
+                assertTrue(properties.has("toasterToastType"));
+            }
+        }
+    }
+
     /**
      * Tests whether from yang files are generated all required paths for HTTP operations (GET, DELETE, PUT, POST)
      *
@@ -309,12 +357,12 @@ public class ApiDocGeneratorTest {
     private void validateTosterDocContainsModulePrefixes(final ApiDeclaration doc) {
         final JSONObject topLevelJson = doc.getModels();
         try {
-            final JSONObject configToaster = topLevelJson.getJSONObject("(config)toaster");
+            final JSONObject configToaster = topLevelJson.getJSONObject("toaster2(config)toaster");
             assertNotNull("(config)toaster JSON object missing", configToaster);
             // without module prefix
             containsProperties(configToaster, "toasterSlot");
 
-            final JSONObject toasterSlot = topLevelJson.getJSONObject("(config)toasterSlot");
+            final JSONObject toasterSlot = topLevelJson.getJSONObject("toaster2/toaster(config)toasterSlot");
             assertNotNull("(config)toasterSlot JSON object missing", toasterSlot);
             // with module prefix
             containsProperties(toasterSlot, "toaster-augmented:slotInfo");