X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=blobdiff_plain;f=opendaylight%2Fmd-sal%2Fsal-rest-docgen%2Fsrc%2Fmain%2Fjava%2Forg%2Fopendaylight%2Fcontroller%2Fsal%2Frest%2Fdoc%2Fimpl%2FModelGenerator.java;h=93daf05b50c03d853f938f0ea30fe3efc2fa54a6;hb=c945136babc8d57a5238e007197e7b053c77e53e;hp=819892f6477b2994e53c927cf1ab3a8dd2c2b545;hpb=3471ea2c8462ea99043263563903ce7091ad8432;p=controller.git diff --git a/opendaylight/md-sal/sal-rest-docgen/src/main/java/org/opendaylight/controller/sal/rest/doc/impl/ModelGenerator.java b/opendaylight/md-sal/sal-rest-docgen/src/main/java/org/opendaylight/controller/sal/rest/doc/impl/ModelGenerator.java index 819892f647..93daf05b50 100644 --- a/opendaylight/md-sal/sal-rest-docgen/src/main/java/org/opendaylight/controller/sal/rest/doc/impl/ModelGenerator.java +++ b/opendaylight/md-sal/sal-rest-docgen/src/main/java/org/opendaylight/controller/sal/rest/doc/impl/ModelGenerator.java @@ -7,15 +7,18 @@ */ package org.opendaylight.controller.sal.rest.doc.impl; +import static org.opendaylight.controller.sal.rest.doc.impl.BaseYangSwaggerGenerator.MODULE_NAME_SUFFIX; +import static org.opendaylight.controller.sal.rest.doc.model.builder.OperationBuilder.Post.METHOD_NAME; import static org.opendaylight.controller.sal.rest.doc.util.RestDocgenUtil.resolveNodesName; - +import com.google.common.base.Preconditions; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableMap.Builder; import java.io.IOException; import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; +import javax.annotation.concurrent.NotThreadSafe; import org.apache.commons.lang3.BooleanUtils; import org.json.JSONArray; import org.json.JSONException; @@ -24,9 +27,10 @@ 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.ChoiceSchemaNode; import org.opendaylight.yangtools.yang.model.api.ConstraintDefinition; import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode; +import org.opendaylight.yangtools.yang.model.api.DataNodeContainer; import org.opendaylight.yangtools.yang.model.api.DataSchemaNode; import org.opendaylight.yangtools.yang.model.api.IdentitySchemaNode; import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode; @@ -35,6 +39,7 @@ 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.SchemaNode; 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; @@ -62,9 +67,10 @@ import org.slf4j.LoggerFactory; /** * Generates JSON Schema for data defined in Yang */ +@NotThreadSafe public class ModelGenerator { - private static Logger _logger = LoggerFactory.getLogger(ModelGenerator.class); + private static final Logger LOG = LoggerFactory.getLogger(ModelGenerator.class); private static final String BASE_64 = "base64"; private static final String BINARY_ENCODING_KEY = "binaryEncoding"; @@ -93,26 +99,26 @@ public class ModelGenerator { private static final String ID_KEY = "id"; private static final String SUB_TYPES_KEY = "subTypes"; - private static final Map>, String> YANG_TYPE_TO_JSON_TYPE_MAPPING; + private static final Map, String> YANG_TYPE_TO_JSON_TYPE_MAPPING; static { - Map>, String> tempMap1 = new HashMap>, String>( - 10); - tempMap1.put(StringType.class, STRING); - tempMap1.put(BooleanType.class, BOOLEAN); - tempMap1.put(Int8.class, INTEGER); - tempMap1.put(Int16.class, INTEGER); - tempMap1.put(Int32.class, INTEGER); - tempMap1.put(Int64.class, INTEGER); - tempMap1.put(Uint16.class, INTEGER); - tempMap1.put(Uint32.class, INTEGER); - tempMap1.put(Uint64.class, INTEGER); - tempMap1.put(Uint8.class, INTEGER); - tempMap1.put(Decimal64.class, NUMBER); - tempMap1.put(EnumerationType.class, ENUM); + final Builder, String> b = ImmutableMap.builder(); + + b.put(StringType.class, STRING); + b.put(BooleanType.class, BOOLEAN); + b.put(Int8.class, INTEGER); + b.put(Int16.class, INTEGER); + b.put(Int32.class, INTEGER); + b.put(Int64.class, INTEGER); + b.put(Uint16.class, INTEGER); + b.put(Uint32.class, INTEGER); + b.put(Uint64.class, INTEGER); + b.put(Uint8.class, INTEGER); + b.put(Decimal64.class, NUMBER); + b.put(EnumerationType.class, ENUM); // TODO: Binary type - YANG_TYPE_TO_JSON_TYPE_MAPPING = Collections.unmodifiableMap(tempMap1); + YANG_TYPE_TO_JSON_TYPE_MAPPING = b.build(); } private Module topLevelModule; @@ -120,44 +126,30 @@ public class ModelGenerator { public ModelGenerator() { } - public JSONObject convertToJsonSchema(Module module, SchemaContext schemaContext) throws IOException, JSONException { + public JSONObject convertToJsonSchema(final Module module, final SchemaContext schemaContext) throws IOException, JSONException { JSONObject models = new JSONObject(); topLevelModule = module; - processContainers(module, models, schemaContext); + processModules(module, models); + processContainersAndLists(module, models, schemaContext); processRPCs(module, models, schemaContext); processIdentities(module, models); return models; } - private void processContainers(Module module, JSONObject models, SchemaContext schemaContext) throws IOException, - JSONException { + private void processModules(final Module module, final JSONObject models) throws JSONException { + createConcreteModelForPost(models, module.getName()+MODULE_NAME_SUFFIX, createPropertiesForPost(module)); + } + + private void processContainersAndLists(final Module module, final JSONObject models, final SchemaContext schemaContext) + throws IOException, JSONException { String moduleName = module.getName(); for (DataSchemaNode childNode : module.getChildNodes()) { - JSONObject configModuleJSON = null; - JSONObject operationalModuleJSON = null; - - String childNodeName = childNode.getQName().getLocalName(); - /* - * For every container in the module - */ - if (childNode instanceof ContainerSchemaNode) { - configModuleJSON = processContainer((ContainerSchemaNode) childNode, moduleName, true, models, true, - schemaContext); - operationalModuleJSON = processContainer((ContainerSchemaNode) childNode, moduleName, true, models, - false, schemaContext); - } - - if (configModuleJSON != null) { - _logger.debug("Adding model for [{}]", OperationBuilder.CONFIG + childNodeName); - configModuleJSON.put("id", OperationBuilder.CONFIG + childNodeName); - models.put(OperationBuilder.CONFIG + childNodeName, configModuleJSON); - } - if (operationalModuleJSON != null) { - _logger.debug("Adding model for [{}]", OperationBuilder.OPERATIONAL + childNodeName); - operationalModuleJSON.put("id", OperationBuilder.OPERATIONAL + childNodeName); - models.put(OperationBuilder.OPERATIONAL + childNodeName, operationalModuleJSON); + // For every container and list in the module + if (childNode instanceof ContainerSchemaNode || childNode instanceof ListSchemaNode) { + processDataNodeContainer((DataNodeContainer) childNode, moduleName, models, true, schemaContext); + processDataNodeContainer((DataNodeContainer) childNode, moduleName, models, false, schemaContext); } } @@ -171,7 +163,7 @@ public class ModelGenerator { * @throws JSONException * @throws IOException */ - private void processRPCs(Module module, JSONObject models, SchemaContext schemaContext) throws JSONException, + private void processRPCs(final Module module, final JSONObject models, final SchemaContext schemaContext) throws JSONException, IOException { Set rpcs = module.getRpcs(); @@ -180,7 +172,7 @@ public class ModelGenerator { ContainerSchemaNode input = rpc.getInput(); if (input != null) { - JSONObject inputJSON = processContainer(input, moduleName, true, models, schemaContext); + JSONObject inputJSON = processDataNodeContainer(input, moduleName, models, schemaContext); String filename = "(" + rpc.getQName().getLocalName() + ")input"; inputJSON.put("id", filename); // writeToFile(filename, inputJSON.toString(2), moduleName); @@ -189,7 +181,7 @@ public class ModelGenerator { ContainerSchemaNode output = rpc.getOutput(); if (output != null) { - JSONObject outputJSON = processContainer(output, moduleName, true, models, schemaContext); + JSONObject outputJSON = processDataNodeContainer(output, moduleName, models, schemaContext); String filename = "(" + rpc.getQName().getLocalName() + ")output"; outputJSON.put("id", filename); models.put(filename, outputJSON); @@ -206,16 +198,16 @@ public class ModelGenerator { * 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 { + private void processIdentities(final Module module, final JSONObject models) throws JSONException { String moduleName = module.getName(); Set idNodes = module.getIdentities(); - _logger.debug("Processing Identities for module {} . Found {} identity statements", moduleName, idNodes.size()); + LOG.debug("Processing Identities for module {} . Found {} identity statements", moduleName, idNodes.size()); for (IdentitySchemaNode idNode : idNodes) { JSONObject identityObj = new JSONObject(); String identityName = idNode.getQName().getLocalName(); - _logger.debug("Processing Identity: {}", identityName); + LOG.debug("Processing Identity: {}", identityName); identityObj.put(ID_KEY, identityName); identityObj.put(DESCRIPTION_KEY, idNode.getDescription()); @@ -251,7 +243,7 @@ public class ModelGenerator { } /** - * Processes the container node and populates the moduleJSON + * Processes the container and list nodes and populates the moduleJSON * * @param container * @param moduleName @@ -259,32 +251,74 @@ public class ModelGenerator { * @throws JSONException * @throws IOException */ - 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 processDataNodeContainer(final DataNodeContainer dataNode, final String moduleName, final JSONObject models, + final SchemaContext schemaContext) throws JSONException, IOException { + return processDataNodeContainer(dataNode, moduleName, models, (Boolean) null, schemaContext); } - 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(); - } else { - moduleJSON = new JSONObject(); + private JSONObject processDataNodeContainer(final DataNodeContainer dataNode, final String moduleName, final JSONObject models, + final Boolean isConfig, final SchemaContext schemaContext) throws JSONException, IOException { + if (dataNode instanceof ListSchemaNode || dataNode instanceof ContainerSchemaNode) { + Preconditions.checkArgument(dataNode instanceof SchemaNode, "Data node should be also schema node"); + Iterable containerChildren = dataNode.getChildNodes(); + JSONObject properties = processChildren(containerChildren, ((SchemaNode) dataNode).getQName(), moduleName, + models, isConfig, schemaContext); + + String nodeName = (BooleanUtils.isNotFalse(isConfig) ? OperationBuilder.CONFIG + : OperationBuilder.OPERATIONAL) + ((SchemaNode) dataNode).getQName().getLocalName(); + + JSONObject childSchema = getSchemaTemplate(); + childSchema.put(TYPE_KEY, OBJECT_TYPE); + childSchema.put(PROPERTIES_KEY, properties); + childSchema.put("id", nodeName); + models.put(nodeName, childSchema); + + if (BooleanUtils.isNotFalse(isConfig)) { + createConcreteModelForPost(models, ((SchemaNode) dataNode).getQName().getLocalName(), + createPropertiesForPost(dataNode)); + } + + JSONObject items = new JSONObject(); + items.put(REF_KEY, nodeName); + JSONObject dataNodeProperties = new JSONObject(); + dataNodeProperties.put(TYPE_KEY, dataNode instanceof ListSchemaNode ? ARRAY_TYPE : OBJECT_TYPE); + dataNodeProperties.put(ITEMS_KEY, items); + + return dataNodeProperties; } - moduleJSON.put(TYPE_KEY, OBJECT_TYPE); + return null; + } - String containerDescription = container.getDescription(); - moduleJSON.put(DESCRIPTION_KEY, containerDescription); + private void createConcreteModelForPost(final JSONObject models, final String localName, final JSONObject properties) + throws JSONException { + String nodePostName = OperationBuilder.CONFIG + localName + METHOD_NAME; + JSONObject postSchema = getSchemaTemplate(); + postSchema.put(TYPE_KEY, OBJECT_TYPE); + postSchema.put("id", nodePostName); + postSchema.put(PROPERTIES_KEY, properties); + models.put(nodePostName, postSchema); + } - JSONObject properties = processChildren(container.getChildNodes(), container.getQName(), moduleName, models, - isConfig, schemaContext); - moduleJSON.put(PROPERTIES_KEY, properties); - return moduleJSON; + private JSONObject createPropertiesForPost(final DataNodeContainer dataNodeContainer) throws JSONException { + JSONObject properties = new JSONObject(); + for (DataSchemaNode childNode : dataNodeContainer.getChildNodes()) { + if (childNode instanceof ListSchemaNode || childNode instanceof ContainerSchemaNode) { + JSONObject items = new JSONObject(); + items.put(REF_KEY, "(config)" + childNode.getQName().getLocalName()); + JSONObject property = new JSONObject(); + property.put(TYPE_KEY, childNode instanceof ListSchemaNode ? ARRAY_TYPE : OBJECT_TYPE); + property.put(ITEMS_KEY, items); + properties.put(childNode.getQName().getLocalName(), property); + } else if (childNode instanceof LeafSchemaNode){ + JSONObject property = processLeafNode((LeafSchemaNode)childNode); + properties.put(childNode.getQName().getLocalName(), property); + } + } + return properties; } - private JSONObject processChildren(Iterable nodes, QName parentQName, String moduleName, - JSONObject models, SchemaContext schemaContext) throws JSONException, IOException { + private JSONObject processChildren(final Iterable nodes, final QName parentQName, final String moduleName, + final JSONObject models, final SchemaContext schemaContext) throws JSONException, IOException { return processChildren(nodes, parentQName, moduleName, models, null, schemaContext); } @@ -299,8 +333,8 @@ public class ModelGenerator { * @throws JSONException * @throws IOException */ - private JSONObject processChildren(Iterable nodes, QName parentQName, String moduleName, - JSONObject models, Boolean isConfig, SchemaContext schemaContext) throws JSONException, IOException { + private JSONObject processChildren(final Iterable nodes, final QName parentQName, final String moduleName, + final JSONObject models, final Boolean isConfig, final SchemaContext schemaContext) throws JSONException, IOException { JSONObject properties = new JSONObject(); @@ -312,19 +346,20 @@ public class ModelGenerator { if (node instanceof LeafSchemaNode) { property = processLeafNode((LeafSchemaNode) node); } else if (node instanceof ListSchemaNode) { - property = processListSchemaNode((ListSchemaNode) node, moduleName, models, isConfig, schemaContext); + property = processDataNodeContainer((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, schemaContext); + } else if (node instanceof ChoiceSchemaNode) { + property = processChoiceNode((ChoiceSchemaNode) 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 = processDataNodeContainer((ContainerSchemaNode) node, moduleName, models, isConfig, schemaContext); } else { @@ -343,7 +378,7 @@ public class ModelGenerator { * @param listNode * @throws JSONException */ - private JSONObject processLeafListNode(LeafListSchemaNode listNode) throws JSONException { + private JSONObject processLeafListNode(final LeafListSchemaNode listNode) throws JSONException { JSONObject props = new JSONObject(); props.put(TYPE_KEY, ARRAY_TYPE); @@ -364,8 +399,8 @@ public class ModelGenerator { * @throws JSONException * @throws IOException */ - private JSONObject processChoiceNode(ChoiceNode choiceNode, String moduleName, JSONObject models, - SchemaContext schemaContext) throws JSONException, IOException { + private JSONObject processChoiceNode(final ChoiceSchemaNode choiceNode, final String moduleName, final JSONObject models, + final SchemaContext schemaContext) throws JSONException, IOException { Set cases = choiceNode.getCases(); @@ -393,7 +428,7 @@ public class ModelGenerator { * @param props * @throws JSONException */ - private void processConstraints(ConstraintDefinition constraints, JSONObject props) throws JSONException { + private void processConstraints(final ConstraintDefinition constraints, final JSONObject props) throws JSONException { boolean isMandatory = constraints.isMandatory(); props.put(REQUIRED_KEY, isMandatory); @@ -407,57 +442,13 @@ public class ModelGenerator { } } - /** - * 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. - * - * @param listNode - * @param moduleName - * @param isConfig - * @return - * @throws JSONException - * @throws 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(); - - 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. - */ - // writeToFile(fileName, childSchema.toString(2), moduleName); - childSchema.put("id", fileName); - models.put(fileName, childSchema); - - JSONObject listNodeProperties = new JSONObject(); - listNodeProperties.put(TYPE_KEY, ARRAY_TYPE); - - JSONObject items = new JSONObject(); - items.put(REF_KEY, fileName); - listNodeProperties.put(ITEMS_KEY, items); - - return listNodeProperties; - - } - /** * * @param leafNode * @return * @throws JSONException */ - private JSONObject processLeafNode(LeafSchemaNode leafNode) throws JSONException { + private JSONObject processLeafNode(final LeafSchemaNode leafNode) throws JSONException { JSONObject property = new JSONObject(); String leafDescription = leafNode.getDescription(); @@ -475,7 +466,7 @@ public class ModelGenerator { * @return * @throws JSONException */ - private JSONObject processAnyXMLNode(AnyXmlSchemaNode leafNode) throws JSONException { + private JSONObject processAnyXMLNode(final AnyXmlSchemaNode leafNode) throws JSONException { JSONObject property = new JSONObject(); String leafDescription = leafNode.getDescription(); @@ -490,7 +481,7 @@ public class ModelGenerator { * @param property * @throws JSONException */ - private void processTypeDef(TypeDefinition leafTypeDef, JSONObject property) throws JSONException { + private void processTypeDef(final TypeDefinition leafTypeDef, final JSONObject property) throws JSONException { if (leafTypeDef instanceof ExtendedType) { processExtendedType(leafTypeDef, property); @@ -523,7 +514,7 @@ public class ModelGenerator { * @param property * @throws JSONException */ - private void processExtendedType(TypeDefinition leafTypeDef, JSONObject property) throws JSONException { + private void processExtendedType(final TypeDefinition leafTypeDef, final JSONObject property) throws JSONException { Object leafBaseType = leafTypeDef.getBaseType(); if (leafBaseType instanceof ExtendedType) { // recursively process an extended type until we hit a base type @@ -545,7 +536,7 @@ public class ModelGenerator { /* * */ - private void processBinaryType(BinaryTypeDefinition binaryType, JSONObject property) throws JSONException { + private void processBinaryType(final BinaryTypeDefinition binaryType, final JSONObject property) throws JSONException { property.put(TYPE_KEY, STRING); JSONObject media = new JSONObject(); media.put(BINARY_ENCODING_KEY, BASE_64); @@ -558,7 +549,7 @@ public class ModelGenerator { * @param property * @throws JSONException */ - private void processEnumType(EnumerationType enumLeafType, JSONObject property) throws JSONException { + private void processEnumType(final EnumerationType enumLeafType, final JSONObject property) throws JSONException { List enumPairs = enumLeafType.getValues(); List enumNames = new ArrayList(); for (EnumPair enumPair : enumPairs) { @@ -573,7 +564,7 @@ public class ModelGenerator { * @param property * @throws JSONException */ - private void processBitsType(BitsTypeDefinition bitsType, JSONObject property) throws JSONException { + private void processBitsType(final BitsTypeDefinition bitsType, final JSONObject property) throws JSONException { property.put(TYPE_KEY, ARRAY_TYPE); property.put(MIN_ITEMS, 0); property.put(UNIQUE_ITEMS_KEY, true); @@ -594,7 +585,7 @@ public class ModelGenerator { * @param property * @throws JSONException */ - private void processUnionType(UnionTypeDefinition unionType, JSONObject property) throws JSONException { + private void processUnionType(final UnionTypeDefinition unionType, final JSONObject property) throws JSONException { StringBuilder type = new StringBuilder(); for (TypeDefinition typeDef : unionType.getTypes()) {