X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=blobdiff_plain;f=restconf%2Fsal-rest-docgen%2Fsrc%2Fmain%2Fjava%2Forg%2Fopendaylight%2Fnetconf%2Fsal%2Frest%2Fdoc%2Fimpl%2FBaseYangSwaggerGenerator.java;h=7e0aac21e43f76c50ccb1146c68fe2be6312915f;hb=f402dcd49a468e018192c96151bef3a0cdf70d62;hp=cbd5c67b0503bf4e5393e22d85f9d047138398e9;hpb=1ae0727e58d68e62915043301d0e3598bdeab5d7;p=netconf.git diff --git a/restconf/sal-rest-docgen/src/main/java/org/opendaylight/netconf/sal/rest/doc/impl/BaseYangSwaggerGenerator.java b/restconf/sal-rest-docgen/src/main/java/org/opendaylight/netconf/sal/rest/doc/impl/BaseYangSwaggerGenerator.java index cbd5c67b05..7e0aac21e4 100644 --- a/restconf/sal-rest-docgen/src/main/java/org/opendaylight/netconf/sal/rest/doc/impl/BaseYangSwaggerGenerator.java +++ b/restconf/sal-rest-docgen/src/main/java/org/opendaylight/netconf/sal/rest/doc/impl/BaseYangSwaggerGenerator.java @@ -7,99 +7,124 @@ */ package org.opendaylight.netconf.sal.rest.doc.impl; +import static org.opendaylight.netconf.sal.rest.doc.impl.ApiDocServiceImpl.DEFAULT_PAGESIZE; import static org.opendaylight.netconf.sal.rest.doc.util.RestDocgenUtil.resolvePathArgumentsName; + import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.SerializationFeature; -import com.fasterxml.jackson.datatype.jsonorg.JsonOrgModule; +import com.fasterxml.jackson.databind.node.ObjectNode; import com.google.common.base.Preconditions; import java.io.IOException; import java.net.URI; -import java.text.DateFormat; -import java.text.ParseException; -import java.text.SimpleDateFormat; +import java.time.format.DateTimeParseException; import java.util.ArrayList; import java.util.Arrays; -import java.util.Calendar; import java.util.Collection; import java.util.Collections; -import java.util.Date; -import java.util.GregorianCalendar; import java.util.List; +import java.util.Map.Entry; +import java.util.Optional; import java.util.Set; import java.util.SortedSet; import java.util.TreeSet; import javax.ws.rs.core.UriInfo; -import org.json.JSONException; -import org.json.JSONObject; +import org.opendaylight.mdsal.dom.api.DOMSchemaService; +import org.opendaylight.netconf.sal.rest.doc.impl.ApiDocServiceImpl.URIType; import org.opendaylight.netconf.sal.rest.doc.model.builder.OperationBuilder; +import org.opendaylight.netconf.sal.rest.doc.model.builder.OperationBuilder.Delete; +import org.opendaylight.netconf.sal.rest.doc.model.builder.OperationBuilder.Get; +import org.opendaylight.netconf.sal.rest.doc.model.builder.OperationBuilder.Post; +import org.opendaylight.netconf.sal.rest.doc.model.builder.OperationBuilder.Put; import org.opendaylight.netconf.sal.rest.doc.swagger.Api; import org.opendaylight.netconf.sal.rest.doc.swagger.ApiDeclaration; import org.opendaylight.netconf.sal.rest.doc.swagger.Operation; import org.opendaylight.netconf.sal.rest.doc.swagger.Parameter; import org.opendaylight.netconf.sal.rest.doc.swagger.Resource; import org.opendaylight.netconf.sal.rest.doc.swagger.ResourceList; -import org.opendaylight.netconf.sal.rest.doc.model.builder.OperationBuilder.Delete; -import org.opendaylight.netconf.sal.rest.doc.model.builder.OperationBuilder.Get; -import org.opendaylight.netconf.sal.rest.doc.model.builder.OperationBuilder.Post; -import org.opendaylight.netconf.sal.rest.doc.model.builder.OperationBuilder.Put; import org.opendaylight.yangtools.yang.common.QName; +import org.opendaylight.yangtools.yang.common.Revision; +import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; +import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates; +import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument; +import org.opendaylight.yangtools.yang.model.api.ActionNodeContainer; import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode; import org.opendaylight.yangtools.yang.model.api.DataNodeContainer; import org.opendaylight.yangtools.yang.model.api.DataSchemaNode; -import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode; import org.opendaylight.yangtools.yang.model.api.ListSchemaNode; import org.opendaylight.yangtools.yang.model.api.Module; +import org.opendaylight.yangtools.yang.model.api.OperationDefinition; import org.opendaylight.yangtools.yang.model.api.RpcDefinition; import org.opendaylight.yangtools.yang.model.api.SchemaContext; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -public class BaseYangSwaggerGenerator { +public abstract class BaseYangSwaggerGenerator { private static final Logger LOG = LoggerFactory.getLogger(BaseYangSwaggerGenerator.class); protected static final String API_VERSION = "1.0.0"; protected static final String SWAGGER_VERSION = "1.2"; - protected static final String RESTCONF_CONTEXT_ROOT = "restconf"; static final String MODULE_NAME_SUFFIX = "_module"; - protected final DateFormat SIMPLE_DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd"); private final ModelGenerator jsonConverter = new ModelGenerator(); // private Map MODULE_DOC_CACHE = new HashMap<>() private final ObjectMapper mapper = new ObjectMapper(); + private final DOMSchemaService schemaService; + + protected BaseYangSwaggerGenerator(final Optional schemaService) { + this.schemaService = schemaService.orElse(null); + this.mapper.configure(SerializationFeature.INDENT_OUTPUT, true); + } + + public DOMSchemaService getSchemaService() { + return schemaService; + } + + public ResourceList getResourceListing(final UriInfo uriInfo, final URIType uriType) { + final SchemaContext schemaContext = schemaService.getGlobalContext(); + Preconditions.checkState(schemaContext != null); + return getResourceListing(uriInfo, schemaContext, "", 0, true, uriType); + } - protected BaseYangSwaggerGenerator() { - mapper.registerModule(new JsonOrgModule()); - mapper.configure(SerializationFeature.INDENT_OUTPUT, true); + public ResourceList getResourceListing(final UriInfo uriInfo, final SchemaContext schemaContext, + final String context, final URIType uriType) { + return getResourceListing(uriInfo, schemaContext, context, 0, true, uriType); } /** - * - * @param uriInfo - * @param schemaContext - * @param context - * @return list of modules converted to swagger compliant resource list. + * 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, final int pageNum, final boolean all, final URIType uriType) { - ResourceList resourceList = createResourceList(); + final ResourceList resourceList = createResourceList(); - Set modules = getSortedModules(schemaContext); + final Set modules = getSortedModules(schemaContext); - List resources = new ArrayList<>(modules.size()); + final List resources = new ArrayList<>(DEFAULT_PAGESIZE); LOG.info("Modules found [{}]", modules.size()); + final int start = DEFAULT_PAGESIZE * pageNum; + final int end = start + DEFAULT_PAGESIZE; + int count = 0; + for (final Module module : modules) { + final String revisionString = module.getQNameModule().getRevision().map(Revision::toString).orElse(null); - for (Module module : modules) { - String revisionString = SIMPLE_DATE_FORMAT.format(module.getRevision()); - 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, uriType); if (doc != null) { - resource.setPath(generatePath(uriInfo, module.getName(), revisionString)); - resources.add(resource); + count++; + if (count >= start && count < end || all) { + final Resource resource = new Resource(); + resource.setPath(generatePath(uriInfo, module.getName(), revisionString)); + resources.add(resource); + } + + if (count >= end && !all) { + break; + } } else { LOG.warn("Could not generate doc for {},{}", module.getName(), revisionString); } @@ -110,109 +135,131 @@ public class BaseYangSwaggerGenerator { return resourceList; } - protected ResourceList createResourceList() { - ResourceList resourceList = new ResourceList(); + public ResourceList createResourceList() { + 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(); + public String generatePath(final UriInfo uriInfo, final String name, final String revision) { + final URI uri = uriInfo.getRequestUriBuilder().replaceQuery("").path(generateCacheKey(name, revision)).build(); return uri.toASCIIString(); } - public ApiDeclaration getApiDeclaration(String module, String revision, UriInfo uriInfo, SchemaContext schemaContext, String context) { - Date rev = null; + public ApiDeclaration getApiDeclaration(final String module, final String revision, final UriInfo uriInfo, + final URIType uriType) { + final SchemaContext schemaContext = schemaService.getGlobalContext(); + Preconditions.checkState(schemaContext != null); + return getApiDeclaration(module, revision, uriInfo, schemaContext, "", uriType); + } + + public ApiDeclaration getApiDeclaration(final String moduleName, final String revision, final UriInfo uriInfo, + final SchemaContext schemaContext, final String context, final URIType uriType) { + final Optional rev; try { - if(revision != null && !revision.equals("0000-00-00")) { - rev = SIMPLE_DATE_FORMAT.parse(revision); - } - } catch (ParseException e) { + rev = Revision.ofNullable(revision); + } catch (final DateTimeParseException e) { throw new IllegalArgumentException(e); } - if(rev != null) { - Calendar cal = new GregorianCalendar(); - - cal.setTime(rev); + final Module module = schemaContext.findModule(moduleName, rev).orElse(null); + Preconditions.checkArgument(module != null, + "Could not find module by name,revision: " + moduleName + "," + revision); - if(cal.get(Calendar.YEAR) < 1970) { - rev = null; - } - } - - Module m = schemaContext.findModuleByName(module, rev); - Preconditions.checkArgument(m != null, "Could not find module by name,revision: " + module + "," + revision); - - return getApiDeclaration(m, rev, uriInfo, context, schemaContext); + return getApiDeclaration(module, uriInfo, context, schemaContext, uriType); } - public ApiDeclaration getApiDeclaration(Module module, Date revision, UriInfo uriInfo, String context, SchemaContext schemaContext) { - String basePath = createBasePathFromUriInfo(uriInfo); + public ApiDeclaration getApiDeclaration(final Module module, final UriInfo uriInfo, + final String context, final SchemaContext schemaContext, final URIType uriType) { + final String basePath = createBasePathFromUriInfo(uriInfo); - ApiDeclaration doc = getSwaggerDocSpec(module, basePath, context, schemaContext); + final ApiDeclaration doc = getSwaggerDocSpec(module, basePath, context, schemaContext, uriType); if (doc != null) { return doc; } return null; } - protected String createBasePathFromUriInfo(UriInfo uriInfo) { + public 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("://") - .append(uriInfo.getBaseUri().getHost()).append(portPart).append("/").append(RESTCONF_CONTEXT_ROOT) - .toString(); + final String basePath = + new StringBuilder(uriInfo.getBaseUri().getScheme()).append("://").append(uriInfo.getBaseUri().getHost()) + .append(portPart).toString(); return basePath; } - public ApiDeclaration getSwaggerDocSpec(Module m, String basePath, String context, SchemaContext schemaContext) { - ApiDeclaration doc = createApiDeclaration(basePath); + public ApiDeclaration getSwaggerDocSpec(final Module module, final String basePath, final String context, + final SchemaContext schemaContext, final URIType uriType) { + final ApiDeclaration doc = createApiDeclaration(basePath); - List apis = new ArrayList<>(); + final List apis = new ArrayList<>(); + boolean hasAddRootPostLink = false; - Collection dataSchemaNodes = m.getChildNodes(); + final Collection dataSchemaNodes = module.getChildNodes(); LOG.debug("child nodes size [{}]", dataSchemaNodes.size()); - for (DataSchemaNode node : dataSchemaNodes) { - if ((node instanceof ListSchemaNode) || (node instanceof ContainerSchemaNode)) { - + for (final DataSchemaNode node : dataSchemaNodes) { + if (node instanceof ListSchemaNode || node instanceof ContainerSchemaNode) { LOG.debug("Is Configuration node [{}] [{}]", node.isConfiguration(), node.getQName().getLocalName()); List pathParams = new ArrayList<>(); - String resourcePath = getDataStorePath("/config/", context); - addRootPostLink(m, (DataNodeContainer) node, pathParams, resourcePath, apis); - addApis(node, apis, resourcePath, pathParams, schemaContext, true); - + String resourcePath; + + /* + * Only when the node's config statement is true, such apis as + * GET/PUT/POST/DELETE config are added for this node. + */ + if (node.isConfiguration()) { // This node's config statement is + // true. + resourcePath = getDataStorePath("config", context); + + /* + * When there are two or more top container or list nodes + * whose config statement is true in module, make sure that + * only one root post link is added for this module. + */ + if (!hasAddRootPostLink) { + LOG.debug("Has added root post link for module {}", module.getName()); + addRootPostLink(module, (DataNodeContainer) node, pathParams, resourcePath, "config", apis); + + hasAddRootPostLink = true; + } + + addApis(node, apis, resourcePath, pathParams, schemaContext, true, module.getName(), "config", + uriType); + } pathParams = new ArrayList<>(); - resourcePath = getDataStorePath("/operational/", context); - addApis(node, apis, resourcePath, pathParams, schemaContext, false); + resourcePath = getDataStorePath("operational", context); + + addApis(node, apis, resourcePath, pathParams, schemaContext, false, module.getName(), "operational", + uriType); } } - Set rpcs = m.getRpcs(); - for (RpcDefinition rpcDefinition : rpcs) { - String resourcePath = getDataStorePath("/operations/", context); - addRpcs(rpcDefinition, apis, resourcePath, schemaContext); + for (final RpcDefinition rpcDefinition : module.getRpcs()) { + final String resourcePath; + resourcePath = getDataStorePath("operations", context); + addOperations(rpcDefinition, apis, resourcePath, schemaContext); } LOG.debug("Number of APIs found [{}]", apis.size()); if (!apis.isEmpty()) { doc.setApis(apis); - JSONObject models = null; + ObjectNode models = null; try { - models = jsonConverter.convertToJsonSchema(m, schemaContext); + models = this.jsonConverter.convertToJsonSchema(module, schemaContext); doc.setModels(models); if (LOG.isDebugEnabled()) { - LOG.debug(mapper.writeValueAsString(doc)); + LOG.debug("Document: {}", this.mapper.writeValueAsString(doc)); } - } catch (IOException | JSONException e) { + } catch (IOException e) { LOG.error("Exception occured in ModelGenerator", e); } @@ -221,18 +268,19 @@ public class BaseYangSwaggerGenerator { return null; } - private void addRootPostLink(final Module m, final DataNodeContainer node, final List pathParams, - final String resourcePath, final List apis) { - if (containsListOrContainer(m.getChildNodes())) { + private void addRootPostLink(final Module module, final DataNodeContainer node, + final List pathParams, final String resourcePath, final String dataStore, final List apis) { + if (containsListOrContainer(module.getChildNodes())) { final Api apiForRootPostUri = new Api(); - apiForRootPostUri.setPath(resourcePath); - apiForRootPostUri.setOperations(operationPost(m.getName()+MODULE_NAME_SUFFIX, m.getDescription(), m, pathParams, true)); + apiForRootPostUri.setPath(resourcePath.concat(getContent(dataStore))); + apiForRootPostUri.setOperations(operationPost(module.getName() + MODULE_NAME_SUFFIX, + module.getDescription().orElse(null), module, pathParams, true, "")); apis.add(apiForRootPostUri); } } - protected ApiDeclaration createApiDeclaration(String basePath) { - ApiDeclaration doc = new ApiDeclaration(); + public ApiDeclaration createApiDeclaration(final String basePath) { + final ApiDeclaration doc = new ApiDeclaration(); doc.setApiVersion(API_VERSION); doc.setSwaggerVersion(SWAGGER_VERSION); doc.setBasePath(basePath); @@ -240,45 +288,52 @@ public class BaseYangSwaggerGenerator { return doc; } - protected String getDataStorePath(String dataStore, String context) { - return dataStore + context; - } + public abstract String getDataStorePath(String dataStore, String context); - private String generateCacheKey(String module, String revision) { + private static String generateCacheKey(final String module, final String revision) { return module + "(" + revision + ")"; } - private void addApis(DataSchemaNode node, List apis, String parentPath, List parentPathParams, SchemaContext schemaContext, - boolean addConfigApi) { + private void addApis(final DataSchemaNode node, final List apis, final String parentPath, + final List parentPathParams, final SchemaContext schemaContext, final boolean addConfigApi, + final String parentName, final String dataStore, final URIType uriType) { + final Api api = new Api(); + final List pathParams = new ArrayList<>(parentPathParams); - Api api = new Api(); - List 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); + api.setPath(resourcePath.concat(getContent(dataStore))); - Iterable childSchemaNodes = Collections. emptySet(); - if ((node instanceof ListSchemaNode) || (node instanceof ContainerSchemaNode)) { - DataNodeContainer dataNodeContainer = (DataNodeContainer) node; + Iterable childSchemaNodes = Collections.emptySet(); + if (node instanceof ListSchemaNode || node instanceof ContainerSchemaNode) { + 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) { + if (uriType.equals(URIType.RFC8040)) { + ((ActionNodeContainer) node).getActions().forEach(actionDef -> { + addOperations(actionDef, apis, resourcePath, schemaContext); + }); + } + + 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, + dataStore, uriType); } } } - } - private boolean containsListOrContainer(final Iterable nodes) { - for (DataSchemaNode child : nodes) { + public abstract String getContent(String dataStore); + + private static boolean containsListOrContainer(final Iterable nodes) { + for (final DataSchemaNode child : nodes) { if (child instanceof ListSchemaNode || child instanceof ContainerSchemaNode) { return true; } @@ -286,66 +341,63 @@ public class BaseYangSwaggerGenerator { return false; } - /** - * @param node - * @param pathParams - * @return - */ - private List operation(DataSchemaNode node, List pathParams, boolean isConfig, Iterable childSchemaNodes) { - List operations = new ArrayList<>(); + private static List operation(final DataSchemaNode node, final List pathParams, + final boolean isConfig, final Iterable childSchemaNodes, + final String parentName) { + final List 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().orElse(null), + 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)); + operations.addAll(operationPost(node.getQName().getLocalName(), node.getDescription().orElse(null), + (DataNodeContainer) node, pathParams, isConfig, parentName + "/")); } } return operations; } - /** - * @param node - * @param pathParams - * @return - */ - private List operationPost(final String name, final String description, final DataNodeContainer dataNodeContainer, List pathParams, boolean isConfig) { - List operations = new ArrayList<>(); + private static List operationPost(final String name, final String description, + final DataNodeContainer dataNodeContainer, final List pathParams, final boolean isConfig, + final String parentName) { + final List 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 pathParams, SchemaContext schemaContext) { - ArrayList pathListParams = new ArrayList<>(); - StringBuilder path = new StringBuilder(); - String localName = resolvePathArgumentsName(schemaNode, schemaContext); + protected abstract ListPathBuilder newListPathBuilder(); + + private String createPath(final DataSchemaNode schemaNode, final List pathParams, + final SchemaContext schemaContext) { + final StringBuilder path = new StringBuilder(); + final String localName = resolvePathArgumentsName(schemaNode, schemaContext); path.append(localName); - if ((schemaNode instanceof ListSchemaNode)) { + if (schemaNode instanceof ListSchemaNode) { final List listKeys = ((ListSchemaNode) schemaNode).getKeyDefinition(); for (final QName listKey : listKeys) { - DataSchemaNode _dataChildByName = ((DataNodeContainer) schemaNode).getDataChildByName(listKey); - pathListParams.add(((LeafSchemaNode) _dataChildByName)); + final ListPathBuilder keyBuilder = newListPathBuilder(); + final String pathParamIdentifier = keyBuilder.nextParamIdentifier(listKey.getLocalName()); - 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()); + + ((DataNodeContainer) schemaNode).findDataChildByName(listKey).flatMap(DataSchemaNode::getDescription) + .ifPresent(pathParam::setDescription); + pathParam.setType("string"); pathParam.setParamType("path"); @@ -355,51 +407,46 @@ public class BaseYangSwaggerGenerator { return path.toString(); } - protected void addRpcs(RpcDefinition rpcDefn, List apis, String parentPath, SchemaContext schemaContext) { - Api rpc = new Api(); - String resourcePath = parentPath + resolvePathArgumentsName(rpcDefn, schemaContext); - rpc.setPath(resourcePath); + protected void addOperations(final OperationDefinition operDef, final List apis, final String parentPath, + final SchemaContext schemaContext) { + final Api operationApi = new Api(); + final String resourcePath = parentPath + "/" + resolvePathArgumentsName(operDef, schemaContext); + operationApi.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.setNotes(operDef.getDescription().orElse(null)); + operationSpec.setNickname(operDef.getQName().getLocalName()); + if (!operDef.getOutput().getChildNodes().isEmpty()) { + operationSpec.setType("(" + operDef.getQName().getLocalName() + ")output" + OperationBuilder.TOP); } - if (rpcDefn.getInput() != null) { - Parameter payload = new Parameter(); + if (!operDef.getInput().getChildNodes().isEmpty()) { + final Parameter payload = new Parameter(); payload.setParamType("body"); - payload.setType("(" + rpcDefn.getQName().getLocalName() + ")input"); + payload.setType("(" + operDef.getQName().getLocalName() + ")input" + OperationBuilder.TOP); operationSpec.setParameters(Collections.singletonList(payload)); operationSpec.setConsumes(OperationBuilder.CONSUMES_PUT_POST); } - - rpc.setOperations(Arrays.asList(operationSpec)); - - apis.add(rpc); + operationApi.setOperations(Arrays.asList(operationSpec)); + apis.add(operationApi); } - protected SortedSet getSortedModules(SchemaContext schemaContext) { + protected SortedSet getSortedModules(final SchemaContext schemaContext) { if (schemaContext == null) { return new TreeSet<>(); } - Set modules = schemaContext.getModules(); - - SortedSet sortedModules = new TreeSet<>((module1, module2) -> { + final SortedSet 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); - result = module1Revision.compareTo(module2Revision); + result = Revision.compare(module1.getRevision(), module2.getRevision()); } if (result == 0) { result = module1.getNamespace().compareTo(module2.getNamespace()); } return result; }); - for (Module m : modules) { + for (final Module m : schemaContext.getModules()) { if (m != null) { sortedModules.add(m); } @@ -407,4 +454,29 @@ public class BaseYangSwaggerGenerator { return sortedModules; } + protected abstract void appendPathKeyValue(StringBuilder builder, Object value); + + public String generateUrlPrefixFromInstanceID(final YangInstanceIdentifier key, final String moduleName) { + final StringBuilder builder = new StringBuilder(); + builder.append("/"); + if (moduleName != null) { + builder.append(moduleName).append(':'); + } + for (final PathArgument arg : key.getPathArguments()) { + final String name = arg.getNodeType().getLocalName(); + if (arg instanceof YangInstanceIdentifier.NodeIdentifierWithPredicates) { + final NodeIdentifierWithPredicates nodeId = (NodeIdentifierWithPredicates) arg; + for (final Entry entry : nodeId.entrySet()) { + appendPathKeyValue(builder, entry.getValue()); + } + } else { + builder.append(name).append('/'); + } + } + return builder.toString(); + } + + protected interface ListPathBuilder { + String nextParamIdentifier(String key); + } }