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 ArrayNode pathParams = JsonNodeFactory.instance.arrayNode();
335 if (node.isConfiguration()) { // This node's config statement is
337 resourcePath = getResourcePath("config", context);
340 * When there are two or more top container or list nodes
341 * whose config statement is true in module, make sure that
342 * only one root post link is added for this module.
344 if (isForSingleModule && !hasAddRootPostLink) {
345 LOG.debug("Has added root post link for module {}", module.getName());
346 addRootPostLink(module, deviceName, pathParams, resourcePath, paths, oaversion);
348 hasAddRootPostLink = true;
351 addPaths(node, deviceName, moduleName, paths, resourcePath, pathParams, schemaContext, true,
352 module.getName(), definitionNames, uriType, oaversion);
354 pathParams = JsonNodeFactory.instance.arrayNode();
355 resourcePath = getResourcePath("operational", context);
357 if (uriType.equals(URIType.DRAFT02)
358 || uriType.equals(URIType.RFC8040) && !node.isConfiguration()) {
359 addPaths(node, deviceName, moduleName, paths, resourcePath, pathParams, schemaContext, false,
360 moduleName, definitionNames, uriType, oaversion);
365 for (final RpcDefinition rpcDefinition : module.getRpcs()) {
366 final String resourcePath = getResourcePath("operations", context);
367 addOperations(rpcDefinition, moduleName, deviceName, paths, resourcePath, module.getName(), definitionNames,
368 schemaContext, oaversion);
371 LOG.debug("Number of Paths found [{}]", paths.size());
373 if (isForSingleModule) {
376 addFields(doc.getPaths(), paths.fields());
382 private static void addRootPostLink(final Module module, final Optional<String> deviceName,
383 final ArrayNode pathParams, final String resourcePath, final ObjectNode paths, final OAversion oaversion) {
384 if (containsListOrContainer(module.getChildNodes())) {
385 final ObjectNode post = JsonNodeFactory.instance.objectNode();
386 final String moduleName = module.getName();
387 final String name = moduleName + MODULE_NAME_SUFFIX;
388 post.set("post", buildPost("", name, "", moduleName, deviceName,
389 module.getDescription().orElse(""), pathParams, oaversion));
390 paths.set(resourcePath, post);
394 public SwaggerObject createSwaggerObject(final String schema, final String host, final String basePath,
395 final String title) {
396 final SwaggerObject doc = new SwaggerObject();
397 doc.setSwagger(SWAGGER_VERSION);
398 final Info info = new Info();
399 info.setTitle(title);
400 info.setVersion(API_VERSION);
402 doc.setSchemes(ImmutableList.of(schema));
404 doc.setBasePath(basePath);
405 doc.setProduces(Arrays.asList("application/xml", "application/json"));
409 public static CommonApiObject getAppropriateDoc(final SwaggerObject swaggerObject, final OAversion oaversion) {
410 if (oaversion.equals(OAversion.V3_0)) {
411 return convertToOpenApi(swaggerObject);
413 return swaggerObject;
416 private static OpenApiObject convertToOpenApi(final SwaggerObject swaggerObject) {
417 final OpenApiObject doc = new OpenApiObject();
418 doc.setOpenapi(OPEN_API_VERSION);
419 doc.setInfo(swaggerObject.getInfo());
420 doc.setServers(convertToServers(swaggerObject.getSchemes(), swaggerObject.getHost(),
421 swaggerObject.getBasePath()));
422 doc.setPaths(swaggerObject.getPaths());
423 doc.setComponents(new Components(swaggerObject.getDefinitions()));
428 private static List<Server> convertToServers(final List<String> schemes, final String host, final String basePath) {
429 return ImmutableList.of(new Server(schemes.get(0) + "://" + host + basePath));
432 protected abstract String getPathVersion();
434 public abstract String getResourcePath(String resourceType, String context);
436 public abstract String getResourcePathPart(String resourceType);
438 private static String generateCacheKey(final String module, final String revision) {
439 return module + "(" + revision + ")";
442 private void addPaths(final DataSchemaNode node, final Optional<String> deviceName, final String moduleName,
443 final ObjectNode paths, final String parentPath, final ArrayNode parentPathParams,
444 final EffectiveModelContext schemaContext, final boolean isConfig, final String parentName,
445 final DefinitionNames definitionNames, final URIType uriType, final OAversion oaversion) {
446 final ArrayNode pathParams = JsonUtil.copy(parentPathParams);
447 final String resourcePath = parentPath + "/" + createPath(node, pathParams, schemaContext, oaversion);
448 LOG.debug("Adding path: [{}]", resourcePath);
450 Iterable<? extends DataSchemaNode> childSchemaNodes = Collections.emptySet();
451 if (node instanceof ListSchemaNode || node instanceof ContainerSchemaNode) {
452 final DataNodeContainer dataNodeContainer = (DataNodeContainer) node;
453 childSchemaNodes = dataNodeContainer.getChildNodes();
456 final ObjectNode path = JsonNodeFactory.instance.objectNode();
457 path.setAll(operations(node, moduleName, deviceName, pathParams, isConfig, parentName, definitionNames,
458 uriType, oaversion));
459 paths.set(resourcePath, path);
462 if (uriType.equals(URIType.RFC8040)) {
463 final String operationPath = "rests/operations" + resourcePath.substring(11);
464 ((ActionNodeContainer) node).getActions().forEach(actionDef ->
465 addOperations(actionDef, moduleName, deviceName, paths, operationPath, parentName, definitionNames,
466 schemaContext, oaversion));
470 for (final DataSchemaNode childNode : childSchemaNodes) {
471 if (childNode instanceof ListSchemaNode || childNode instanceof ContainerSchemaNode) {
472 final String newParent = parentName + "_" + node.getQName().getLocalName();
473 if (uriType.equals(URIType.RFC8040)) {
474 final boolean newIsConfig = isConfig && childNode.isConfiguration();
475 addPaths(childNode, deviceName, moduleName, paths, resourcePath, pathParams, schemaContext,
476 newIsConfig, newParent, definitionNames, uriType, oaversion);
478 if (!isConfig || childNode.isConfiguration()) {
479 addPaths(childNode, deviceName, moduleName, paths, resourcePath, pathParams, schemaContext,
480 isConfig, newParent, definitionNames, uriType, oaversion);
487 private static boolean containsListOrContainer(final Iterable<? extends DataSchemaNode> nodes) {
488 for (final DataSchemaNode child : nodes) {
489 if (child instanceof ListSchemaNode || child instanceof ContainerSchemaNode) {
496 private static Map<String, ObjectNode> operations(final DataSchemaNode node, final String moduleName,
497 final Optional<String> deviceName, final ArrayNode pathParams,
498 final boolean isConfig, final String parentName,
499 final DefinitionNames definitionNames, final URIType uriType,
500 final OAversion oaversion) {
501 final Map<String, ObjectNode> operations = new HashMap<>();
502 final String discriminator = definitionNames.getDiscriminator(node);
504 final String nodeName = node.getQName().getLocalName();
507 if (isConfig && uriType.equals(URIType.DRAFT02)) {
508 prefix = CONFIG + "_";
511 final String defName = parentName + prefix + nodeName + TOP + discriminator;
512 final ObjectNode get = buildGet(node, moduleName, deviceName, pathParams, defName, isConfig, uriType,
514 operations.put("get", get);
518 final ObjectNode put = buildPut(parentName, nodeName, discriminator, moduleName, deviceName,
519 node.getDescription().orElse(""), pathParams, oaversion);
520 operations.put("put", put);
522 final ObjectNode delete = buildDelete(node, moduleName, deviceName, pathParams, oaversion);
523 operations.put("delete", delete);
525 operations.put("post", buildPost(parentName, nodeName, discriminator, moduleName, deviceName,
526 node.getDescription().orElse(""), pathParams, oaversion));
531 protected abstract ListPathBuilder newListPathBuilder();
533 private String createPath(final DataSchemaNode schemaNode, final ArrayNode pathParams,
534 final EffectiveModelContext schemaContext, final OAversion oaversion) {
535 final StringBuilder path = new StringBuilder();
536 final String localName = resolvePathArgumentsName(schemaNode, schemaContext);
537 path.append(localName);
539 if (schemaNode instanceof ListSchemaNode) {
540 final ListPathBuilder keyBuilder = newListPathBuilder();
541 for (final QName listKey : ((ListSchemaNode) schemaNode).getKeyDefinition()) {
542 final String paramName = createUniquePathParamName(listKey.getLocalName(), pathParams);
543 final String pathParamIdentifier = keyBuilder.nextParamIdentifier(paramName);
545 path.append(pathParamIdentifier);
547 final ObjectNode pathParam = JsonNodeFactory.instance.objectNode();
548 pathParam.put("name", paramName);
550 ((DataNodeContainer) schemaNode).findDataChildByName(listKey).flatMap(DataSchemaNode::getDescription)
551 .ifPresent(desc -> pathParam.put("description", desc));
553 final ObjectNode typeParent = getTypeParentNode(pathParam, oaversion);
555 typeParent.put("type", "string");
556 pathParam.put("in", "path");
557 pathParam.put("required", true);
559 pathParams.add(pathParam);
562 return path.toString();
565 private String createUniquePathParamName(final String clearName, final ArrayNode pathParams) {
566 for (final JsonNode pathParam : pathParams) {
567 if (isNamePicked(clearName, pathParam)) {
568 return createUniquePathParamName(clearName, pathParams, 1);
574 private String createUniquePathParamName(final String clearName, final ArrayNode pathParams,
575 final int discriminator) {
576 final String newName = clearName + discriminator;
577 for (final JsonNode pathParam : pathParams) {
578 if (isNamePicked(newName, pathParam)) {
579 return createUniquePathParamName(clearName, pathParams, discriminator + 1);
585 private static boolean isNamePicked(final String name, final JsonNode pathParam) {
586 return name.equals(pathParam.get("name").asText());
589 public SortedSet<Module> getSortedModules(final EffectiveModelContext schemaContext) {
590 if (schemaContext == null) {
591 return Collections.emptySortedSet();
594 final SortedSet<Module> sortedModules = new TreeSet<>((module1, module2) -> {
595 int result = module1.getName().compareTo(module2.getName());
597 result = Revision.compare(module1.getRevision(), module2.getRevision());
600 result = module1.getNamespace().compareTo(module2.getNamespace());
604 for (final Module m : schemaContext.getModules()) {
606 sortedModules.add(m);
609 return sortedModules;
612 private static void addOperations(final OperationDefinition operDef, final String moduleName,
613 final Optional<String> deviceName, final ObjectNode paths, final String parentPath, final String parentName,
614 final DefinitionNames definitionNames, final EffectiveModelContext schemaContext,
615 final OAversion oaversion) {
616 final ObjectNode operations = JsonNodeFactory.instance.objectNode();
617 final String resourcePath = parentPath + "/" + resolvePathArgumentsName(operDef, schemaContext);
618 operations.set("post", buildPostOperation(operDef, moduleName, deviceName, parentName, definitionNames,
620 paths.set(resourcePath, operations);
623 protected abstract void appendPathKeyValue(StringBuilder builder, Object value);
625 public String generateUrlPrefixFromInstanceID(final YangInstanceIdentifier key, final String moduleName) {
626 final StringBuilder builder = new StringBuilder();
628 if (moduleName != null) {
629 builder.append(moduleName).append(':');
631 for (final PathArgument arg : key.getPathArguments()) {
632 final String name = arg.getNodeType().getLocalName();
633 if (arg instanceof NodeIdentifierWithPredicates) {
634 final NodeIdentifierWithPredicates nodeId = (NodeIdentifierWithPredicates) arg;
635 for (final Entry<QName, Object> entry : nodeId.entrySet()) {
636 appendPathKeyValue(builder, entry.getValue());
639 builder.append(name).append('/');
642 return builder.toString();
645 protected interface ListPathBuilder {
646 String nextParamIdentifier(String key);