import com.google.common.annotations.Beta;
import com.google.common.base.Preconditions;
+import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.opendaylight.mdsal.binding.javav2.generator.util.Types;
import org.opendaylight.mdsal.binding.javav2.generator.util.generated.type.builder.GeneratedPropertyBuilderImpl;
import org.opendaylight.mdsal.binding.javav2.generator.util.generated.type.builder.GeneratedTypeBuilderImpl;
+import org.opendaylight.mdsal.binding.javav2.generator.yang.types.GroupingDefinitionDependencySort;
import org.opendaylight.mdsal.binding.javav2.generator.yang.types.TypeProviderImpl;
import org.opendaylight.mdsal.binding.javav2.model.api.AccessModifier;
import org.opendaylight.mdsal.binding.javav2.model.api.GeneratedTransferObject;
static GeneratedTypeBuilder addDefaultInterfaceDefinition(final String packageName, final SchemaNode
schemaNode, final Module module, final Map<Module, ModuleContext> genCtx, final SchemaContext schemaContext,
- final boolean verboseClassComments, final Map<String, Map<String, GeneratedTypeBuilder>> genTypeBuilders) {
+ final boolean verboseClassComments, final Map<String, Map<String, GeneratedTypeBuilder>> genTypeBuilders,
+ final TypeProvider typeProvider) {
return addDefaultInterfaceDefinition(packageName, schemaNode, null, module, genCtx, schemaContext,
- verboseClassComments, genTypeBuilders);
+ verboseClassComments, genTypeBuilders, typeProvider);
}
static Map<Module, ModuleContext> processUsesAugments(final SchemaContext schemaContext, final
*/
static Map<Module, ModuleContext> addRawAugmentGenTypeDefinition(final Module module, final String augmentPackageName,
final String basePackageName, final Type targetTypeRef, final AugmentationSchema augSchema,
- final Map<String, Map<String, GeneratedTypeBuilder>> genTypeBuilders, final Map<Module, ModuleContext> genCtx) {
+ final Map<String, Map<String, GeneratedTypeBuilder>> genTypeBuilders, final Map<Module,
+ ModuleContext> genCtx, final SchemaContext schemaContext, final boolean verboseClassComments, final
+ TypeProvider typeProvider) {
- Map<String, GeneratedTypeBuilder> augmentBuilders = genTypeBuilders.get(augmentPackageName);
- if (augmentBuilders == null) {
- augmentBuilders = new HashMap<>();
- genTypeBuilders.put(augmentPackageName, augmentBuilders);
- }
+ Map<String, GeneratedTypeBuilder> augmentBuilders = genTypeBuilders.computeIfAbsent(augmentPackageName, k -> new HashMap<>());
String augIdentifier = getAugmentIdentifier(augSchema.getUnknownSchemaNodes());
if (augIdentifier == null) {
augTypeBuilder = addImplementedInterfaceFromUses(augSchema, augTypeBuilder, genCtx);
augTypeBuilder = augSchemaNodeToMethods(module, basePackageName, augTypeBuilder, augTypeBuilder, augSchema
- .getChildNodes());
+ .getChildNodes(), genCtx, schemaContext, verboseClassComments, typeProvider, genTypeBuilders);
augmentBuilders.put(augTypeBuilder.getName(), augTypeBuilder);
if(!augSchema.getChildNodes().isEmpty()) {
* added to it.
*/
private static GeneratedTypeBuilder augSchemaNodeToMethods(final Module module, final String basePackageName,
- final GeneratedTypeBuilder typeBuilder, final GeneratedTypeBuilder childOf,
- final Iterable<DataSchemaNode> schemaNodes) {
+ final GeneratedTypeBuilder typeBuilder, final GeneratedTypeBuilder childOf, final Iterable<DataSchemaNode> schemaNodes,
+ final Map<Module, ModuleContext> genCtx, final SchemaContext schemaContext, final boolean
+ verboseClassComments, final TypeProvider typeProvider, final Map<String, Map<String,
+ GeneratedTypeBuilder>> genTypeBuilders) {
if (schemaNodes != null && typeBuilder != null) {
for (final DataSchemaNode schemaNode : schemaNodes) {
if (!schemaNode.isAugmenting()) {
- //TODO: design decomposition and implement it
- //addSchemaNodeToBuilderAsMethod(basePackageName, schemaNode, typeBuilder, childOf, module);
+ addSchemaNodeToBuilderAsMethod(basePackageName, schemaNode, typeBuilder, childOf, module, genCtx,
+ schemaContext, verboseClassComments, genTypeBuilders, typeProvider);
}
}
}
*/
static GeneratedTypeBuilder addDefaultInterfaceDefinition(final String packageName, final SchemaNode
schemaNode, final Type parent, final Module module, final Map<Module, ModuleContext> genCtx,
- final SchemaContext schemaContext, final boolean verboseClassComments, final Map<String, Map<String, GeneratedTypeBuilder>> genTypeBuilders) {
+ final SchemaContext schemaContext, final boolean verboseClassComments, final Map<String, Map<String,
+ GeneratedTypeBuilder>> genTypeBuilders, final TypeProvider typeProvider) {
GeneratedTypeBuilder it = addRawInterfaceDefinition(packageName, schemaNode, schemaContext, "",
verboseClassComments, genTypeBuilders);
}
if (schemaNode instanceof DataNodeContainer) {
- //TODO: design decomposition and implement it
- //groupingsToGenTypes(module, ((DataNodeContainer) schemaNode).getGroupings());
+ groupingsToGenTypes(module, ((DataNodeContainer) schemaNode).getGroupings(), genCtx, schemaContext,
+ verboseClassComments, genTypeBuilders, typeProvider);
it = addImplementedInterfaceFromUses((DataNodeContainer) schemaNode, it, genCtx);
}
final GeneratedTypeBuilder notificationInterface = addDefaultInterfaceDefinition
(basePackageName, notification, null, module, genCtx, schemaContext,
- verboseClassComments, genTypeBuilders);
+ verboseClassComments, genTypeBuilders, typeProvider);
annotateDeprecatedIfNecessary(notification.getStatus(), notificationInterface);
notificationInterface.addImplementsType(NOTIFICATION);
genCtx.get(module).addChildNodeType(notification, notificationInterface);
* builder belongs
* @param schemaNode
* schema node which provide data about the schema node name
- * @param schemaContext
+ * @param schemaContext schema context
* @param prefix
* return type name prefix
* @return generated type builder for <code>schemaNode</code>
@SuppressWarnings({ "rawtypes", "unchecked" })
private static GeneratedTypeBuilder processDataSchemaNode(final Module module, final String basePackageName,
final GeneratedTypeBuilder childOf, final DataSchemaNode node, final SchemaContext schemaContext,
- final boolean verboseClassComments, final Map<Module, ModuleContext> genCtx, final Map<String, Map<String,
+ final boolean verboseClassComments, Map<Module, ModuleContext> genCtx, final Map<String, Map<String,
GeneratedTypeBuilder>> genTypeBuilders, final TypeProvider typeProvider) {
if (node.isAugmenting() || node.isAddedByUses()) {
}
final String packageName = packageNameForGeneratedType(basePackageName, node.getPath(), BindingNamespaceType.Data);
final GeneratedTypeBuilder genType = addDefaultInterfaceDefinition(packageName, node, childOf, module,
- genCtx, schemaContext, verboseClassComments, genTypeBuilders);
+ genCtx, schemaContext, verboseClassComments, genTypeBuilders, typeProvider);
genType.addComment(node.getDescription());
annotateDeprecatedIfNecessary(node.getStatus(), genType);
genType.setDescription(createDescription(node, genType.getFullyQualifiedName(), schemaContext, verboseClassComments));
genType.setSchemaPath((List) node.getPath().getPathFromRoot());
if (node instanceof DataNodeContainer) {
genCtx.get(module).addChildNodeType(node, genType);
- //TODO: implement groupings to GTO building first
- // groupingsToGenTypes(module, ((DataNodeContainer) node).getGroupings());
+ genCtx = groupingsToGenTypes(module, ((DataNodeContainer) node).getGroupings(), genCtx, schemaContext,
+ verboseClassComments, genTypeBuilders, typeProvider);
processUsesAugments(schemaContext, (DataNodeContainer) node, module, genCtx, genTypeBuilders,
verboseClassComments, typeProvider);
}
return genType;
}
+
+ /**
+ * Converts all <b>groupings</b> of the module to the list of
+ * <code>Type</code> objects. Firstly are groupings sorted according mutual
+ * dependencies. At least dependent (independent) groupings are in the list
+ * saved at first positions. For every grouping the record is added to map
+ * {@link ModuleContext#groupings allGroupings}
+ *
+ * @param module
+ * current module
+ * @param groupings
+ * collection of groupings from which types will be generated
+ * @param typeProvider
+ * provider that defines contract for generated types
+ * @param schemaContext
+ * schema context
+ * @param genCtx
+ * map of generated entities in context of YANG modules
+ * @param genTypeBuilders
+ * map of generated type builders
+ * @param verboseClassComments
+ * generate verbose comments
+ *
+ */
+ static Map<Module, ModuleContext> groupingsToGenTypes(final Module module, final Collection<GroupingDefinition>
+ groupings, Map<Module, ModuleContext> genCtx, final SchemaContext schemaContext, final boolean
+ verboseClassComments, Map<String, Map<String, GeneratedTypeBuilder>> genTypeBuilders, final TypeProvider typeProvider) {
+ final String basePackageName = BindingMapping.getRootPackageName(module);
+ final List<GroupingDefinition> groupingsSortedByDependencies = new GroupingDefinitionDependencySort()
+ .sort(groupings);
+ for (final GroupingDefinition grouping : groupingsSortedByDependencies) {
+ genCtx = groupingToGenType(basePackageName, grouping, module, genCtx, schemaContext,
+ verboseClassComments, genTypeBuilders, typeProvider);
+ }
+ return genCtx;
+ }
+
+ /**
+ * Converts individual grouping to GeneratedType. Firstly generated type
+ * builder is created and every child node of grouping is resolved to the
+ * method.
+ *
+ * @param basePackageName
+ * string contains the module package name
+ * @param grouping
+ * GroupingDefinition which contains data about grouping
+ * @param module
+ * current module
+ * @param typeProvider
+ * provider that defines contract for generated types
+ * @param schemaContext
+ * schema context
+ * @param genCtx
+ * map of generated entities in context of YANG modules
+ * @param genTypeBuilders
+ * map of generated type builders
+ * @param verboseClassComments
+ * generate verbose comments
+ *
+ * @return GeneratedType which is generated from grouping (object of type
+ * <code>GroupingDefinition</code>)
+ */
+ private static Map<Module, ModuleContext> groupingToGenType(final String basePackageName, final GroupingDefinition grouping, final Module
+ module, Map<Module, ModuleContext> genCtx, final SchemaContext schemaContext, final boolean
+ verboseClassComments, Map<String, Map<String, GeneratedTypeBuilder>> genTypeBuilders, final TypeProvider typeProvider) {
+ final String packageName = packageNameForGeneratedType(basePackageName, grouping.getPath(), BindingNamespaceType.Grouping);
+ final GeneratedTypeBuilder genType = addDefaultInterfaceDefinition(packageName, grouping, module, genCtx,
+ schemaContext, verboseClassComments, genTypeBuilders, typeProvider);
+ annotateDeprecatedIfNecessary(grouping.getStatus(), genType);
+ genCtx.get(module).addGroupingType(grouping.getPath(), genType);
+ resolveDataSchemaNodes(module, basePackageName, genType, genType, grouping.getChildNodes(), genCtx,
+ schemaContext, verboseClassComments, genTypeBuilders, typeProvider);
+ genCtx = groupingsToGenTypes(module, grouping.getGroupings(), genCtx, schemaContext, verboseClassComments,
+ genTypeBuilders, typeProvider);
+ genCtx = processUsesAugments(schemaContext, grouping, module, genCtx, genTypeBuilders, verboseClassComments,
+ typeProvider);
+ return genCtx;
+ }
}
--- /dev/null
+/*
+ * Copyright (c) 2017 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.mdsal.binding.javav2.generator.yang.types;
+
+import com.google.common.collect.Maps;
+import com.google.common.collect.Sets;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import org.opendaylight.yangtools.yang.model.api.AugmentationSchema;
+import org.opendaylight.yangtools.yang.model.api.ChoiceCaseNode;
+import org.opendaylight.yangtools.yang.model.api.ChoiceSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.GroupingDefinition;
+import org.opendaylight.yangtools.yang.model.api.SchemaPath;
+import org.opendaylight.yangtools.yang.model.api.UsesNode;
+import org.opendaylight.yangtools.yang.parser.util.NodeWrappedType;
+import org.opendaylight.yangtools.yang.parser.util.TopologicalSort;
+import org.opendaylight.yangtools.yang.parser.util.TopologicalSort.Node;
+
+public class GroupingDefinitionDependencySort {
+
+ /**
+ * Sorts set <code>groupingDefinitions</code> according to the mutual
+ * dependencies.<br>
+ *
+ * Elements of <code>groupingDefinitions</code> are firstly transformed to
+ * {@link org.opendaylight.yangtools.yang.parser.util.TopologicalSort.Node
+ * Node} interfaces and then are sorted by
+ * {@link org.opendaylight.yangtools.yang.parser.util.TopologicalSort#sort(Set)
+ * sort()} method of <code>TopologicalSort</code>.<br>
+ * <br>
+ *
+ *
+ * <i>Definition of dependency relation:<br>
+ * The first <code>GroupingDefinition</code> object (in this context)
+ * depends on second <code>GroupingDefinition</code> object if the first one
+ * contains in its set of <code>UsesNode</code> (obtained through
+ * {@link org.opendaylight.yangtools.yang.model.api.DataNodeContainer#getUses()
+ * getUses} method) reference to the second one.</i>
+ *
+ * @param groupingDefinitions
+ * set of grouping definition which should be sorted according to
+ * mutual dependencies
+ * @return list of grouping definitiond which are sorted by mutual
+ * dependencies
+ * @throws IllegalArgumentException
+ * if <code>groupingDefinitions</code>
+ *
+ */
+ public List<GroupingDefinition> sort(final Collection<GroupingDefinition> groupingDefinitions) {
+ if (groupingDefinitions == null) {
+ throw new IllegalArgumentException("Set of Type Definitions " + "cannot be NULL!");
+ }
+
+ final List<GroupingDefinition> resultGroupingDefinitions = new ArrayList<GroupingDefinition>();
+ final Set<Node> unsorted = groupingDefinitionsToNodes(groupingDefinitions);
+ final List<Node> sortedNodes = TopologicalSort.sort(unsorted);
+ for (Node node : sortedNodes) {
+ NodeWrappedType nodeWrappedType = (NodeWrappedType) node;
+ resultGroupingDefinitions.add((GroupingDefinition) (nodeWrappedType.getWrappedType()));
+ }
+ return resultGroupingDefinitions;
+
+ }
+
+ /**
+ * Wraps every grouping definition to node type and adds to every node
+ * information about dependencies.
+ *
+ * The map with mapping from schema path (represents grouping definition) to
+ * node is created. For every created node (next <i>nodeFrom</i>) is for its
+ * wrapped grouping definition passed the set of its <i>uses nodes</i>
+ * through. For every uses node is found its wrapping node (next as
+ * <i>nodeTo</i>). This dependency relationship between nodeFrom and all
+ * found nodesTo is modeled with creating of one edge from nodeFrom to
+ * nodeTo.
+ *
+ *
+ * @param groupingDefinitions
+ * set of goruping definition which will be wrapped to nodes
+ *
+ * @return set of nodes where every one contains wrapped grouping definition
+ */
+ private Set<Node> groupingDefinitionsToNodes(final Collection<GroupingDefinition> groupingDefinitions) {
+ final Map<SchemaPath, Node> nodeMap = Maps.newHashMap();
+ final Set<Node> resultNodes = Sets.newHashSet();
+
+ for (final GroupingDefinition groupingDefinition : groupingDefinitions) {
+ final Node node = new NodeWrappedType(groupingDefinition);
+ nodeMap.put(groupingDefinition.getPath(), node);
+ resultNodes.add(node);
+ }
+
+ for (final Node node : resultNodes) {
+ final NodeWrappedType nodeWrappedType = (NodeWrappedType) node;
+ final GroupingDefinition groupingDefinition = (GroupingDefinition) nodeWrappedType.getWrappedType();
+
+ Set<UsesNode> usesNodes = getAllUsesNodes(groupingDefinition);
+
+ for (UsesNode usesNode : usesNodes) {
+ SchemaPath schemaPath = usesNode.getGroupingPath();
+ Node nodeTo = nodeMap.get(schemaPath);
+ if (nodeTo != null) {
+ nodeWrappedType.addEdge(nodeTo);
+ }
+ }
+ }
+
+ return resultNodes;
+ }
+
+ /**
+ * Returns the set of the uses nodes which are get from uses in
+ * <code>container</code>, from uses in groupings inside
+ * <code>container</code> and from uses inside child nodes of the
+ * <code>container</code>.
+ *
+ * @param container
+ * data node container which can contain some uses of grouping
+ * @return set of uses nodes which were find in <code>container</code>.
+ */
+ private Set<UsesNode> getAllUsesNodes(final DataNodeContainer container) {
+ Set<UsesNode> ret = new HashSet<>();
+ Set<UsesNode> usesNodes = container.getUses();
+ ret.addAll(usesNodes);
+
+ for (UsesNode usesNode : usesNodes) {
+ for (AugmentationSchema augment : usesNode.getAugmentations()) {
+ ret.addAll(getAllUsesNodes(augment));
+ }
+ }
+ Set<GroupingDefinition> groupings = container.getGroupings();
+ for (GroupingDefinition groupingDefinition : groupings) {
+ ret.addAll(getAllUsesNodes(groupingDefinition));
+ }
+ for (DataSchemaNode childNode : container.getChildNodes()) {
+ if (childNode instanceof DataNodeContainer) {
+ ret.addAll(getAllUsesNodes((DataNodeContainer) childNode));
+ } else if (childNode instanceof ChoiceSchemaNode) {
+ Set<ChoiceCaseNode> cases = ((ChoiceSchemaNode) childNode).getCases();
+ for (ChoiceCaseNode choiceCaseNode : cases) {
+ ret.addAll(getAllUsesNodes(choiceCaseNode));
+ }
+ }
+ }
+ return ret;
+ }
+}