2 * Copyright (c) 2014 Brocade Communications Systems, Inc. and others. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
8 package org.opendaylight.netconf.sal.rest.doc.impl;
10 import static org.opendaylight.netconf.sal.rest.doc.impl.ApiDocServiceImpl.DEFAULT_PAGESIZE;
11 import static org.opendaylight.netconf.sal.rest.doc.model.builder.OperationBuilder.CONFIG;
12 import static org.opendaylight.netconf.sal.rest.doc.model.builder.OperationBuilder.TOP;
13 import static org.opendaylight.netconf.sal.rest.doc.model.builder.OperationBuilder.buildDelete;
14 import static org.opendaylight.netconf.sal.rest.doc.model.builder.OperationBuilder.buildGet;
15 import static org.opendaylight.netconf.sal.rest.doc.model.builder.OperationBuilder.buildPost;
16 import static org.opendaylight.netconf.sal.rest.doc.model.builder.OperationBuilder.buildPostOperation;
17 import static org.opendaylight.netconf.sal.rest.doc.model.builder.OperationBuilder.buildPut;
18 import static org.opendaylight.netconf.sal.rest.doc.model.builder.OperationBuilder.getTypeParentNode;
19 import static org.opendaylight.netconf.sal.rest.doc.util.JsonUtil.addFields;
20 import static org.opendaylight.netconf.sal.rest.doc.util.RestDocgenUtil.resolvePathArgumentsName;
22 import com.fasterxml.jackson.databind.JsonNode;
23 import com.fasterxml.jackson.databind.ObjectMapper;
24 import com.fasterxml.jackson.databind.SerializationFeature;
25 import com.fasterxml.jackson.databind.node.ArrayNode;
26 import com.fasterxml.jackson.databind.node.JsonNodeFactory;
27 import com.fasterxml.jackson.databind.node.ObjectNode;
28 import com.google.common.base.Preconditions;
29 import com.google.common.collect.ImmutableList;
30 import com.google.common.collect.Range;
31 import java.io.IOException;
33 import java.time.format.DateTimeParseException;
34 import java.util.ArrayList;
35 import java.util.Arrays;
36 import java.util.Collection;
37 import java.util.Collections;
38 import java.util.HashMap;
39 import java.util.Iterator;
40 import java.util.List;
42 import java.util.Map.Entry;
43 import java.util.Optional;
45 import java.util.SortedSet;
46 import java.util.TreeSet;
47 import javax.ws.rs.core.UriInfo;
48 import org.opendaylight.mdsal.dom.api.DOMSchemaService;
49 import org.opendaylight.netconf.sal.rest.doc.impl.ApiDocServiceImpl.OAversion;
50 import org.opendaylight.netconf.sal.rest.doc.impl.ApiDocServiceImpl.URIType;
51 import org.opendaylight.netconf.sal.rest.doc.swagger.CommonApiObject;
52 import org.opendaylight.netconf.sal.rest.doc.swagger.Components;
53 import org.opendaylight.netconf.sal.rest.doc.swagger.Info;
54 import org.opendaylight.netconf.sal.rest.doc.swagger.OpenApiObject;
55 import org.opendaylight.netconf.sal.rest.doc.swagger.Resource;
56 import org.opendaylight.netconf.sal.rest.doc.swagger.ResourceList;
57 import org.opendaylight.netconf.sal.rest.doc.swagger.Server;
58 import org.opendaylight.netconf.sal.rest.doc.swagger.SwaggerObject;
59 import org.opendaylight.netconf.sal.rest.doc.util.JsonUtil;
60 import org.opendaylight.yangtools.yang.common.QName;
61 import org.opendaylight.yangtools.yang.common.Revision;
62 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
63 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
64 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
65 import org.opendaylight.yangtools.yang.model.api.ActionNodeContainer;
66 import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
67 import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
68 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
69 import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
70 import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
71 import org.opendaylight.yangtools.yang.model.api.Module;
72 import org.opendaylight.yangtools.yang.model.api.OperationDefinition;
73 import org.opendaylight.yangtools.yang.model.api.RpcDefinition;
74 import org.slf4j.Logger;
75 import org.slf4j.LoggerFactory;
77 public abstract class BaseYangSwaggerGenerator {
79 private static final Logger LOG = LoggerFactory.getLogger(BaseYangSwaggerGenerator.class);
81 private static final String API_VERSION = "1.0.0";
82 private static final String SWAGGER_VERSION = "2.0";
83 private static final String OPEN_API_VERSION = "3.0.3";
85 private final DefinitionGenerator jsonConverter = new DefinitionGenerator();
87 private final ObjectMapper mapper = new ObjectMapper();
88 private final DOMSchemaService schemaService;
90 public static final String BASE_PATH = "/";
91 public static final String MODULE_NAME_SUFFIX = "_module";
93 protected BaseYangSwaggerGenerator(final Optional<DOMSchemaService> schemaService) {
94 this.schemaService = schemaService.orElse(null);
95 this.mapper.configure(SerializationFeature.INDENT_OUTPUT, true);
98 public DOMSchemaService getSchemaService() {
102 public ResourceList getResourceListing(final UriInfo uriInfo, final EffectiveModelContext schemaContext,
103 final String context, final URIType uriType, final OAversion oaversion) {
104 return getResourceListing(uriInfo, schemaContext, context, 0, true, uriType, oaversion);
108 * Return list of modules converted to swagger compliant resource list.
110 public ResourceList getResourceListing(final UriInfo uriInfo, final EffectiveModelContext schemaContext,
111 final String context, final int pageNum, final boolean all,
112 final URIType uriType, final OAversion oaversion) {
113 final ResourceList resourceList = createResourceList();
115 final Set<Module> modules = getSortedModules(schemaContext);
117 final List<Resource> resources = new ArrayList<>(DEFAULT_PAGESIZE);
119 LOG.info("Modules found [{}]", modules.size());
120 final int start = DEFAULT_PAGESIZE * pageNum;
121 final int end = start + DEFAULT_PAGESIZE;
123 for (final Module module : modules) {
124 final String revisionString = module.getQNameModule().getRevision().map(Revision::toString).orElse(null);
126 LOG.debug("Working on [{},{}]...", module.getName(), revisionString);
127 final SwaggerObject doc = getApiDeclaration(module.getName(), revisionString, uriInfo, schemaContext,
128 context, uriType, oaversion);
131 if (count >= start && count < end || all) {
132 final Resource resource = new Resource();
133 resource.setPath(generatePath(uriInfo, module.getName(), revisionString));
134 resources.add(resource);
137 if (count >= end && !all) {
141 LOG.warn("Could not generate doc for {},{}", module.getName(), revisionString);
145 resourceList.setApis(resources);
150 public SwaggerObject getAllModulesDoc(final UriInfo uriInfo, final DefinitionNames definitionNames,
151 final URIType uriType, final OAversion oaversion) {
152 final EffectiveModelContext schemaContext = schemaService.getGlobalContext();
153 Preconditions.checkState(schemaContext != null);
154 return getAllModulesDoc(uriInfo, Optional.empty(), schemaContext, Optional.empty(), "", definitionNames,
158 public SwaggerObject getAllModulesDoc(final UriInfo uriInfo, final Optional<Range<Integer>> range,
159 final EffectiveModelContext schemaContext, final Optional<String> deviceName,
160 final String context, final DefinitionNames definitionNames,
161 final URIType uriType, final OAversion oaversion) {
162 final String schema = createSchemaFromUriInfo(uriInfo);
163 final String host = createHostFromUriInfo(uriInfo);
164 String name = "Controller";
165 if (deviceName.isPresent()) {
166 name = deviceName.get();
169 final String title = String.format("%s modules of RestConf version %s", name, uriType.name());
170 final SwaggerObject doc = createSwaggerObject(schema, host, BASE_PATH, title);
171 doc.setDefinitions(JsonNodeFactory.instance.objectNode());
172 doc.setPaths(JsonNodeFactory.instance.objectNode());
174 fillDoc(doc, range, schemaContext, context, deviceName, uriType, oaversion, definitionNames);
179 public void fillDoc(final SwaggerObject doc, final Optional<Range<Integer>> range,
180 final EffectiveModelContext schemaContext, final String context,
181 final Optional<String> deviceName, final URIType uriType, final OAversion oaversion,
182 final DefinitionNames definitionNames) {
183 final SortedSet<Module> modules = getSortedModules(schemaContext);
184 final Set<Module> filteredModules;
185 if (range.isPresent()) {
186 filteredModules = filterByRange(modules, range.get());
188 filteredModules = modules;
191 for (final Module module : filteredModules) {
192 final String revisionString = module.getQNameModule().getRevision().map(Revision::toString).orElse(null);
194 LOG.debug("Working on [{},{}]...", module.getName(), revisionString);
196 getSwaggerDocSpec(module, context, deviceName, schemaContext, uriType, oaversion, definitionNames, doc,
201 private static Set<Module> filterByRange(final SortedSet<Module> modules, final Range<Integer> range) {
202 final int begin = range.lowerEndpoint();
203 final int end = range.upperEndpoint();
205 Module firstModule = null;
207 final Iterator<Module> iterator = modules.iterator();
209 while (iterator.hasNext() && counter < end) {
210 final Module module = iterator.next();
211 if (containsListOrContainer(module.getChildNodes()) || !module.getRpcs().isEmpty()) {
212 if (counter == begin) {
213 firstModule = module;
219 if (iterator.hasNext()) {
220 return modules.subSet(firstModule, iterator.next());
222 return modules.tailSet(firstModule);
226 public ResourceList createResourceList() {
227 final ResourceList resourceList = new ResourceList();
228 resourceList.setApiVersion(API_VERSION);
229 resourceList.setSwaggerVersion(SWAGGER_VERSION);
233 public String generatePath(final UriInfo uriInfo, final String name, final String revision) {
234 final URI uri = uriInfo.getRequestUriBuilder().replaceQuery("").path(generateCacheKey(name, revision)).build();
235 return uri.toASCIIString();
238 public CommonApiObject getApiDeclaration(final String module, final String revision, final UriInfo uriInfo,
239 final URIType uriType, final OAversion oaversion) {
240 final EffectiveModelContext schemaContext = schemaService.getGlobalContext();
241 Preconditions.checkState(schemaContext != null);
242 final SwaggerObject doc = getApiDeclaration(module, revision, uriInfo, schemaContext, "", uriType,
244 return getAppropriateDoc(doc, oaversion);
247 public SwaggerObject getApiDeclaration(final String moduleName, final String revision, final UriInfo uriInfo,
248 final EffectiveModelContext schemaContext, final String context,
249 final URIType uriType, final OAversion oaversion) {
250 final Optional<Revision> rev;
253 rev = Revision.ofNullable(revision);
254 } catch (final DateTimeParseException e) {
255 throw new IllegalArgumentException(e);
258 final Module module = schemaContext.findModule(moduleName, rev).orElse(null);
259 Preconditions.checkArgument(module != null,
260 "Could not find module by name,revision: " + moduleName + "," + revision);
262 return getApiDeclaration(module, uriInfo, context, schemaContext, uriType, oaversion);
265 public SwaggerObject getApiDeclaration(final Module module, final UriInfo uriInfo,
266 final String context, final EffectiveModelContext schemaContext,
267 final URIType uriType, final OAversion oaversion) {
268 final String schema = createSchemaFromUriInfo(uriInfo);
269 final String host = createHostFromUriInfo(uriInfo);
271 return getSwaggerDocSpec(module, schema, host, BASE_PATH, context, schemaContext, uriType, oaversion);
274 public String createHostFromUriInfo(final UriInfo uriInfo) {
275 String portPart = "";
276 final int port = uriInfo.getBaseUri().getPort();
278 portPart = ":" + port;
280 return uriInfo.getBaseUri().getHost() + portPart;
283 public String createSchemaFromUriInfo(final UriInfo uriInfo) {
284 return uriInfo.getBaseUri().getScheme();
287 public SwaggerObject getSwaggerDocSpec(final Module module, final String schema, final String host,
288 final String basePath, final String context,
289 final EffectiveModelContext schemaContext, final URIType uriType,
290 final OAversion oaversion) {
291 final SwaggerObject doc = createSwaggerObject(schema, host, basePath, module.getName());
292 final DefinitionNames definitionNames = new DefinitionNames();
293 return getSwaggerDocSpec(module, context, Optional.empty(), schemaContext, uriType, oaversion,
294 definitionNames, doc, true);
298 public SwaggerObject getSwaggerDocSpec(final Module module, final String context, final Optional<String> deviceName,
299 final EffectiveModelContext schemaContext, final URIType uriType,
300 final OAversion oaversion, final DefinitionNames definitionNames,
301 final SwaggerObject doc, final boolean isForSingleModule) {
302 final ObjectNode definitions;
305 if (isForSingleModule) {
306 definitions = this.jsonConverter.convertToJsonSchema(module, schemaContext, definitionNames, oaversion,
308 doc.setDefinitions(definitions);
310 definitions = this.jsonConverter.convertToJsonSchema(module, schemaContext, definitionNames, oaversion,
312 addFields(doc.getDefinitions(), definitions.fields());
314 if (LOG.isDebugEnabled()) {
315 LOG.debug("Document: {}", this.mapper.writeValueAsString(doc));
317 } catch (final IOException e) {
318 LOG.error("Exception occured in DefinitionGenerator", e);
321 final ObjectNode paths = JsonNodeFactory.instance.objectNode();
322 final String moduleName = module.getName();
324 boolean hasAddRootPostLink = false;
326 final Collection<? extends DataSchemaNode> dataSchemaNodes = module.getChildNodes();
327 LOG.debug("child nodes size [{}]", dataSchemaNodes.size());
328 for (final DataSchemaNode node : dataSchemaNodes) {
329 if (node instanceof ListSchemaNode || node instanceof ContainerSchemaNode) {
330 LOG.debug("Is Configuration node [{}] [{}]", node.isConfiguration(), node.getQName().getLocalName());
332 final String localName = module.getName() + ":" + node.getQName().getLocalName();
333 ArrayNode pathParams = JsonNodeFactory.instance.arrayNode();
336 if (node.isConfiguration()) { // This node's config statement is
338 resourcePath = getResourcePath("config", context);
341 * When there are two or more top container or list nodes
342 * whose config statement is true in module, make sure that
343 * only one root post link is added for this module.
345 if (isForSingleModule && !hasAddRootPostLink) {
346 LOG.debug("Has added root post link for module {}", module.getName());
347 addRootPostLink(module, deviceName, pathParams, resourcePath, paths, oaversion);
349 hasAddRootPostLink = true;
352 final String resolvedPath = resourcePath + "/" + createPath(node, pathParams, oaversion, localName);
353 addPaths(node, deviceName, moduleName, paths, pathParams, schemaContext, true,
354 module.getName(), definitionNames, uriType, oaversion, resolvedPath);
356 pathParams = JsonNodeFactory.instance.arrayNode();
357 resourcePath = getResourcePath("operational", context);
359 if (uriType.equals(URIType.DRAFT02)
360 || uriType.equals(URIType.RFC8040) && !node.isConfiguration()) {
361 final String resolvedPath = resourcePath + "/" + createPath(node, pathParams, oaversion, localName);
362 addPaths(node, deviceName, moduleName, paths, pathParams, schemaContext, false,
363 moduleName, definitionNames, uriType, oaversion, resolvedPath);
368 for (final RpcDefinition rpcDefinition : module.getRpcs()) {
369 final String resolvedPath = getResourcePath("operations", context) + "/" + moduleName + ":"
370 + rpcDefinition.getQName().getLocalName();
371 addOperations(rpcDefinition, moduleName, deviceName, paths, module.getName(), definitionNames, oaversion,
375 LOG.debug("Number of Paths found [{}]", paths.size());
377 if (isForSingleModule) {
380 addFields(doc.getPaths(), paths.fields());
386 private static void addRootPostLink(final Module module, final Optional<String> deviceName,
387 final ArrayNode pathParams, final String resourcePath, final ObjectNode paths, final OAversion oaversion) {
388 if (containsListOrContainer(module.getChildNodes())) {
389 final ObjectNode post = JsonNodeFactory.instance.objectNode();
390 final String moduleName = module.getName();
391 final String name = moduleName + MODULE_NAME_SUFFIX;
392 post.set("post", buildPost("", name, "", moduleName, deviceName,
393 module.getDescription().orElse(""), pathParams, oaversion));
394 paths.set(resourcePath, post);
398 public SwaggerObject createSwaggerObject(final String schema, final String host, final String basePath,
399 final String title) {
400 final SwaggerObject doc = new SwaggerObject();
401 doc.setSwagger(SWAGGER_VERSION);
402 final Info info = new Info();
403 info.setTitle(title);
404 info.setVersion(API_VERSION);
406 doc.setSchemes(ImmutableList.of(schema));
408 doc.setBasePath(basePath);
409 doc.setProduces(Arrays.asList("application/xml", "application/json"));
413 public static CommonApiObject getAppropriateDoc(final SwaggerObject swaggerObject, final OAversion oaversion) {
414 if (oaversion.equals(OAversion.V3_0)) {
415 return convertToOpenApi(swaggerObject);
417 return swaggerObject;
420 private static OpenApiObject convertToOpenApi(final SwaggerObject swaggerObject) {
421 final OpenApiObject doc = new OpenApiObject();
422 doc.setOpenapi(OPEN_API_VERSION);
423 doc.setInfo(swaggerObject.getInfo());
424 doc.setServers(convertToServers(swaggerObject.getSchemes(), swaggerObject.getHost(),
425 swaggerObject.getBasePath()));
426 doc.setPaths(swaggerObject.getPaths());
427 doc.setComponents(new Components(swaggerObject.getDefinitions()));
432 private static List<Server> convertToServers(final List<String> schemes, final String host, final String basePath) {
433 return ImmutableList.of(new Server(schemes.get(0) + "://" + host + basePath));
436 protected abstract String getPathVersion();
438 public abstract String getResourcePath(String resourceType, String context);
440 public abstract String getResourcePathPart(String resourceType);
442 private static String generateCacheKey(final String module, final String revision) {
443 return module + "(" + revision + ")";
446 private void addPaths(final DataSchemaNode node, final Optional<String> deviceName, final String moduleName,
447 final ObjectNode paths, final ArrayNode parentPathParams,
448 final EffectiveModelContext schemaContext, final boolean isConfig, final String parentName,
449 final DefinitionNames definitionNames, final URIType uriType, final OAversion oaversion,
450 final String resourcePath) {
451 LOG.debug("Adding path: [{}]", resourcePath);
453 final ArrayNode pathParams = JsonUtil.copy(parentPathParams);
454 Iterable<? extends DataSchemaNode> childSchemaNodes = Collections.emptySet();
455 if (node instanceof ListSchemaNode || node instanceof ContainerSchemaNode) {
456 final DataNodeContainer dataNodeContainer = (DataNodeContainer) node;
457 childSchemaNodes = dataNodeContainer.getChildNodes();
460 final ObjectNode path = JsonNodeFactory.instance.objectNode();
461 path.setAll(operations(node, moduleName, deviceName, pathParams, isConfig, parentName, definitionNames,
462 uriType, oaversion));
463 paths.set(resourcePath, path);
465 if (uriType.equals(URIType.RFC8040)) {
466 ((ActionNodeContainer) node).getActions().forEach(actionDef -> {
467 final String resolvedPath = "rests/operations" + resourcePath.substring(11)
468 + "/" + resolvePathArgumentsName(actionDef.getQName(), node.getQName(), schemaContext);
469 addOperations(actionDef, moduleName, deviceName, paths, parentName, definitionNames, oaversion,
474 for (final DataSchemaNode childNode : childSchemaNodes) {
475 if (childNode instanceof ListSchemaNode || childNode instanceof ContainerSchemaNode) {
476 final String newParent = parentName + "_" + node.getQName().getLocalName();
477 final String localName = resolvePathArgumentsName(childNode.getQName(), node.getQName(), schemaContext);
478 final String newResourcePath = resourcePath + "/" + createPath(childNode, pathParams, oaversion,
480 if (uriType.equals(URIType.RFC8040)) {
481 final boolean newIsConfig = isConfig && childNode.isConfiguration();
482 addPaths(childNode, deviceName, moduleName, paths, pathParams, schemaContext,
483 newIsConfig, newParent, definitionNames, uriType, oaversion, newResourcePath);
485 if (!isConfig || childNode.isConfiguration()) {
486 addPaths(childNode, deviceName, moduleName, paths, pathParams, schemaContext,
487 isConfig, newParent, definitionNames, uriType, oaversion, newResourcePath);
494 private static boolean containsListOrContainer(final Iterable<? extends DataSchemaNode> nodes) {
495 for (final DataSchemaNode child : nodes) {
496 if (child instanceof ListSchemaNode || child instanceof ContainerSchemaNode) {
503 private static Map<String, ObjectNode> operations(final DataSchemaNode node, final String moduleName,
504 final Optional<String> deviceName, final ArrayNode pathParams,
505 final boolean isConfig, final String parentName,
506 final DefinitionNames definitionNames, final URIType uriType,
507 final OAversion oaversion) {
508 final Map<String, ObjectNode> operations = new HashMap<>();
509 final String discriminator = definitionNames.getDiscriminator(node);
511 final String nodeName = node.getQName().getLocalName();
514 if (isConfig && uriType.equals(URIType.DRAFT02)) {
515 prefix = CONFIG + "_";
518 final String defName = parentName + prefix + nodeName + TOP + discriminator;
519 final ObjectNode get = buildGet(node, moduleName, deviceName, pathParams, defName, isConfig, uriType,
521 operations.put("get", get);
525 final ObjectNode put = buildPut(parentName, nodeName, discriminator, moduleName, deviceName,
526 node.getDescription().orElse(""), pathParams, oaversion);
527 operations.put("put", put);
529 final ObjectNode delete = buildDelete(node, moduleName, deviceName, pathParams, oaversion);
530 operations.put("delete", delete);
532 operations.put("post", buildPost(parentName, nodeName, discriminator, moduleName, deviceName,
533 node.getDescription().orElse(""), pathParams, oaversion));
538 protected abstract ListPathBuilder newListPathBuilder();
540 private String createPath(final DataSchemaNode schemaNode, final ArrayNode pathParams,
541 final OAversion oaversion, final String localName) {
542 final StringBuilder path = new StringBuilder();
543 path.append(localName);
545 if (schemaNode instanceof ListSchemaNode) {
546 final ListPathBuilder keyBuilder = newListPathBuilder();
547 for (final QName listKey : ((ListSchemaNode) schemaNode).getKeyDefinition()) {
548 final String paramName = createUniquePathParamName(listKey.getLocalName(), pathParams);
549 final String pathParamIdentifier = keyBuilder.nextParamIdentifier(paramName);
551 path.append(pathParamIdentifier);
553 final ObjectNode pathParam = JsonNodeFactory.instance.objectNode();
554 pathParam.put("name", paramName);
556 ((DataNodeContainer) schemaNode).findDataChildByName(listKey).flatMap(DataSchemaNode::getDescription)
557 .ifPresent(desc -> pathParam.put("description", desc));
559 final ObjectNode typeParent = getTypeParentNode(pathParam, oaversion);
561 typeParent.put("type", "string");
562 pathParam.put("in", "path");
563 pathParam.put("required", true);
565 pathParams.add(pathParam);
568 return path.toString();
571 private String createUniquePathParamName(final String clearName, final ArrayNode pathParams) {
572 for (final JsonNode pathParam : pathParams) {
573 if (isNamePicked(clearName, pathParam)) {
574 return createUniquePathParamName(clearName, pathParams, 1);
580 private String createUniquePathParamName(final String clearName, final ArrayNode pathParams,
581 final int discriminator) {
582 final String newName = clearName + discriminator;
583 for (final JsonNode pathParam : pathParams) {
584 if (isNamePicked(newName, pathParam)) {
585 return createUniquePathParamName(clearName, pathParams, discriminator + 1);
591 private static boolean isNamePicked(final String name, final JsonNode pathParam) {
592 return name.equals(pathParam.get("name").asText());
595 public SortedSet<Module> getSortedModules(final EffectiveModelContext schemaContext) {
596 if (schemaContext == null) {
597 return Collections.emptySortedSet();
600 final SortedSet<Module> sortedModules = new TreeSet<>((module1, module2) -> {
601 int result = module1.getName().compareTo(module2.getName());
603 result = Revision.compare(module1.getRevision(), module2.getRevision());
606 result = module1.getNamespace().compareTo(module2.getNamespace());
610 for (final Module m : schemaContext.getModules()) {
612 sortedModules.add(m);
615 return sortedModules;
618 private static void addOperations(final OperationDefinition operDef, final String moduleName,
619 final Optional<String> deviceName, final ObjectNode paths, final String parentName,
620 final DefinitionNames definitionNames, final OAversion oaversion, final String resourcePath) {
621 final ObjectNode operations = JsonNodeFactory.instance.objectNode();
622 operations.set("post", buildPostOperation(operDef, moduleName, deviceName, parentName, definitionNames,
624 paths.set(resourcePath, operations);
627 protected abstract void appendPathKeyValue(StringBuilder builder, Object value);
629 public String generateUrlPrefixFromInstanceID(final YangInstanceIdentifier key, final String moduleName) {
630 final StringBuilder builder = new StringBuilder();
632 if (moduleName != null) {
633 builder.append(moduleName).append(':');
635 for (final PathArgument arg : key.getPathArguments()) {
636 final String name = arg.getNodeType().getLocalName();
637 if (arg instanceof NodeIdentifierWithPredicates) {
638 final NodeIdentifierWithPredicates nodeId = (NodeIdentifierWithPredicates) arg;
639 for (final Entry<QName, Object> entry : nodeId.entrySet()) {
640 appendPathKeyValue(builder, entry.getValue());
643 builder.append(name).append('/');
646 return builder.toString();
649 protected interface ListPathBuilder {
650 String nextParamIdentifier(String key);