<artifactId>mockito-all</artifactId>
<scope>test</scope>
</dependency>
+ <dependency>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>yang-data-api</artifactId>
+ </dependency>
</dependencies>
<build>
*/
package org.opendaylight.controller.sal.rest.doc.impl;
+import com.google.common.base.Preconditions;
import javax.ws.rs.core.UriInfo;
-
import org.opendaylight.controller.sal.core.api.model.SchemaService;
import org.opendaylight.controller.sal.rest.doc.swagger.ApiDeclaration;
import org.opendaylight.controller.sal.rest.doc.swagger.ResourceList;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import com.google.common.base.Preconditions;
-
/**
- * This class gathers all yang defined {@link Module}s and generates Swagger
- * compliant documentation.
+ * This class gathers all yang defined {@link Module}s and generates Swagger compliant documentation.
*/
public class ApiDocGenerator extends BaseYangSwaggerGenerator {
*/
package org.opendaylight.controller.sal.rest.doc.impl;
+import static org.opendaylight.controller.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.google.common.base.Preconditions;
import java.io.IOException;
import java.net.URI;
import java.text.DateFormat;
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.controller.sal.rest.doc.model.builder.OperationBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import com.fasterxml.jackson.databind.ObjectMapper;
-import com.fasterxml.jackson.databind.SerializationFeature;
-import com.fasterxml.jackson.datatype.jsonorg.JsonOrgModule;
-import com.google.common.base.Preconditions;
-
public class BaseYangSwaggerGenerator {
private static Logger _logger = LoggerFactory.getLogger(BaseYangSwaggerGenerator.class);
* @param operType
* @return list of modules converted to swagger compliant resource list.
*/
- public ResourceList getResourceListing(UriInfo uriInfo, SchemaContext schemaContext,
- String context) {
+ public ResourceList getResourceListing(UriInfo uriInfo, SchemaContext schemaContext, String context) {
ResourceList resourceList = createResourceList();
for (Module module : modules) {
String revisionString = SIMPLE_DATE_FORMAT.format(module.getRevision());
-
Resource resource = new Resource();
_logger.debug("Working on [{},{}]...", module.getName(), revisionString);
- ApiDeclaration doc = getApiDeclaration(module.getName(), revisionString, uriInfo,
- schemaContext, context);
+ ApiDeclaration doc = getApiDeclaration(module.getName(), revisionString, uriInfo, schemaContext, context);
if (doc != null) {
resource.setPath(generatePath(uriInfo, module.getName(), revisionString));
return uri.toASCIIString();
}
- public ApiDeclaration getApiDeclaration(String module, String revision, UriInfo uriInfo,
- SchemaContext schemaContext, String context) {
+ public ApiDeclaration getApiDeclaration(String module, String revision, UriInfo uriInfo, SchemaContext schemaContext, String context) {
Date rev = null;
try {
rev = SIMPLE_DATE_FORMAT.parse(revision);
throw new IllegalArgumentException(e);
}
Module m = schemaContext.findModuleByName(module, rev);
- Preconditions.checkArgument(m != null, "Could not find module by name,revision: " + module
- + "," + revision);
+ Preconditions.checkArgument(m != null, "Could not find module by name,revision: " + module + "," + revision);
- return getApiDeclaration(m, rev, uriInfo, schemaContext, context);
+ return getApiDeclaration(m, rev, uriInfo, context, schemaContext);
}
- public ApiDeclaration getApiDeclaration(Module module, Date revision, UriInfo uriInfo,
- SchemaContext schemaContext, String context) {
+ public ApiDeclaration getApiDeclaration(Module module, Date revision, UriInfo uriInfo, String context, SchemaContext schemaContext) {
String basePath = createBasePathFromUriInfo(uriInfo);
- ApiDeclaration doc = getSwaggerDocSpec(module, basePath, context);
+ ApiDeclaration doc = getSwaggerDocSpec(module, basePath, context, schemaContext);
if (doc != null) {
return doc;
}
portPart = ":" + port;
}
String basePath = new StringBuilder(uriInfo.getBaseUri().getScheme()).append("://")
- .append(uriInfo.getBaseUri().getHost()).append(portPart).append("/")
- .append(RESTCONF_CONTEXT_ROOT).toString();
+ .append(uriInfo.getBaseUri().getHost()).append(portPart).append("/").append(RESTCONF_CONTEXT_ROOT)
+ .toString();
return basePath;
}
- public ApiDeclaration getSwaggerDocSpec(Module m, String basePath, String context) {
+ public ApiDeclaration getSwaggerDocSpec(Module m, String basePath, String context, SchemaContext schemaContext) {
ApiDeclaration doc = createApiDeclaration(basePath);
List<Api> apis = new ArrayList<Api>();
for (DataSchemaNode node : dataSchemaNodes) {
if ((node instanceof ListSchemaNode) || (node instanceof ContainerSchemaNode)) {
- _logger.debug("Is Configuration node [{}] [{}]", node.isConfiguration(), node
- .getQName().getLocalName());
+ _logger.debug("Is Configuration node [{}] [{}]", node.isConfiguration(), node.getQName().getLocalName());
List<Parameter> pathParams = new ArrayList<Parameter>();
- String resourcePath = getDataStorePath("/config/", context) + m.getName() + ":";
- addApis(node, apis, resourcePath, pathParams, true);
+ String resourcePath = getDataStorePath("/config/", context);
+ addApis(node, apis, resourcePath, pathParams, schemaContext, true);
pathParams = new ArrayList<Parameter>();
- resourcePath = getDataStorePath("/operational/", context) + m.getName() + ":";
- addApis(node, apis, resourcePath, pathParams, false);
+ resourcePath = getDataStorePath("/operational/", context);
+ addApis(node, apis, resourcePath, pathParams, schemaContext, false);
}
Set<RpcDefinition> rpcs = m.getRpcs();
for (RpcDefinition rpcDefinition : rpcs) {
- String resourcePath = getDataStorePath("/operations/", context) + m.getName() + ":";
- addRpcs(rpcDefinition, apis, resourcePath);
+ String resourcePath = getDataStorePath("/operations/", context);
+ addRpcs(rpcDefinition, apis, resourcePath, schemaContext);
}
}
JSONObject models = null;
try {
- models = jsonConverter.convertToJsonSchema(m);
+ models = jsonConverter.convertToJsonSchema(m, schemaContext);
doc.setModels(models);
if (_logger.isDebugEnabled()) {
_logger.debug(mapper.writeValueAsString(doc));
return module + "(" + revision + ")";
}
- private void addApis(DataSchemaNode node, List<Api> apis, String parentPath,
- List<Parameter> parentPathParams, boolean addConfigApi) {
+ private void addApis(DataSchemaNode node, List<Api> apis, String parentPath, List<Parameter> parentPathParams, SchemaContext schemaContext,
+ boolean addConfigApi) {
Api api = new Api();
List<Parameter> pathParams = new ArrayList<Parameter>(parentPathParams);
- String resourcePath = parentPath + createPath(node, pathParams) + "/";
+ String resourcePath = parentPath + createPath(node, pathParams, schemaContext) + "/";
_logger.debug("Adding path: [{}]", resourcePath);
api.setPath(resourcePath);
api.setOperations(operations(node, pathParams, addConfigApi));
if (childNode instanceof ListSchemaNode || childNode instanceof ContainerSchemaNode) {
// keep config and operation attributes separate.
if (childNode.isConfiguration() == addConfigApi) {
- addApis(childNode, apis, resourcePath, pathParams, addConfigApi);
+ addApis(childNode, apis, resourcePath, pathParams, schemaContext, addConfigApi);
}
}
}
* @param pathParams
* @return
*/
- private List<Operation> operations(DataSchemaNode node, List<Parameter> pathParams,
- boolean isConfig) {
+ private List<Operation> operations(DataSchemaNode node, List<Parameter> pathParams, boolean isConfig) {
List<Operation> operations = new ArrayList<>();
OperationBuilder.Get getBuilder = new OperationBuilder.Get(node, isConfig);
return operations;
}
- private String createPath(final DataSchemaNode schemaNode, List<Parameter> pathParams) {
+ private String createPath(final DataSchemaNode schemaNode, List<Parameter> pathParams, SchemaContext schemaContext) {
ArrayList<LeafSchemaNode> pathListParams = new ArrayList<LeafSchemaNode>();
StringBuilder path = new StringBuilder();
- QName _qName = schemaNode.getQName();
- String localName = _qName.getLocalName();
+ 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);
- pathListParams.add(((LeafSchemaNode) _dataChildByName));
-
- String pathParamIdentifier = new StringBuilder("/{")
- .append(listKey.getLocalName()).append("}").toString();
- path.append(pathParamIdentifier);
-
- Parameter pathParam = new Parameter();
- pathParam.setName(listKey.getLocalName());
- pathParam.setDescription(_dataChildByName.getDescription());
- pathParam.setType("string");
- pathParam.setParamType("path");
-
- pathParams.add(pathParam);
- }
+ DataSchemaNode _dataChildByName = ((DataNodeContainer) schemaNode).getDataChildByName(listKey);
+ pathListParams.add(((LeafSchemaNode) _dataChildByName));
+
+ String pathParamIdentifier = new StringBuilder("/{").append(listKey.getLocalName()).append("}")
+ .toString();
+ path.append(pathParamIdentifier);
+
+ Parameter pathParam = new Parameter();
+ pathParam.setName(listKey.getLocalName());
+ pathParam.setDescription(_dataChildByName.getDescription());
+ pathParam.setType("string");
+ pathParam.setParamType("path");
+
+ pathParams.add(pathParam);
}
}
return path.toString();
}
- protected void addRpcs(RpcDefinition rpcDefn, List<Api> apis, String parentPath) {
+ protected void addRpcs(RpcDefinition rpcDefn, List<Api> apis, String parentPath, SchemaContext schemaContext) {
Api rpc = new Api();
- String resourcePath = parentPath + rpcDefn.getQName().getLocalName();
+ String resourcePath = parentPath + resolvePathArgumentsName(rpcDefn, schemaContext);
rpc.setPath(resourcePath);
Operation operationSpec = new Operation();
}
return sortedModules;
}
+
}
*/
package org.opendaylight.controller.sal.rest.doc.impl;
+import static org.opendaylight.controller.sal.rest.doc.util.RestDocgenUtil.resolveNodesName;
+
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import org.json.JSONException;
import org.json.JSONObject;
import org.opendaylight.controller.sal.rest.doc.model.builder.OperationBuilder;
+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.ChoiceNode;
import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
import org.opendaylight.yangtools.yang.model.api.Module;
import org.opendaylight.yangtools.yang.model.api.RpcDefinition;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
import org.opendaylight.yangtools.yang.model.api.type.BinaryTypeDefinition;
import org.opendaylight.yangtools.yang.model.api.type.BitsTypeDefinition;
private static final String NUMBER = "number";
private static final String BOOLEAN = "boolean";
private static final String STRING = "string";
- private static final String ID_KEY = "id";
- private static final String SUB_TYPES_KEY = "subTypes";
+ private static final String ID_KEY = "id";
+ private static final String SUB_TYPES_KEY = "subTypes";
private static final Map<Class<? extends TypeDefinition<?>>, String> YANG_TYPE_TO_JSON_TYPE_MAPPING;
YANG_TYPE_TO_JSON_TYPE_MAPPING = Collections.unmodifiableMap(tempMap1);
}
+ private Module topLevelModule;
+
public ModelGenerator() {
}
- public JSONObject convertToJsonSchema(Module module) throws IOException, JSONException {
+ public JSONObject convertToJsonSchema(Module module, SchemaContext schemaContext) throws IOException, JSONException {
JSONObject models = new JSONObject();
- processContainers(module, models);
- processRPCs(module, models);
- processIdentities(module, models);
+ topLevelModule = module;
+ processContainers(module, models, schemaContext);
+ processRPCs(module, models, schemaContext);
+ processIdentities(module, models);
return models;
}
- private void processContainers(Module module, JSONObject models) throws IOException,
+ private void processContainers(Module module, JSONObject models, SchemaContext schemaContext) throws IOException,
JSONException {
String moduleName = module.getName();
* For every container in the module
*/
if (childNode instanceof ContainerSchemaNode) {
- configModuleJSON = processContainer((ContainerSchemaNode) childNode, moduleName,
- true, models, true);
- operationalModuleJSON = processContainer((ContainerSchemaNode) childNode,
- moduleName, true, models, false);
+ configModuleJSON = processContainer((ContainerSchemaNode) childNode, moduleName, true, models, true,
+ schemaContext);
+ operationalModuleJSON = processContainer((ContainerSchemaNode) childNode, moduleName, true, models,
+ false, schemaContext);
}
if (configModuleJSON != null) {
}
/**
- * Process the RPCs for a Module Spits out a file each of the name
- * <rpcName>-input.json and <rpcName>-output.json for each RPC that contains
- * input & output elements
+ * Process the RPCs for a Module Spits out a file each of the name <rpcName>-input.json and <rpcName>-output.json
+ * for each RPC that contains input & output elements
*
* @param module
* @throws JSONException
* @throws IOException
*/
- private void processRPCs(Module module, JSONObject models) throws JSONException, IOException {
+ private void processRPCs(Module module, JSONObject models, SchemaContext schemaContext) throws JSONException,
+ IOException {
Set<RpcDefinition> rpcs = module.getRpcs();
String moduleName = module.getName();
ContainerSchemaNode input = rpc.getInput();
if (input != null) {
- JSONObject inputJSON = processContainer(input, moduleName, true, models);
+ JSONObject inputJSON = processContainer(input, moduleName, true, models, schemaContext);
String filename = "(" + rpc.getQName().getLocalName() + ")input";
inputJSON.put("id", filename);
// writeToFile(filename, inputJSON.toString(2), moduleName);
ContainerSchemaNode output = rpc.getOutput();
if (output != null) {
- JSONObject outputJSON = processContainer(output, moduleName, true, models);
+ JSONObject outputJSON = processContainer(output, moduleName, true, models, schemaContext);
String filename = "(" + rpc.getQName().getLocalName() + ")output";
outputJSON.put("id", filename);
models.put(filename, outputJSON);
}
}
- /**
- * Processes the 'identity' statement in a yang model
- * and maps it to a 'model' in the Swagger JSON spec.
- *
- * @param module The module from which the identity stmt will be processed
- * @param models The JSONObject in which the parsed identity will be put as a 'model' obj
- * @throws JSONException
- */
- private void processIdentities(Module module, JSONObject models) throws JSONException {
-
- String moduleName = module.getName();
- Set<IdentitySchemaNode> idNodes = module.getIdentities();
- _logger.debug("Processing Identities for module {} . Found {} identity statements", moduleName, idNodes.size());
-
- for(IdentitySchemaNode idNode : idNodes){
- JSONObject identityObj=new JSONObject();
- String identityName = idNode.getQName().getLocalName();
- _logger.debug("Processing Identity: {}", identityName);
-
- identityObj.put(ID_KEY, identityName);
- identityObj.put(DESCRIPTION_KEY, idNode.getDescription());
-
- JSONObject props = new JSONObject();
- IdentitySchemaNode baseId = idNode.getBaseIdentity();
+ /**
+ * Processes the 'identity' statement in a yang model and maps it to a 'model' in the Swagger JSON spec.
+ *
+ * @param module
+ * The module from which the identity stmt will be processed
+ * @param models
+ * The JSONObject in which the parsed identity will be put as a 'model' obj
+ * @throws JSONException
+ */
+ private void processIdentities(Module module, JSONObject models) throws JSONException {
+ String moduleName = module.getName();
+ Set<IdentitySchemaNode> idNodes = module.getIdentities();
+ _logger.debug("Processing Identities for module {} . Found {} identity statements", moduleName, idNodes.size());
+
+ for (IdentitySchemaNode idNode : idNodes) {
+ JSONObject identityObj = new JSONObject();
+ String identityName = idNode.getQName().getLocalName();
+ _logger.debug("Processing Identity: {}", identityName);
+
+ identityObj.put(ID_KEY, identityName);
+ identityObj.put(DESCRIPTION_KEY, idNode.getDescription());
+
+ JSONObject props = new JSONObject();
+ 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();
+
+ if (derivedIds != null) {
+ JSONArray subTypes = new JSONArray();
+ for (IdentitySchemaNode derivedId : derivedIds) {
+ subTypes.put(derivedId.getQName().getLocalName());
+ }
+ identityObj.put(SUB_TYPES_KEY, subTypes);
+ }
+ } else {
+ /**
+ * This is a derived entity. Add it's base type & move on.
+ */
+ props.put(TYPE_KEY, baseId.getQName().getLocalName());
+ }
- 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();
-
- if(derivedIds != null) {
- JSONArray subTypes = new JSONArray();
- for(IdentitySchemaNode derivedId : derivedIds){
- subTypes.put(derivedId.getQName().getLocalName());
- }
- identityObj.put(SUB_TYPES_KEY, subTypes);
+ // Add the properties. For a base type, this will be an empty object as required by the Swagger spec.
+ identityObj.put(PROPERTIES_KEY, props);
+ models.put(identityName, identityObj);
}
- } else {
- /**
- * This is a derived entity. Add it's base type & move on.
- */
- props.put(TYPE_KEY, baseId.getQName().getLocalName());
- }
-
- //Add the properties. For a base type, this will be an empty object as required by the Swagger spec.
- identityObj.put(PROPERTIES_KEY, props);
- models.put(identityName, identityObj);
}
- }
+
/**
* Processes the container node and populates the moduleJSON
*
* @throws JSONException
* @throws IOException
*/
- private JSONObject processContainer(ContainerSchemaNode container, String moduleName,
- boolean addSchemaStmt, JSONObject models) throws JSONException, IOException {
- return processContainer(container, moduleName, addSchemaStmt, models, (Boolean) null);
+ private JSONObject processContainer(ContainerSchemaNode container, String moduleName, boolean addSchemaStmt,
+ JSONObject models, SchemaContext schemaContext) throws JSONException, IOException {
+ return processContainer(container, moduleName, addSchemaStmt, models, (Boolean) null, schemaContext);
}
- private JSONObject processContainer(ContainerSchemaNode container, String moduleName,
- boolean addSchemaStmt, JSONObject models, Boolean isConfig) throws JSONException,
- IOException {
+ private JSONObject processContainer(ContainerSchemaNode container, String moduleName, boolean addSchemaStmt,
+ JSONObject models, Boolean isConfig, SchemaContext schemaContext) throws JSONException, IOException {
JSONObject moduleJSON = getSchemaTemplate();
if (addSchemaStmt) {
moduleJSON = getSchemaTemplate();
String containerDescription = container.getDescription();
moduleJSON.put(DESCRIPTION_KEY, containerDescription);
- JSONObject properties = processChildren(container.getChildNodes(), moduleName, models, isConfig);
+ JSONObject properties = processChildren(container.getChildNodes(), container.getQName(), moduleName, models,
+ isConfig, schemaContext);
moduleJSON.put(PROPERTIES_KEY, properties);
return moduleJSON;
}
- private JSONObject processChildren(Iterable<DataSchemaNode> nodes, String moduleName,
- JSONObject models) throws JSONException, IOException {
- return processChildren(nodes, moduleName, models, null);
+ private JSONObject processChildren(Iterable<DataSchemaNode> nodes, QName parentQName, String moduleName,
+ JSONObject models, SchemaContext schemaContext) throws JSONException, IOException {
+ return processChildren(nodes, parentQName, moduleName, models, null, schemaContext);
}
/**
* Processes the nodes
*
* @param nodes
+ * @param parentQName
* @param moduleName
* @param isConfig
* @return
* @throws JSONException
* @throws IOException
*/
- private JSONObject processChildren(Iterable<DataSchemaNode> nodes, String moduleName,
- JSONObject models, Boolean isConfig) throws JSONException, IOException {
+ private JSONObject processChildren(Iterable<DataSchemaNode> nodes, QName parentQName, String moduleName,
+ JSONObject models, Boolean isConfig, SchemaContext schemaContext) throws JSONException, IOException {
JSONObject properties = new JSONObject();
for (DataSchemaNode node : nodes) {
if (isConfig == null || node.isConfiguration() == isConfig) {
- String name = node.getQName().getLocalName();
+ String name = resolveNodesName(node, topLevelModule, schemaContext);
JSONObject property = null;
if (node instanceof LeafSchemaNode) {
property = processLeafNode((LeafSchemaNode) node);
} else if (node instanceof ListSchemaNode) {
- property = processListSchemaNode((ListSchemaNode) node, moduleName, models, isConfig);
+ property = processListSchemaNode((ListSchemaNode) node, moduleName, models, isConfig, schemaContext);
} else if (node instanceof LeafListSchemaNode) {
property = processLeafListNode((LeafListSchemaNode) node);
} else if (node instanceof ChoiceNode) {
- property = processChoiceNode((ChoiceNode) node, moduleName, models);
+ property = processChoiceNode((ChoiceNode) node, moduleName, models, schemaContext);
} else if (node instanceof AnyXmlSchemaNode) {
property = processAnyXMLNode((AnyXmlSchemaNode) node);
} else if (node instanceof ContainerSchemaNode) {
- property = processContainer((ContainerSchemaNode) node, moduleName, false,
- models, isConfig);
+ property = processContainer((ContainerSchemaNode) node, moduleName, false, models, isConfig,
+ schemaContext);
} else {
- throw new IllegalArgumentException("Unknown DataSchemaNode type: "
- + node.getClass());
+ throw new IllegalArgumentException("Unknown DataSchemaNode type: " + node.getClass());
}
property.putOpt(DESCRIPTION_KEY, node.getDescription());
* @throws JSONException
* @throws IOException
*/
- private JSONObject processChoiceNode(ChoiceNode choiceNode, String moduleName, JSONObject models)
- throws JSONException, IOException {
+ private JSONObject processChoiceNode(ChoiceNode choiceNode, String moduleName, JSONObject models,
+ SchemaContext schemaContext) throws JSONException, IOException {
Set<ChoiceCaseNode> cases = choiceNode.getCases();
JSONArray choiceProps = new JSONArray();
for (ChoiceCaseNode choiceCase : cases) {
String choiceName = choiceCase.getQName().getLocalName();
- JSONObject choiceProp = processChildren(choiceCase.getChildNodes(), moduleName, models);
+ JSONObject choiceProp = processChildren(choiceCase.getChildNodes(), choiceCase.getQName(), moduleName,
+ models, schemaContext);
JSONObject choiceObj = new JSONObject();
choiceObj.put(choiceName, choiceProp);
choiceObj.put(TYPE_KEY, OBJECT_TYPE);
* @param props
* @throws JSONException
*/
- private void processConstraints(ConstraintDefinition constraints, JSONObject props)
- throws JSONException {
+ private void processConstraints(ConstraintDefinition constraints, JSONObject props) throws JSONException {
boolean isMandatory = constraints.isMandatory();
props.put(REQUIRED_KEY, isMandatory);
/**
* Parses a ListSchema node.
*
- * Due to a limitation of the RAML--->JAX-RS tool, sub-properties must be in
- * a separate JSON schema file. Hence, we have to write some properties to a
- * new file, while continuing to process the rest.
+ * Due to a limitation of the RAML--->JAX-RS tool, sub-properties must be in a separate JSON schema file. Hence, we
+ * have to write some properties to a new file, while continuing to process the rest.
*
* @param listNode
* @param moduleName
* @throws JSONException
* @throws IOException
*/
- private JSONObject processListSchemaNode(ListSchemaNode listNode, String moduleName,
- JSONObject models, Boolean isConfig) throws JSONException, IOException {
+ private JSONObject processListSchemaNode(ListSchemaNode listNode, String moduleName, JSONObject models,
+ Boolean isConfig, SchemaContext schemaContext) throws JSONException, IOException {
- String fileName = (BooleanUtils.isNotFalse(isConfig)?OperationBuilder.CONFIG:OperationBuilder.OPERATIONAL) +
- listNode.getQName().getLocalName();
+ String fileName = (BooleanUtils.isNotFalse(isConfig) ? OperationBuilder.CONFIG : OperationBuilder.OPERATIONAL)
+ + listNode.getQName().getLocalName();
- JSONObject childSchemaProperties = processChildren(listNode.getChildNodes(), moduleName, models);
+ JSONObject childSchemaProperties = processChildren(listNode.getChildNodes(), listNode.getQName(), moduleName,
+ models, schemaContext);
JSONObject childSchema = getSchemaTemplate();
childSchema.put(TYPE_KEY, OBJECT_TYPE);
childSchema.put(PROPERTIES_KEY, childSchemaProperties);
/*
- * Due to a limitation of the RAML--->JAX-RS tool, sub-properties must
- * be in a separate JSON schema file. Hence, we have to write some
- * properties to a new file, while continuing to process the rest.
+ * Due to a limitation of the RAML--->JAX-RS tool, sub-properties must be in a separate JSON schema file. Hence,
+ * we have to write some properties to a new file, while continuing to process the rest.
*/
// writeToFile(fileName, childSchema.toString(2), moduleName);
childSchema.put("id", fileName);
* @param property
* @throws JSONException
*/
- private void processTypeDef(TypeDefinition<?> leafTypeDef, JSONObject property)
- throws JSONException {
+ private void processTypeDef(TypeDefinition<?> leafTypeDef, JSONObject property) throws JSONException {
if (leafTypeDef instanceof ExtendedType) {
processExtendedType(leafTypeDef, property);
processUnionType((UnionTypeDefinition) leafTypeDef, property);
} else if (leafTypeDef instanceof IdentityrefTypeDefinition) {
- property.putOpt(TYPE_KEY, ((IdentityrefTypeDefinition) leafTypeDef).getIdentity().getQName().getLocalName());
+ property.putOpt(TYPE_KEY, ((IdentityrefTypeDefinition) leafTypeDef).getIdentity().getQName().getLocalName());
} else if (leafTypeDef instanceof BinaryTypeDefinition) {
processBinaryType((BinaryTypeDefinition) leafTypeDef, property);
} else {
* @param property
* @throws JSONException
*/
- private void processExtendedType(TypeDefinition<?> leafTypeDef, JSONObject property)
- throws JSONException {
+ private void processExtendedType(TypeDefinition<?> leafTypeDef, JSONObject property) throws JSONException {
Object leafBaseType = leafTypeDef.getBaseType();
if (leafBaseType instanceof ExtendedType) {
// recursively process an extended type until we hit a base type
processExtendedType((TypeDefinition<?>) leafBaseType, property);
} else {
- List<LengthConstraint> lengthConstraints = ((ExtendedType) leafTypeDef)
- .getLengthConstraints();
+ List<LengthConstraint> lengthConstraints = ((ExtendedType) leafTypeDef).getLengthConstraints();
for (LengthConstraint lengthConstraint : lengthConstraints) {
Number min = lengthConstraint.getMin();
Number max = lengthConstraint.getMax();
/*
*
*/
- private void processBinaryType(BinaryTypeDefinition binaryType, JSONObject property)
- throws JSONException {
+ private void processBinaryType(BinaryTypeDefinition binaryType, JSONObject property) throws JSONException {
property.put(TYPE_KEY, STRING);
JSONObject media = new JSONObject();
media.put(BINARY_ENCODING_KEY, BASE_64);
* @param property
* @throws JSONException
*/
- private void processEnumType(EnumerationType enumLeafType, JSONObject property)
- throws JSONException {
+ private void processEnumType(EnumerationType enumLeafType, JSONObject property) throws JSONException {
List<EnumPair> enumPairs = enumLeafType.getValues();
List<String> enumNames = new ArrayList<String>();
for (EnumPair enumPair : enumPairs) {
* @param property
* @throws JSONException
*/
- private void processBitsType(BitsTypeDefinition bitsType, JSONObject property)
- throws JSONException {
+ private void processBitsType(BitsTypeDefinition bitsType, JSONObject property) throws JSONException {
property.put(TYPE_KEY, ARRAY_TYPE);
property.put(MIN_ITEMS, 0);
property.put(UNIQUE_ITEMS_KEY, true);
* @param property
* @throws JSONException
*/
- private void processUnionType(UnionTypeDefinition unionType, JSONObject property)
- throws JSONException {
+ private void processUnionType(UnionTypeDefinition unionType, JSONObject property) throws JSONException {
StringBuilder type = new StringBuilder();
- for (TypeDefinition<?> typeDef : unionType.getTypes() ) {
- if( type.length() > 0 ){
- type.append( " or " );
+ for (TypeDefinition<?> typeDef : unionType.getTypes()) {
+ if (type.length() > 0) {
+ type.append(" or ");
}
type.append(YANG_TYPE_TO_JSON_TYPE_MAPPING.get(typeDef.getClass()));
}
- property.put(TYPE_KEY, type );
+ property.put(TYPE_KEY, type);
}
/**
return schemaJSON;
}
+
}
import java.util.TreeMap;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.AtomicReference;
-
import javax.ws.rs.core.UriInfo;
-
import org.opendaylight.controller.sal.core.api.model.SchemaService;
import org.opendaylight.controller.sal.core.api.mount.MountProvisionInstance;
import org.opendaylight.controller.sal.core.api.mount.MountProvisionService;
--- /dev/null
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.rest.doc.util;
+
+import java.net.URI;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.model.api.Module;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.model.api.SchemaNode;
+
+public class RestDocgenUtil {
+
+ private RestDocgenUtil() {
+ }
+
+ private static Map<URI, Map<Date, Module>> namespaceAndRevisionToModule = new HashMap<URI, Map<Date, Module>>();
+
+ /**
+ * Resolve path argument name for {@code node}.
+ *
+ * The name can contain also prefix which consists of module name followed by colon. The module prefix is presented
+ * if namespace of {@code node} and its parent is different. In other cases only name of {@code node} is returned.
+ *
+ * @return name of {@code node}
+ */
+ public static String resolvePathArgumentsName(final SchemaNode node, final SchemaContext schemaContext) {
+ Iterable<QName> schemaPath = node.getPath().getPathTowardsRoot();
+ Iterator<QName> it = schemaPath.iterator();
+ QName nodeQName = it.next();
+
+ QName parentQName = null;
+ if (it.hasNext()) {
+ parentQName = it.next();
+ }
+ if (isEqualNamespaceAndRevision(parentQName, nodeQName)) {
+ return node.getQName().getLocalName();
+ } else {
+ return resolveFullNameFromNode(node, schemaContext);
+ }
+ }
+
+ private synchronized static String resolveFullNameFromNode(final SchemaNode node, final SchemaContext schemaContext) {
+ final URI namespace = node.getQName().getNamespace();
+ final Date revision = node.getQName().getRevision();
+
+ Map<Date, Module> revisionToModule = namespaceAndRevisionToModule.get(namespace);
+ if (revisionToModule == null) {
+ revisionToModule = new HashMap<>();
+ namespaceAndRevisionToModule.put(namespace, revisionToModule);
+ }
+ Module module = revisionToModule.get(revision);
+ if (module == null) {
+ module = schemaContext.findModuleByNamespaceAndRevision(namespace, revision);
+ revisionToModule.put(revision, module);
+ }
+ if (module != null) {
+ return module.getName() + ":" + node.getQName().getLocalName();
+ }
+ return node.getQName().getLocalName();
+ }
+
+ public static String resolveNodesName(final SchemaNode node, final Module module, final SchemaContext schemaContext) {
+ if (node.getQName().getNamespace().equals(module.getQNameModule().getNamespace())
+ && node.getQName().getRevision().equals(module.getQNameModule().getRevision())) {
+ return node.getQName().getLocalName();
+ } else {
+ return resolveFullNameFromNode(node, schemaContext);
+ }
+ }
+
+ private static boolean isEqualNamespaceAndRevision(QName parentQName, QName nodeQName) {
+ if (parentQName == null) {
+ if (nodeQName == null) {
+ return true;
+ }
+ return false;
+ }
+ return parentQName.getNamespace().equals(nodeQName.getNamespace())
+ && parentQName.getRevision().equals(nodeQName.getRevision());
+ }
+}
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
+import com.google.common.base.Preconditions;
import java.io.File;
import java.util.Arrays;
+import java.util.HashSet;
import java.util.Map.Entry;
import java.util.Set;
import java.util.TreeSet;
-
import javax.ws.rs.core.UriInfo;
-
import junit.framework.Assert;
-
+import org.json.JSONException;
+import org.json.JSONObject;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.opendaylight.controller.sal.rest.doc.swagger.Resource;
import org.opendaylight.controller.sal.rest.doc.swagger.ResourceList;
import org.opendaylight.yangtools.yang.model.api.Module;
-
-import com.google.common.base.Preconditions;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.parser.impl.YangParserImpl;
/**
*
public static final String HTTP_HOST = "http://host";
private ApiDocGenerator generator;
private DocGenTestHelper helper;
+ private SchemaContext schemaContext;
@Before
public void setUp() throws Exception {
generator = new ApiDocGenerator();
helper = new DocGenTestHelper();
helper.setUp();
+ schemaContext = new YangParserImpl().resolveSchemaContext(new HashSet<Module>(helper.getModules().values()));
}
@After
for (Entry<File, Module> m : helper.getModules().entrySet()) {
if (m.getKey().getAbsolutePath().endsWith("toaster_short.yang")) {
ApiDeclaration doc = generator.getSwaggerDocSpec(m.getValue(),
- "http://localhost:8080/restconf", "");
+ "http://localhost:8080/restconf", "",schemaContext);
validateToaster(doc);
+ validateTosterDocContainsModulePrefixes(doc);
Assert.assertNotNull(doc);
}
}
for (Entry<File, Module> m : helper.getModules().entrySet()) {
if (m.getKey().getAbsolutePath().endsWith("toaster.yang")) {
ApiDeclaration doc = generator.getSwaggerDocSpec(m.getValue(),
- "http://localhost:8080/restconf", "");
+ "http://localhost:8080/restconf", "",schemaContext);
Assert.assertNotNull(doc);
//testing bugs.opendaylight.org bug 1290. UnionType model type.
}
}
+ /**
+ * Tests whether from yang files are generated all required paths for HTTP operations (GET, DELETE, PUT, POST)
+ *
+ * If container | list is augmented then in path there should be specified module name followed with collon (e. g.
+ * "/config/module1:element1/element2/module2:element3")
+ *
+ * @param doc
+ * @throws Exception
+ */
private void validateToaster(ApiDeclaration doc) throws Exception {
Set<String> expectedUrls = new TreeSet<>(Arrays.asList(new String[] {
"/config/toaster2:toaster/", "/operational/toaster2:toaster/",
"/operations/toaster2:cancel-toast", "/operations/toaster2:make-toast",
- "/operations/toaster2:restock-toaster" }));
+ "/operations/toaster2:restock-toaster",
+ "/config/toaster2:toaster/toasterSlot/{slotId}/toaster-augmented:slotInfo/" }));
Set<String> actualUrls = new TreeSet<>();
@Test
public void testGetResourceListing() throws Exception {
UriInfo info = helper.createMockUriInfo(HTTP_HOST);
- SchemaService mockSchemaService = helper.createMockSchemaService();
+ SchemaService mockSchemaService = helper.createMockSchemaService(schemaContext);
generator.setSchemaService(mockSchemaService);
assertEquals(HTTP_HOST + "/toaster2(2009-11-20)", toaster2.getPath());
}
+ private void validateTosterDocContainsModulePrefixes(ApiDeclaration doc) {
+ JSONObject topLevelJson = doc.getModels();
+ try {
+ JSONObject configToaster = topLevelJson.getJSONObject("(config)toaster");
+ assertNotNull("(config)toaster JSON object missing", configToaster);
+ //without module prefix
+ containsProperties(configToaster, "toasterSlot");
+
+ JSONObject toasterSlot = topLevelJson.getJSONObject("(config)toasterSlot");
+ assertNotNull("(config)toasterSlot JSON object missing", toasterSlot);
+ //with module prefix
+ containsProperties(toasterSlot, "toaster-augmented:slotInfo");
+
+ } catch (JSONException e) {
+ fail("Json exception while reading JSON object. Original message "+e.getMessage());
+ }
+ }
+
+ private void containsProperties(final JSONObject jsonObject,final String...properties) throws JSONException {
+ for (String property : properties) {
+ JSONObject propertiesObject = jsonObject.getJSONObject("properties");
+ assertNotNull("Properties object missing in ", propertiesObject);
+ JSONObject concretePropertyObject = propertiesObject.getJSONObject(property);
+ assertNotNull(property + " is missing",concretePropertyObject);
+ }
+ }
}
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.SerializationFeature;
+import com.fasterxml.jackson.datatype.jsonorg.JsonOrgModule;
import java.io.File;
import java.io.FileNotFoundException;
import java.net.URI;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
-
import javax.ws.rs.core.UriBuilder;
import javax.ws.rs.core.UriInfo;
-
import org.mockito.ArgumentCaptor;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import org.opendaylight.controller.sal.core.api.model.SchemaService;
import org.opendaylight.yangtools.yang.model.api.Module;
import org.opendaylight.yangtools.yang.model.api.SchemaContext;
-import org.opendaylight.yangtools.yang.model.parser.api.YangModelParser;
+import org.opendaylight.yangtools.yang.model.parser.api.YangContextParser;
import org.opendaylight.yangtools.yang.parser.impl.YangParserImpl;
-import com.fasterxml.jackson.databind.ObjectMapper;
-import com.fasterxml.jackson.databind.SerializationFeature;
-import com.fasterxml.jackson.datatype.jsonorg.JsonOrgModule;
-
public class DocGenTestHelper {
private Map<File, Module> modules;
URISyntaxException {
URI resourceDirUri = getClass().getResource(resourceDirectory).toURI();
- final YangModelParser parser = new YangParserImpl();
+ final YangContextParser parser = new YangParserImpl();
final File testDir = new File(resourceDirUri);
final String[] fileList = testDir.list();
final List<File> testFiles = new ArrayList<>();
final ArgumentCaptor<String> moduleCapture = ArgumentCaptor.forClass(String.class);
final ArgumentCaptor<Date> dateCapture = ArgumentCaptor.forClass(Date.class);
+ final ArgumentCaptor<URI> namespaceCapture = ArgumentCaptor.forClass(URI.class);
when(mockContext.findModuleByName(moduleCapture.capture(), dateCapture.capture())).then(
new Answer<Module>() {
@Override
return null;
}
});
+ when(mockContext.findModuleByNamespaceAndRevision(namespaceCapture.capture(), dateCapture.capture())).then(
+ new Answer<Module>() {
+ @Override
+ public Module answer(InvocationOnMock invocation) throws Throwable {
+ URI namespace = namespaceCapture.getValue();
+ Date date = dateCapture.getValue();
+ for (Module m : modules.values()) {
+ if (m.getNamespace().equals(namespace) && m.getRevision().equals(date)) {
+ return m;
+ }
+ }
+ return null;
+ }
+ });
return mockContext;
}
import java.net.URISyntaxException;
import java.util.Arrays;
+import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;
-
import javax.ws.rs.core.UriInfo;
-
import org.junit.Before;
import org.junit.Test;
import org.opendaylight.controller.sal.core.api.model.SchemaService;
import org.opendaylight.controller.sal.rest.doc.swagger.ResourceList;
import org.opendaylight.yangtools.yang.common.QName;
import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.model.api.Module;
import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.parser.impl.YangParserImpl;
public class MountPointSwaggerTest {
private static final String INSTANCE_URL = "nodes/node/123/";
private MountPointSwagger swagger;
private DocGenTestHelper helper;
+ private SchemaContext schemaContext;
@Before
public void setUp() throws Exception {
swagger = new MountPointSwagger();
helper = new DocGenTestHelper();
helper.setUp();
+ schemaContext = new YangParserImpl().resolveSchemaContext(new HashSet<Module>(helper.getModules().values()));
}
@Test()
--- /dev/null
+module toaster-augmented {
+
+ yang-version 1;
+
+ namespace
+ "http://netconfcentral.org/ns/toaster/augmented";
+
+ prefix toast;
+ import toaster2 {prefix tst; revision-date 2009-11-20;}
+
+ revision "2014-7-14" {
+ }
+
+ augment "/tst:toaster/tst:toasterSlot" {
+ container slotInfo {
+ leaf numberOfToastPrepared {
+ type uint32;
+ }
+ }
+ }
+}
\ No newline at end of file
Microsoft Toaster.";
}
+ list toasterSlot {
+ key "slotId";
+ leaf slotId {
+ type string;
+ }
+ }
+
leaf toasterModelNumber {
type DisplayString;
config false;