</executions>
</plugin>
- <!-- Scala -> compile Scala files, in this example generated from Twirl -->
+ <!-- Scala -> compile Scala files generated from Twirl -->
<plugin>
<groupId>net.alchim31.maven</groupId>
<artifactId>scala-maven-plugin</artifactId>
--- /dev/null
+/*
+ * Copyright (c) 2016 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.binding2.generator.impl;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkState;
+import static org.opendaylight.mdsal.binding2.generator.impl.GenHelperUtil.findCaseByPath;
+import static org.opendaylight.mdsal.binding2.generator.impl.GenHelperUtil.findChildNodeByPath;
+import static org.opendaylight.mdsal.binding2.generator.impl.GenHelperUtil.processUsesAugments;
+import static org.opendaylight.mdsal.binding2.generator.impl.GenHelperUtil.resolveDataSchemaNodes;
+import static org.opendaylight.mdsal.binding2.generator.util.Binding2GeneratorUtil.packageNameForAugmentedGeneratedType;
+import static org.opendaylight.mdsal.binding2.generator.util.Binding2GeneratorUtil.packageNameForGeneratedType;
+import static org.opendaylight.mdsal.binding2.generator.util.Binding2Mapping.getRootPackageName;
+import static org.opendaylight.yangtools.yang.model.util.SchemaContextUtil.findDataSchemaNode;
+
+import com.google.common.annotations.Beta;
+import com.google.common.base.Optional;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import org.opendaylight.mdsal.binding2.generator.util.ReferencedTypeImpl;
+import org.opendaylight.mdsal.binding2.model.api.Type;
+import org.opendaylight.mdsal.binding2.model.api.type.builder.GeneratedTypeBuilder;
+import org.opendaylight.yangtools.yang.common.QName;
+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.DerivableSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.GroupingDefinition;
+import org.opendaylight.yangtools.yang.model.api.Module;
+import org.opendaylight.yangtools.yang.model.api.NotificationDefinition;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.model.api.SchemaNode;
+import org.opendaylight.yangtools.yang.model.api.SchemaPath;
+import org.opendaylight.yangtools.yang.model.api.UsesNode;
+import org.opendaylight.yangtools.yang.model.util.SchemaContextUtil;
+
+@Beta
+final class AugmentToGenType {
+
+ private AugmentToGenType() {
+ throw new UnsupportedOperationException("Utility class");
+ }
+
+ /**
+ * Comparator based on augment target path.
+ */
+ private static final Comparator<AugmentationSchema> AUGMENT_COMP = (o1, o2) -> {
+ final Iterator<QName> thisIt = o1.getTargetPath().getPathFromRoot().iterator();
+ final Iterator<QName> otherIt = o2.getTargetPath().getPathFromRoot().iterator();
+
+ while (thisIt.hasNext()) {
+ if (!otherIt.hasNext()) {
+ return 1;
+ }
+
+ final int comp = thisIt.next().compareTo(otherIt.next());
+ if (comp != 0) {
+ return comp;
+ }
+ }
+
+ return otherIt.hasNext() ? -1 : 0;
+ };
+
+ /**
+ * Converts all <b>augmentation</b> of the module to the list
+ * <code>Type</code> objects.
+ *
+ * @param module
+ * module from which is obtained list of all augmentation objects
+ * to iterate over them
+ * @param schemaContext
+ * @param genCtx
+ * @param genTypeBuilders
+ *
+ * @throws IllegalArgumentException
+ * <ul>
+ * <li>if the module is null</li>
+ * <li>if the name of module is null</li>
+ * </ul>
+ * @throws IllegalStateException
+ * if set of augmentations from module is null
+ */
+ static Map<Module, ModuleContext> generate(final Module module, final SchemaContext schemaContext, Map<Module,
+ ModuleContext> genCtx, Map<String, Map<String, GeneratedTypeBuilder>> genTypeBuilders,
+ final boolean verboseClassComments) {
+
+ checkArgument(module != null, "Module reference cannot be NULL.");
+ checkArgument(module.getName() != null, "Module name cannot be NULL.");
+ checkState(module.getAugmentations() != null, "Augmentations Set cannot be NULL.");
+
+ final String basePackageName = getRootPackageName(module);
+ final List<AugmentationSchema> augmentations = resolveAugmentations(module);
+ for (final AugmentationSchema augment : augmentations) {
+ genCtx = augmentationToGenTypes(basePackageName, augment, module, schemaContext, verboseClassComments,
+ genCtx, genTypeBuilders);
+ }
+ return genCtx;
+ }
+
+ /**
+ * Returns list of <code>AugmentationSchema</code> objects. The objects are
+ * sorted according to the length of their target path from the shortest to
+ * the longest.
+ *
+ * @param module
+ * module from which is obtained list of all augmentation objects
+ * @return list of sorted <code>AugmentationSchema</code> objects obtained
+ * from <code>module</code>
+ * @throws IllegalArgumentException
+ * if module is null
+ * @throws IllegalStateException
+ * if set of module augmentations is null
+ */
+ private static List<AugmentationSchema> resolveAugmentations(final Module module) {
+ checkArgument(module != null, "Module reference cannot be NULL.");
+ checkState(module.getAugmentations() != null, "Augmentations Set cannot be NULL.");
+
+ final Set<AugmentationSchema> augmentations = module.getAugmentations();
+ final List<AugmentationSchema> sortedAugmentations = new ArrayList<>(augmentations);
+ Collections.sort(sortedAugmentations, AUGMENT_COMP);
+
+ return sortedAugmentations;
+ }
+
+ /**
+ * Converts <code>augSchema</code> to list of <code>Type</code> which
+ * contains generated type for augmentation. In addition there are also
+ * generated types for all containers, list and choices which are child of
+ * <code>augSchema</code> node or a generated types for cases are added if
+ * augmented node is choice.
+ *
+ * @param augmentPackageName
+ * string with the name of the package to which the augmentation
+ * belongs
+ * @param augSchema
+ * AugmentationSchema which is contains data about augmentation
+ * (target path, childs...)
+ * @param module
+ * current module
+ * @param schemaContext
+ * @param genCtx
+ * @param genTypeBuilders
+ * @throws IllegalArgumentException
+ * <ul>
+ * <li>if <code>augmentPackageName</code> equals null</li>
+ * <li>if <code>augSchema</code> equals null</li>
+ * </ul>
+ * @throws IllegalStateException
+ * if augment target path is null
+ * @return
+ */
+ private static Map<Module, ModuleContext> augmentationToGenTypes(final String augmentPackageName, final AugmentationSchema augSchema,
+ final Module module, final SchemaContext schemaContext, final boolean verboseClassComments,
+ Map<Module, ModuleContext> genCtx, Map<String, Map<String, GeneratedTypeBuilder>> genTypeBuilders) {
+
+ Map<Module, ModuleContext> generatedCtx;
+ checkArgument(augmentPackageName != null, "Package Name cannot be NULL.");
+ checkArgument(augSchema != null, "Augmentation Schema cannot be NULL.");
+ checkState(augSchema.getTargetPath() != null,
+ "Augmentation Schema does not contain Target Path (Target Path is NULL).");
+
+ generatedCtx = processUsesAugments(schemaContext, augSchema, module, genCtx, genTypeBuilders, verboseClassComments);
+ final SchemaPath targetPath = augSchema.getTargetPath();
+ SchemaNode targetSchemaNode;
+
+ targetSchemaNode = findDataSchemaNode(schemaContext, targetPath);
+ if (targetSchemaNode instanceof DataSchemaNode && ((DataSchemaNode) targetSchemaNode).isAddedByUses()) {
+ if (targetSchemaNode instanceof DerivableSchemaNode) {
+ targetSchemaNode = ((DerivableSchemaNode) targetSchemaNode).getOriginal().orNull();
+ }
+ if (targetSchemaNode == null) {
+ throw new IllegalStateException("Failed to find target node from grouping in augmentation " + augSchema
+ + " in module " + module.getName());
+ }
+ }
+ if (targetSchemaNode == null) {
+ throw new IllegalArgumentException("augment target not found: " + targetPath);
+ }
+
+ GeneratedTypeBuilder targetTypeBuilder = findChildNodeByPath(targetSchemaNode.getPath(), generatedCtx);
+ if (targetTypeBuilder == null) {
+ targetTypeBuilder = findCaseByPath(targetSchemaNode.getPath(), generatedCtx);
+ }
+ if (targetTypeBuilder == null) {
+ throw new NullPointerException("Target type not yet generated: " + targetSchemaNode);
+ }
+
+ if (!(targetSchemaNode instanceof ChoiceSchemaNode)) {
+ final String packageName = augmentPackageName;
+ final Type targetType = new ReferencedTypeImpl(targetTypeBuilder.getPackageName(),
+ targetTypeBuilder.getName());
+ generatedCtx = GenHelperUtil.addRawAugmentGenTypeDefinition(module, packageName, augmentPackageName, targetType,
+ augSchema, genTypeBuilders, generatedCtx);
+ return generatedCtx;
+
+ } else {
+ generatedCtx = generateTypesFromAugmentedChoiceCases(schemaContext, module, augmentPackageName,
+ targetTypeBuilder.toInstance(), (ChoiceSchemaNode) targetSchemaNode, augSchema.getChildNodes(),
+ null, generatedCtx, verboseClassComments, genTypeBuilders);
+ return generatedCtx;
+ }
+ }
+
+ public static Map<Module, ModuleContext> usesAugmentationToGenTypes(final SchemaContext schemaContext, final String
+ augmentPackageName, final AugmentationSchema augSchema, final Module module, final UsesNode usesNode, final DataNodeContainer
+ usesNodeParent, Map<Module, ModuleContext> genCtx,
+ Map<String, Map<String, GeneratedTypeBuilder>> genTypeBuilders,
+ final boolean verboseClassComments) {
+
+ Map<Module, ModuleContext> generatedCtx;
+ checkArgument(augmentPackageName != null, "Package Name cannot be NULL.");
+ checkArgument(augSchema != null, "Augmentation Schema cannot be NULL.");
+ checkState(augSchema.getTargetPath() != null,
+ "Augmentation Schema does not contain Target Path (Target Path is NULL).");
+
+ generatedCtx = processUsesAugments(schemaContext, augSchema, module, genCtx, genTypeBuilders, verboseClassComments);
+ final SchemaPath targetPath = augSchema.getTargetPath();
+ final SchemaNode targetSchemaNode = findOriginalTargetFromGrouping(schemaContext, targetPath, usesNode);
+ if (targetSchemaNode == null) {
+ throw new IllegalArgumentException("augment target not found: " + targetPath);
+ }
+
+ GeneratedTypeBuilder targetTypeBuilder = findChildNodeByPath(targetSchemaNode.getPath(), generatedCtx);
+ if (targetTypeBuilder == null) {
+ targetTypeBuilder = findCaseByPath(targetSchemaNode.getPath(), generatedCtx);
+ }
+ if (targetTypeBuilder == null) {
+ throw new NullPointerException("Target type not yet generated: " + targetSchemaNode);
+ }
+
+ if (!(targetSchemaNode instanceof ChoiceSchemaNode)) {
+ String packageName = augmentPackageName;
+ if (usesNodeParent instanceof SchemaNode) {
+ packageName = packageNameForAugmentedGeneratedType(augmentPackageName, ((SchemaNode) usesNodeParent).getPath());
+ }
+ generatedCtx = GenHelperUtil.addRawAugmentGenTypeDefinition(module, packageName, augmentPackageName,
+ targetTypeBuilder.toInstance(), augSchema, genTypeBuilders, generatedCtx);
+ return generatedCtx;
+ } else {
+ generatedCtx = generateTypesFromAugmentedChoiceCases(schemaContext, module, augmentPackageName,
+ targetTypeBuilder.toInstance(), (ChoiceSchemaNode) targetSchemaNode, augSchema.getChildNodes(),
+ usesNodeParent, generatedCtx, verboseClassComments, genTypeBuilders);
+ return generatedCtx;
+ }
+ }
+
+ /**
+ * Convenient method to find node added by uses statement.
+ * @param schemaContext
+ * @param targetPath
+ * node path
+ * @param parentUsesNode
+ * parent of uses node
+ * @return node from its original location in grouping
+ */
+ private static DataSchemaNode findOriginalTargetFromGrouping(final SchemaContext schemaContext, final SchemaPath targetPath,
+ final UsesNode parentUsesNode) {
+ final SchemaNode targetGrouping = SchemaContextUtil.findNodeInSchemaContext(schemaContext, parentUsesNode
+ .getGroupingPath()
+ .getPathFromRoot());
+ if (!(targetGrouping instanceof GroupingDefinition)) {
+ throw new IllegalArgumentException("Failed to generate code for augment in " + parentUsesNode);
+ }
+
+ final GroupingDefinition grouping = (GroupingDefinition) targetGrouping;
+ SchemaNode result = grouping;
+ for (final QName node : targetPath.getPathFromRoot()) {
+ if (result instanceof DataNodeContainer) {
+ final QName resultNode = QName.create(result.getQName().getModule(), node.getLocalName());
+ result = ((DataNodeContainer) result).getDataChildByName(resultNode);
+ } else if (result instanceof ChoiceSchemaNode) {
+ result = ((ChoiceSchemaNode) result).getCaseNodeByName(node.getLocalName());
+ }
+ }
+ if (result == null) {
+ return null;
+ }
+
+ if (result instanceof DerivableSchemaNode) {
+ DerivableSchemaNode castedResult = (DerivableSchemaNode) result;
+ Optional<? extends SchemaNode> originalNode = castedResult
+ .getOriginal();
+ if (castedResult.isAddedByUses() && originalNode.isPresent()) {
+ result = originalNode.get();
+ }
+ }
+
+ if (result instanceof DataSchemaNode) {
+ DataSchemaNode resultDataSchemaNode = (DataSchemaNode) result;
+ if (resultDataSchemaNode.isAddedByUses()) {
+ // The original node is required, but we have only the copy of
+ // the original node.
+ // Maybe this indicates a bug in Yang parser.
+ throw new IllegalStateException(
+ "Failed to generate code for augment in "
+ + parentUsesNode);
+ } else {
+ return resultDataSchemaNode;
+ }
+ } else {
+ throw new IllegalStateException(
+ "Target node of uses-augment statement must be DataSchemaNode. Failed to generate code for augment in "
+ + parentUsesNode);
+ }
+ }
+
+ /**
+ * Generates list of generated types for all the cases of a choice which are
+ * added to the choice through the augment.
+ *
+ * @param schemaContext
+ * @param module
+ * current module
+ * @param basePackageName
+ * string contains name of package to which augment belongs. If
+ * an augmented choice is from an other package (pcg1) than an
+ * augmenting choice (pcg2) then case's of the augmenting choice
+ * will belong to pcg2.
+ * @param targetType
+ * Type which represents target choice
+ * @param targetNode
+ * node which represents target choice
+ * @param augmentedNodes
+ * set of choice case nodes for which is checked if are/aren't
+ * added to choice through augmentation
+ * @return list of generated types which represents augmented cases of
+ * choice <code>refChoiceType</code>
+ * @throws IllegalArgumentException
+ * <ul>
+ * <li>if <code>basePackageName</code> is null</li>
+ * <li>if <code>targetType</code> is null</li>
+ * <li>if <code>augmentedNodes</code> is null</li>
+ * </ul>
+ */
+ private static Map<Module, ModuleContext> generateTypesFromAugmentedChoiceCases(final SchemaContext schemaContext, final Module module,
+ final String basePackageName, final Type targetType, final ChoiceSchemaNode targetNode,
+ final Iterable<DataSchemaNode> augmentedNodes, final DataNodeContainer usesNodeParent,
+ Map<Module, ModuleContext> genCtx, final boolean verboseClassComments,
+ Map<String, Map<String, GeneratedTypeBuilder>> genTypeBuilders) {
+ checkArgument(basePackageName != null, "Base Package Name cannot be NULL.");
+ checkArgument(targetType != null, "Referenced Choice Type cannot be NULL.");
+ checkArgument(augmentedNodes != null, "Set of Choice Case Nodes cannot be NULL.");
+
+ for (final DataSchemaNode caseNode : augmentedNodes) {
+ if (caseNode != null) {
+ final String packageName = packageNameForGeneratedType(basePackageName, caseNode.getPath());
+ final GeneratedTypeBuilder caseTypeBuilder = GenHelperUtil.addDefaultInterfaceDefinition(packageName,
+ caseNode, module, genCtx, schemaContext, verboseClassComments, genTypeBuilders);
+ caseTypeBuilder.addImplementsType(targetType);
+
+ SchemaNode parent;
+ final SchemaPath nodeSp = targetNode.getPath();
+ parent = findDataSchemaNode(schemaContext, nodeSp.getParent());
+
+ GeneratedTypeBuilder childOfType = null;
+ if (parent instanceof Module) {
+ childOfType = genCtx.get(parent).getModuleNode();
+ } else if (parent instanceof ChoiceCaseNode) {
+ childOfType = findCaseByPath(parent.getPath(), genCtx);
+ } else if (parent instanceof DataSchemaNode || parent instanceof NotificationDefinition) {
+ childOfType = findChildNodeByPath(parent.getPath(), genCtx);
+ } else if (parent instanceof GroupingDefinition) {
+ childOfType = GenHelperUtil.findGroupingByPath(parent.getPath(), genCtx);
+ }
+
+ if (childOfType == null) {
+ throw new IllegalArgumentException("Failed to find parent type of choice " + targetNode);
+ }
+
+ ChoiceCaseNode node = null;
+ final String caseLocalName = caseNode.getQName().getLocalName();
+ if (caseNode instanceof ChoiceCaseNode) {
+ node = (ChoiceCaseNode) caseNode;
+ } else if (targetNode.getCaseNodeByName(caseLocalName) == null) {
+ final String targetNodeLocalName = targetNode.getQName().getLocalName();
+ for (DataSchemaNode dataSchemaNode : usesNodeParent.getChildNodes()) {
+ if (dataSchemaNode instanceof ChoiceSchemaNode && targetNodeLocalName.equals(dataSchemaNode.getQName
+ ().getLocalName())) {
+ node = ((ChoiceSchemaNode) dataSchemaNode).getCaseNodeByName(caseLocalName);
+ break;
+ }
+ }
+ } else {
+ node = targetNode.getCaseNodeByName(caseLocalName);
+ }
+ final Iterable<DataSchemaNode> childNodes = node.getChildNodes();
+ if (childNodes != null) {
+ resolveDataSchemaNodes(module, basePackageName, caseTypeBuilder, childOfType, childNodes);
+ }
+ genCtx.get(module).addCaseType(caseNode.getPath(), caseTypeBuilder);
+ genCtx.get(module).addChoiceToCaseMapping(targetType, caseTypeBuilder, node);
+ }
+ }
+ return genCtx;
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2016 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.binding2.generator.impl;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.base.Preconditions.checkState;
+
+import com.google.common.annotations.Beta;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import org.opendaylight.mdsal.binding2.generator.api.BindingGenerator;
+import org.opendaylight.mdsal.binding2.generator.spi.TypeProvider;
+import org.opendaylight.mdsal.binding2.generator.yang.types.TypeProviderImpl;
+import org.opendaylight.mdsal.binding2.model.api.Type;
+import org.opendaylight.mdsal.binding2.model.api.type.builder.GeneratedTypeBuilder;
+import org.opendaylight.yangtools.yang.model.api.Module;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.parser.util.ModuleDependencySort;
+
+/**
+ * Main class for Binding generator v2. Provides transformation of Schema Context to
+ * generated transfer objects. Process is accompanied with Twirl templates to generate
+ * particular Javadoc for related YANG elements.
+ */
+@Beta
+public class BindingGeneratorImpl implements BindingGenerator {
+
+ /**
+ * When set to true, generated classes will include Javadoc comments
+ * which are useful for users.
+ */
+ private final boolean verboseClassComments;
+
+ /**
+ * Outer key represents the package name. Outer value represents map of all
+ * builders in the same package. Inner key represents the schema node name
+ * (in JAVA class/interface name format). Inner value represents instance of
+ * builder for schema node specified in key part.
+ */
+ private Map<String, Map<String, GeneratedTypeBuilder>> genTypeBuilders = new HashMap<>();
+
+ private Map<Module, ModuleContext> genCtx = new HashMap<>();
+
+ /**
+ * Creates a new binding generator v2.
+ *
+ * @param verboseClassComments generate verbose comments
+ */
+ public BindingGeneratorImpl(final boolean verboseClassComments) {
+ this.verboseClassComments = verboseClassComments;
+ }
+
+ /**
+ * Provide methods for converting YANG types to JAVA types.
+ */
+ private TypeProvider typeProvider;
+
+ /**
+ * Holds reference to schema context to resolve data of augmented element
+ * when creating augmentation builder
+ */
+ private SchemaContext schemaContext;
+
+ /**
+ * Resolves generated types from <code>context</code> schema nodes of all
+ * modules.
+ *
+ * Generated types are created for modules, groupings, types, containers,
+ * lists, choices, augments, rpcs, notification, identities.
+ *
+ * @param context
+ * schema context which contains data about all schema nodes
+ * saved in modules
+ * @return list of types (usually <code>GeneratedType</code>
+ * <code>GeneratedTransferObject</code>which are generated from
+ * <code>context</code> data.
+ * @throws IllegalArgumentException
+ * if arg <code>context</code> is null
+ * @throws IllegalStateException
+ * if <code>context</code> contain no modules
+ */
+ @Override
+ public List<Type> generateTypes(SchemaContext context) {
+ checkArgument(context != null, "Schema Context reference cannot be NULL.");
+ checkState(context.getModules() != null, "Schema Context does not contain defined modules.");
+ schemaContext = context;
+ typeProvider = new TypeProviderImpl(context);
+ final Set<Module> modules = context.getModules();
+ return generateTypes(context, modules);
+ }
+
+ @Override
+ public List<Type> generateTypes(SchemaContext context, Set<Module> modules) {
+ checkArgument(context != null, "Schema Context reference cannot be NULL.");
+ checkState(context.getModules() != null, "Schema Context does not contain defined modules.");
+ checkArgument(modules != null, "Set of Modules cannot be NULL.");
+
+ schemaContext = context;
+ typeProvider = new TypeProviderImpl(context);
+ final Module[] modulesArray = new Module[context.getModules().size()];
+ context.getModules().toArray(modulesArray);
+ final List<Module> contextModules = ModuleDependencySort.sort(modulesArray);
+
+ for (final Module contextModule : contextModules) {
+ genCtx = ModuleToGenType.generate(contextModule, context, typeProvider, verboseClassComments);
+ }
+ for (final Module contextModule : contextModules) {
+ genCtx = AugmentToGenType.generate(contextModule, schemaContext, genCtx,
+ genTypeBuilders, verboseClassComments);
+ }
+
+ final List<Type> filteredGenTypes = new ArrayList<>();
+ for (final Module m : modules) {
+ final ModuleContext ctx = checkNotNull(genCtx.get(m), "Module context not found for module %s", m);
+ filteredGenTypes.addAll(ctx.getGeneratedTypes());
+ final Set<Type> additionalTypes = ((TypeProviderImpl) typeProvider).getAdditionalTypes().get(m);
+ if (additionalTypes != null) {
+ filteredGenTypes.addAll(additionalTypes);
+ }
+ }
+
+ return filteredGenTypes;
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2016 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.binding2.generator.impl;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static org.opendaylight.mdsal.binding2.generator.impl.AugmentToGenType.usesAugmentationToGenTypes;
+import static org.opendaylight.mdsal.binding2.generator.util.BindingTypes.TREE_ROOT;
+import static org.opendaylight.mdsal.binding2.generator.util.BindingTypes.augmentable;
+import static org.opendaylight.mdsal.binding2.generator.util.Types.typeForClass;
+
+import com.google.common.annotations.Beta;
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Splitter;
+import com.google.common.base.Strings;
+import com.google.common.collect.Iterables;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.regex.Pattern;
+import org.opendaylight.mdsal.binding2.generator.impl.util.YangTextTemplate;
+import org.opendaylight.mdsal.binding2.generator.util.Binding2GeneratorUtil;
+import org.opendaylight.mdsal.binding2.generator.util.Binding2Mapping;
+import org.opendaylight.mdsal.binding2.generator.util.BindingTypes;
+import org.opendaylight.mdsal.binding2.generator.util.Types;
+import org.opendaylight.mdsal.binding2.generator.util.generated.type.builder.GeneratedTypeBuilderImpl;
+import org.opendaylight.mdsal.binding2.model.api.Constant;
+import org.opendaylight.mdsal.binding2.model.api.GeneratedType;
+import org.opendaylight.mdsal.binding2.model.api.Type;
+import org.opendaylight.mdsal.binding2.model.api.type.builder.GeneratedTypeBuilder;
+import org.opendaylight.mdsal.binding2.model.api.type.builder.GeneratedTypeBuilderBase;
+import org.opendaylight.mdsal.binding2.txt.yangTemplateForModule;
+import org.opendaylight.mdsal.binding2.txt.yangTemplateForNode;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.model.api.AugmentationSchema;
+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.GroupingDefinition;
+import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.Module;
+import org.opendaylight.yangtools.yang.model.api.NotificationDefinition;
+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.SchemaPath;
+import org.opendaylight.yangtools.yang.model.api.Status;
+import org.opendaylight.yangtools.yang.model.api.UnknownSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.UsesNode;
+import org.opendaylight.yangtools.yang.model.util.SchemaContextUtil;
+
+
+/**
+ * Helper util class used for generation of types in binding spec v2.
+ */
+@Beta
+final class GenHelperUtil {
+
+ private GenHelperUtil() {
+ throw new UnsupportedOperationException("Util class");
+ }
+
+ private static final Pattern UNICODE_CHAR_PATTERN = Pattern.compile("\\\\+u");
+ private static final Splitter BSDOT_SPLITTER = Splitter.on("\\.");
+ private static final char NEW_LINE = '\n';
+
+ /**
+ * Constant with the concrete name of identifier.
+ */
+ private static final String AUGMENT_IDENTIFIER_NAME = "augment-identifier";
+
+ /**
+ * Constant with the concrete name of namespace.
+ */
+ private static final String YANG_EXT_NAMESPACE = "urn:opendaylight:yang:extension:yang-ext";
+
+
+ /**
+ * Create GeneratedTypeBuilder object from module argument.
+ *
+ * @param module
+ * Module object from which builder will be created
+ * @param genCtx
+ * @param verboseClassComments
+ *
+ * @return <code>GeneratedTypeBuilder</code> which is internal
+ * representation of the module
+ * @throws IllegalArgumentException
+ * if module is null
+ */
+ static GeneratedTypeBuilder moduleToDataType(final Module module, Map<Module, ModuleContext> genCtx, final boolean verboseClassComments) {
+ checkArgument(module != null, "Module reference cannot be NULL.");
+
+ final GeneratedTypeBuilder moduleDataTypeBuilder = moduleTypeBuilder(module, "Data", verboseClassComments);
+ addImplementedInterfaceFromUses(module, moduleDataTypeBuilder, genCtx);
+ moduleDataTypeBuilder.addImplementsType(TREE_ROOT);
+ moduleDataTypeBuilder.addComment(module.getDescription());
+ moduleDataTypeBuilder.setDescription(createDescription(module, verboseClassComments));
+ moduleDataTypeBuilder.setReference(module.getReference());
+ return moduleDataTypeBuilder;
+ }
+
+ /**
+ * Generates type builder for <code>module</code>.
+ *
+ * @param module
+ * Module which is source of package name for generated type
+ * builder
+ * @param postfix
+ * string which is added to the module class name representation
+ * as suffix
+ * @param verboseClassComments
+ * @return instance of GeneratedTypeBuilder which represents
+ * <code>module</code>.
+ * @throws IllegalArgumentException
+ * if <code>module</code> is null
+ */
+ static GeneratedTypeBuilder moduleTypeBuilder(final Module module, final String postfix, final boolean verboseClassComments) {
+ checkArgument(module != null, "Module reference cannot be NULL.");
+ final String packageName = Binding2Mapping.getRootPackageName(module);
+ final String moduleName = Binding2Mapping.getClassName(module.getName()) + postfix;
+
+ final GeneratedTypeBuilderImpl moduleBuilder = new GeneratedTypeBuilderImpl(packageName, moduleName);
+ moduleBuilder.setDescription(createDescription(module, verboseClassComments));
+ moduleBuilder.setReference(module.getReference());
+ moduleBuilder.setModuleName(moduleName);
+
+ return moduleBuilder;
+ }
+
+ /**
+ * Adds the implemented types to type builder.
+ *
+ * The method passes through the list of <i>uses</i> in
+ * {@code dataNodeContainer}. For every <i>use</i> is obtained corresponding
+ * generated type from all groupings
+ * allGroupings} which is added as <i>implements type</i> to
+ * <code>builder</code>
+ *
+ * @param dataNodeContainer
+ * element which contains the list of used YANG groupings
+ * @param builder
+ * builder to which are added implemented types according to
+ * <code>dataNodeContainer</code>
+ * @param genCtx
+ * @return generated type builder with all implemented types
+ */
+ private static GeneratedTypeBuilder addImplementedInterfaceFromUses(final DataNodeContainer dataNodeContainer,
+ final GeneratedTypeBuilder builder, Map<Module, ModuleContext> genCtx) {
+ for (final UsesNode usesNode : dataNodeContainer.getUses()) {
+ if (usesNode.getGroupingPath() != null) {
+ final GeneratedType genType = findGroupingByPath(usesNode.getGroupingPath(), genCtx).toInstance();
+ if (genType == null) {
+ throw new IllegalStateException("Grouping " + usesNode.getGroupingPath() + "is not resolved for "
+ + builder.getName());
+ }
+
+ builder.addImplementsType(genType);
+ }
+ }
+ return builder;
+ }
+
+ static GeneratedTypeBuilder findGroupingByPath(final SchemaPath path, Map<Module, ModuleContext> genCtx) {
+ for (final ModuleContext ctx : genCtx.values()) {
+ final GeneratedTypeBuilder result = ctx.getGrouping(path);
+ if (result != null) {
+ return result;
+ }
+ }
+ return null;
+ }
+
+ private static String createDescription(final Module module, final boolean verboseClassComments) {
+ final StringBuilder sb = new StringBuilder();
+ final String moduleDescription = Binding2GeneratorUtil.encodeAngleBrackets(module.getDescription());
+ final String formattedDescription = YangTextTemplate.formatToParagraph(moduleDescription, 0);
+
+ if (!Strings.isNullOrEmpty(formattedDescription)) {
+ sb.append(formattedDescription);
+ sb.append(NEW_LINE);
+ }
+
+ if (verboseClassComments) {
+ sb.append("<p>");
+ sb.append("This class represents the following YANG schema fragment defined in module <b>");
+ sb.append(module.getName());
+ sb.append("</b>");
+ sb.append(NEW_LINE);
+ sb.append("<pre>");
+ sb.append(NEW_LINE);
+ sb.append(Binding2GeneratorUtil.encodeAngleBrackets(yangTemplateForModule.render(module).body()));
+ sb.append("</pre>");
+ }
+
+ return replaceAllIllegalChars(sb);
+ }
+
+ @VisibleForTesting
+ public static String replaceAllIllegalChars(final StringBuilder stringBuilder){
+ final String ret = UNICODE_CHAR_PATTERN.matcher(stringBuilder).replaceAll("\\\\\\\\u");
+ return ret.isEmpty() ? "" : ret;
+ }
+
+ /**
+ * Adds the methods to <code>typeBuilder</code> which represent subnodes of
+ * node for which <code>typeBuilder</code> was created.
+ *
+ * The subnodes aren't mapped to the methods if they are part of grouping or
+ * augment (in this case are already part of them).
+ *
+ * @param module
+ * current module
+ * @param basePackageName
+ * string contains the module package name
+ * @param parent
+ * generated type builder which represents any node. The subnodes
+ * of this node are added to the <code>typeBuilder</code> as
+ * methods. The subnode can be of type leaf, leaf-list, list,
+ * container, choice.
+ * @param childOf
+ * parent type
+ * @param schemaNodes
+ * set of data schema nodes which are the children of the node
+ * for which <code>typeBuilder</code> was created
+ * @return generated type builder which is the same builder as input
+ * parameter. The getter methods (representing child nodes) could be
+ * added to it.
+ */
+ static GeneratedTypeBuilder resolveDataSchemaNodes(final Module module, final String basePackageName,
+ final GeneratedTypeBuilder parent, final GeneratedTypeBuilder childOf, final Iterable<DataSchemaNode> schemaNodes) {
+ if (schemaNodes != null && parent != null) {
+ for (final DataSchemaNode schemaNode : schemaNodes) {
+ if (!schemaNode.isAugmenting() && !schemaNode.isAddedByUses()) {
+ //TODO: design decomposition and implement it
+ //addSchemaNodeToBuilderAsMethod(basePackageName, schemaNode, parent, childOf, module);
+ }
+ }
+ }
+ return parent;
+ }
+
+ static Map<Module, ModuleContext> processUsesAugments(final SchemaContext schemaContext, final
+ DataNodeContainer node, final Module module, Map<Module, ModuleContext> genCtx, Map<String,
+ Map<String, GeneratedTypeBuilder>> genTypeBuilders, final boolean verboseClassComments) {
+ final String basePackageName = Binding2Mapping.getRootPackageName(module);
+ for (final UsesNode usesNode : node.getUses()) {
+ for (final AugmentationSchema augment : usesNode.getAugmentations()) {
+ genCtx = usesAugmentationToGenTypes(schemaContext, basePackageName, augment, module, usesNode,
+ node, genCtx, genTypeBuilders, verboseClassComments);
+ genCtx = processUsesAugments(schemaContext, augment, module, genCtx, genTypeBuilders, verboseClassComments);
+ }
+ }
+ return genCtx;
+ }
+
+ static GeneratedTypeBuilder findChildNodeByPath(final SchemaPath path, Map<Module, ModuleContext> genCtx) {
+ for (final ModuleContext ctx : genCtx.values()) {
+ final GeneratedTypeBuilder result = ctx.getChildNode(path);
+ if (result != null) {
+ return result;
+ }
+ }
+ return null;
+ }
+
+ static GeneratedTypeBuilder findCaseByPath(final SchemaPath path, Map<Module, ModuleContext> genCtx) {
+ for (final ModuleContext ctx : genCtx.values()) {
+ final GeneratedTypeBuilder result = ctx.getCase(path);
+ if (result != null) {
+ return result;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Returns a generated type builder for an augmentation.
+ *
+ * The name of the type builder is equal to the name of augmented node with
+ * serial number as suffix.
+ *
+ * @param module
+ * current module
+ * @param augmentPackageName
+ * string with contains the package name to which the augment
+ * belongs
+ * @param basePackageName
+ * string with the package name to which the augmented node
+ * belongs
+ * @param targetTypeRef
+ * target type
+ * @param augSchema
+ * augmentation schema which contains data about the child nodes
+ * and uses of augment
+ * @return generated type builder for augment in genCtx
+ */
+ static Map<Module, ModuleContext> addRawAugmentGenTypeDefinition(final Module module, final String augmentPackageName,
+ final String basePackageName, final Type targetTypeRef, final AugmentationSchema augSchema,
+ Map<String, Map<String, GeneratedTypeBuilder>> genTypeBuilders, Map<Module, ModuleContext> genCtx) {
+
+ Map<String, GeneratedTypeBuilder> augmentBuilders = genTypeBuilders.get(augmentPackageName);
+ if (augmentBuilders == null) {
+ augmentBuilders = new HashMap<>();
+ genTypeBuilders.put(augmentPackageName, augmentBuilders);
+ }
+ final String augIdentifier = getAugmentIdentifier(augSchema.getUnknownSchemaNodes());
+
+ String augTypeName;
+ if (augIdentifier != null) {
+ augTypeName = Binding2Mapping.getClassName(augIdentifier);
+ } else {
+ augTypeName = augGenTypeName(augmentBuilders, targetTypeRef.getName());
+ }
+
+ GeneratedTypeBuilder augTypeBuilder = new GeneratedTypeBuilderImpl(augmentPackageName, augTypeName);
+
+ augTypeBuilder.addImplementsType(BindingTypes.TREE_NODE);
+ augTypeBuilder.addImplementsType(Types.augmentationTypeFor(targetTypeRef));
+ annotateDeprecatedIfNecessary(augSchema.getStatus(), augTypeBuilder);
+ augTypeBuilder = addImplementedInterfaceFromUses(augSchema, augTypeBuilder, genCtx);
+
+ augTypeBuilder = augSchemaNodeToMethods(module, basePackageName, augTypeBuilder, augTypeBuilder, augSchema
+ .getChildNodes());
+ augmentBuilders.put(augTypeName, augTypeBuilder);
+
+ if(!augSchema.getChildNodes().isEmpty()) {
+ genCtx.get(module).addTypeToAugmentation(augTypeBuilder, augSchema);
+
+ }
+ genCtx.get(module).addAugmentType(augTypeBuilder);
+ return genCtx;
+ }
+
+ /**
+ * Adds the methods to <code>typeBuilder</code> what represents subnodes of
+ * node for which <code>typeBuilder</code> was created.
+ *
+ * @param module
+ * current module
+ * @param basePackageName
+ * string contains the module package name
+ * @param typeBuilder
+ * generated type builder which represents any node. The subnodes
+ * of this node are added to the <code>typeBuilder</code> as
+ * methods. The subnode can be of type leaf, leaf-list, list,
+ * container, choice.
+ * @param childOf
+ * parent type
+ * @param schemaNodes
+ * set of data schema nodes which are the children of the node
+ * for which <code>typeBuilder</code> was created
+ * @return generated type builder which is the same object as the input
+ * parameter <code>typeBuilder</code>. The getter method could be
+ * added to it.
+ */
+ private static GeneratedTypeBuilder augSchemaNodeToMethods(final Module module, final String basePackageName,
+ final GeneratedTypeBuilder typeBuilder, final GeneratedTypeBuilder childOf,
+ final Iterable<DataSchemaNode> schemaNodes) {
+ 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);
+ }
+ }
+ }
+ return typeBuilder;
+ }
+
+ /**
+ * @param unknownSchemaNodes
+ * @return nodeParameter of UnknownSchemaNode
+ */
+ private static String getAugmentIdentifier(final List<UnknownSchemaNode> unknownSchemaNodes) {
+ for (final UnknownSchemaNode unknownSchemaNode : unknownSchemaNodes) {
+ final QName nodeType = unknownSchemaNode.getNodeType();
+ if (AUGMENT_IDENTIFIER_NAME.equals(nodeType.getLocalName())
+ && YANG_EXT_NAMESPACE.equals(nodeType.getNamespace().toString())) {
+ return unknownSchemaNode.getNodeParameter();
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Returns first unique name for the augment generated type builder. The
+ * generated type builder name for augment consists from name of augmented
+ * node and serial number of its augmentation.
+ *
+ * @param builders
+ * map of builders which were created in the package to which the
+ * augmentation belongs
+ * @param genTypeName
+ * string with name of augmented node
+ * @return string with unique name for augmentation builder
+ */
+ private static String augGenTypeName(final Map<String, GeneratedTypeBuilder> builders, final String genTypeName) {
+ int index = 1;
+ if (builders != null) {
+ while (builders.containsKey(genTypeName + index)) {
+ index = index + 1;
+ }
+ }
+ return genTypeName + index;
+ }
+
+ static GeneratedTypeBuilder addDefaultInterfaceDefinition(final String packageName, final SchemaNode
+ schemaNode, final Module module, Map<Module, ModuleContext> genCtx, final SchemaContext schemaContext,
+ final boolean verboseClassComments, Map<String, Map<String, GeneratedTypeBuilder>> genTypeBuilders) {
+ return addDefaultInterfaceDefinition(packageName, schemaNode, null, module, genCtx, schemaContext,
+ verboseClassComments, genTypeBuilders);
+ }
+
+ /**
+ * Instantiates generated type builder with <code>packageName</code> and
+ * <code>schemaNode</code>.
+ *
+ * The new builder always implements
+ * {@link org.opendaylight.mdsal.binding2.spec.TreeNode TreeNode}.<br>
+ * If <code>schemaNode</code> is instance of GroupingDefinition it also
+ * implements {@link org.opendaylight.mdsal.binding2.spec.Augmentable
+ * Augmentable}.<br>
+ * If <code>schemaNode</code> is instance of
+ * {@link org.opendaylight.yangtools.yang.model.api.DataNodeContainer
+ * DataNodeContainer} it can also implement nodes which are specified in
+ * <i>uses</i>.
+ *
+ * @param packageName
+ * string with the name of the package to which
+ * <code>schemaNode</code> belongs.
+ * @param schemaNode
+ * schema node for which is created generated type builder
+ * @param parent
+ * parent type (can be null)
+ * @param schemaContext
+ * @return generated type builder <code>schemaNode</code>
+ */
+ private static GeneratedTypeBuilder addDefaultInterfaceDefinition(final String packageName, final SchemaNode
+ schemaNode, final Type parent, final Module module, Map<Module, ModuleContext> genCtx,
+ final SchemaContext schemaContext, final boolean verboseClassComments, Map<String, Map<String, GeneratedTypeBuilder>> genTypeBuilders) {
+ GeneratedTypeBuilder it = addRawInterfaceDefinition(packageName, schemaNode, schemaContext, "",
+ verboseClassComments, genTypeBuilders);
+ if (parent == null) {
+ it.addImplementsType(BindingTypes.TREE_NODE);
+ } else {
+ it.addImplementsType(BindingTypes.treeChildNode(parent));
+ }
+ if (!(schemaNode instanceof GroupingDefinition)) {
+ it.addImplementsType(augmentable(it));
+ }
+
+ if (schemaNode instanceof DataNodeContainer) {
+ //TODO: design decomposition and implement it
+ //groupingsToGenTypes(module, ((DataNodeContainer) schemaNode).getGroupings());
+ it = addImplementedInterfaceFromUses((DataNodeContainer) schemaNode, it, genCtx);
+ }
+
+ return it;
+ }
+
+ /**
+ * Returns reference to generated type builder for specified
+ * <code>schemaNode</code> with <code>packageName</code>.
+ *
+ * Firstly the generated type builder is searched in
+ * {@link BindingGeneratorImpl#genTypeBuilders genTypeBuilders}. If it isn't
+ * found it is created and added to <code>genTypeBuilders</code>.
+ *
+ * @param packageName
+ * string with the package name to which returning generated type
+ * builder belongs
+ * @param schemaNode
+ * schema node which provide data about the schema node name
+ * @param schemaContext
+ * @param prefix
+ * return type name prefix
+ * @return generated type builder for <code>schemaNode</code>
+ * @throws IllegalArgumentException
+ * <ul>
+ * <li>if <code>schemaNode</code> is null</li>
+ * <li>if <code>packageName</code> is null</li>
+ * <li>if QName of schema node is null</li>
+ * <li>if schemaNode name is null</li>
+ * </ul>
+ *
+ */
+ private static GeneratedTypeBuilder addRawInterfaceDefinition(final String packageName, final SchemaNode schemaNode,
+ final SchemaContext schemaContext, final String prefix, final boolean verboseClassComments,
+ Map<String, Map<String, GeneratedTypeBuilder>> genTypeBuilders) {
+ checkArgument(schemaNode != null, "Data Schema Node cannot be NULL.");
+ checkArgument(packageName != null, "Package Name for Generated Type cannot be NULL.");
+ checkArgument(schemaNode.getQName() != null, "QName for Data Schema Node cannot be NULL.");
+ final String schemaNodeName = schemaNode.getQName().getLocalName();
+ checkArgument(schemaNodeName != null, "Local Name of QName for Data Schema Node cannot be NULL.");
+
+ String genTypeName;
+ if (prefix == null) {
+ genTypeName = Binding2Mapping.getClassName(schemaNodeName);
+ } else {
+ genTypeName = prefix + Binding2Mapping.getClassName(schemaNodeName);
+ }
+
+ final GeneratedTypeBuilderImpl newType = new GeneratedTypeBuilderImpl(packageName, genTypeName);
+ final Module module = SchemaContextUtil.findParentModule(schemaContext, schemaNode);
+ qNameConstant(newType, Binding2Mapping.QNAME_STATIC_FIELD_NAME, schemaNode.getQName());
+ newType.addComment(schemaNode.getDescription());
+ newType.setDescription(createDescription(schemaNode, newType.getFullyQualifiedName(), schemaContext, verboseClassComments));
+ newType.setReference(schemaNode.getReference());
+ newType.setSchemaPath((List<QName>) schemaNode.getPath().getPathFromRoot());
+ newType.setModuleName(module.getName());
+
+ //FIXME: update genTypeBuilders for callers
+ if (!genTypeBuilders.containsKey(packageName)) {
+ final Map<String, GeneratedTypeBuilder> builders = new HashMap<>();
+ builders.put(genTypeName, newType);
+ genTypeBuilders.put(packageName, builders);
+ } else {
+ final Map<String, GeneratedTypeBuilder> builders = genTypeBuilders.get(packageName);
+ if (!builders.containsKey(genTypeName)) {
+ builders.put(genTypeName, newType);
+ }
+ }
+ return newType;
+
+ }
+
+ private static Constant qNameConstant(final GeneratedTypeBuilderBase<?> toBuilder, final String constantName,
+ final QName name) {
+ return toBuilder.addConstant(typeForClass(QName.class), constantName, name);
+ }
+
+ private static String createDescription(final SchemaNode schemaNode, final String fullyQualifiedName,
+ final SchemaContext schemaContext, final boolean verboseClassComments) {
+ final StringBuilder sb = new StringBuilder();
+ final String nodeDescription = Binding2GeneratorUtil.encodeAngleBrackets(schemaNode.getDescription());
+ final String formattedDescription = YangTextTemplate.formatToParagraph(nodeDescription, 0);
+
+ if (!Strings.isNullOrEmpty(formattedDescription)) {
+ sb.append(formattedDescription);
+ sb.append(NEW_LINE);
+ }
+
+ if (verboseClassComments) {
+ final Module module = SchemaContextUtil.findParentModule(schemaContext, schemaNode);
+ final StringBuilder linkToBuilderClass = new StringBuilder();
+ final String[] namespace = Iterables.toArray(BSDOT_SPLITTER.split(fullyQualifiedName), String.class);
+ final String className = namespace[namespace.length - 1];
+
+ if (hasBuilderClass(schemaNode)) {
+ linkToBuilderClass.append(className);
+ linkToBuilderClass.append("Builder");
+ }
+
+ sb.append("<p>");
+ sb.append("This class represents the following YANG schema fragment defined in module <b>");
+ sb.append(module.getName());
+ sb.append("</b>");
+ sb.append(NEW_LINE);
+ sb.append("<pre>");
+ sb.append(NEW_LINE);
+ sb.append(Binding2GeneratorUtil.encodeAngleBrackets(yangTemplateForNode.render(schemaNode).body()));
+ sb.append("</pre>");
+ sb.append(NEW_LINE);
+ sb.append("The schema path to identify an instance is");
+ sb.append(NEW_LINE);
+ sb.append("<i>");
+ sb.append(YangTextTemplate.formatSchemaPath(module.getName(), schemaNode.getPath().getPathFromRoot()));
+ sb.append("</i>");
+ sb.append(NEW_LINE);
+
+ if (hasBuilderClass(schemaNode)) {
+ sb.append(NEW_LINE);
+ sb.append("<p>To create instances of this class use " + "{@link " + linkToBuilderClass + "}.");
+ sb.append(NEW_LINE);
+ sb.append("@see ");
+ sb.append(linkToBuilderClass);
+ sb.append(NEW_LINE);
+ if (schemaNode instanceof ListSchemaNode) {
+ final List<QName> keyDef = ((ListSchemaNode)schemaNode).getKeyDefinition();
+ if (keyDef != null && !keyDef.isEmpty()) {
+ sb.append("@see ");
+ sb.append(className);
+ sb.append("Key");
+ }
+ sb.append(NEW_LINE);
+ }
+ }
+ }
+
+ return replaceAllIllegalChars(sb);
+ }
+
+ private static void annotateDeprecatedIfNecessary(final Status status, final GeneratedTypeBuilder builder) {
+ if (status == Status.DEPRECATED) {
+ builder.addAnnotation("", "Deprecated");
+ }
+ }
+
+ private static boolean hasBuilderClass(final SchemaNode schemaNode) {
+ if (schemaNode instanceof ContainerSchemaNode || schemaNode instanceof ListSchemaNode ||
+ schemaNode instanceof RpcDefinition || schemaNode instanceof NotificationDefinition) {
+ return true;
+ }
+ return false;
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2016 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.binding2.generator.impl;
+
+import com.google.common.annotations.Beta;
+import org.opendaylight.mdsal.binding2.generator.api.ClassLoadingStrategy;
+import org.opendaylight.mdsal.binding2.model.api.Type;
+
+@Beta
+public abstract class GeneratedClassLoadingStrategy implements ClassLoadingStrategy {
+
+ @Override
+ public Class<?> loadClass(Type type) throws ClassNotFoundException {
+ return loadClass(type.getFullyQualifiedName());
+ }
+
+ @Override
+ public abstract Class<?> loadClass(String fqcn) throws ClassNotFoundException;
+}
--- /dev/null
+/*
+ * Copyright (c) 2013 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.binding2.generator.impl;
+
+import com.google.common.annotations.Beta;
+import com.google.common.collect.BiMap;
+import com.google.common.collect.HashBiMap;
+import com.google.common.collect.HashMultimap;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Maps;
+import com.google.common.collect.Multimap;
+import com.google.common.collect.Multimaps;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.stream.Collectors;
+import org.opendaylight.mdsal.binding2.model.api.Type;
+import org.opendaylight.mdsal.binding2.model.api.type.builder.EnumBuilder;
+import org.opendaylight.mdsal.binding2.model.api.type.builder.GeneratedTOBuilder;
+import org.opendaylight.mdsal.binding2.model.api.type.builder.GeneratedTypeBuilder;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.model.api.AugmentationSchema;
+import org.opendaylight.yangtools.yang.model.api.ChoiceCaseNode;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.SchemaNode;
+import org.opendaylight.yangtools.yang.model.api.SchemaPath;
+import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
+
+/**
+ * This class holds information about generated entities in context of YANG module
+ */
+@Beta
+final class ModuleContext {
+ private GeneratedTypeBuilder moduleNode;
+ private final List<GeneratedTOBuilder> genTOs = new ArrayList<>();
+ private final Map<SchemaPath, Type> typedefs = new HashMap<>();
+ private final Map<SchemaPath, GeneratedTypeBuilder> childNodes = new HashMap<>();
+ private final Map<SchemaPath, GeneratedTypeBuilder> groupings = new HashMap<>();
+ private final Map<SchemaPath, GeneratedTypeBuilder> cases = new HashMap<>();
+ private final Map<QName,GeneratedTOBuilder> identities = new HashMap<>();
+ private final Set<GeneratedTypeBuilder> topLevelNodes = new HashSet<>();
+ private final List<GeneratedTypeBuilder> augmentations = new ArrayList<>();
+ private final BiMap<Type,AugmentationSchema> typeToAugmentation = HashBiMap.create();
+ private final Map<Type,Object> typeToSchema = new HashMap<>();
+ private final Multimap<Type, Type> choiceToCases = HashMultimap.create();
+ private final BiMap<Type,ChoiceCaseNode> caseTypeToSchema = HashBiMap.create();
+ private final Map<SchemaPath, Type> innerTypes = new HashMap<>();
+
+ List<Type> getGeneratedTypes() {
+ List<Type> result = new ArrayList<>();
+
+ if (moduleNode != null) {
+ result.add(moduleNode.toInstance());
+ }
+
+ result.addAll(genTOs.stream().map(GeneratedTOBuilder::toInstance).collect(Collectors.toList()));
+ result.addAll(typedefs.values().stream().filter(b -> b != null).collect(Collectors.toList()));
+ result.addAll(childNodes.values().stream().map(GeneratedTypeBuilder::toInstance).collect(Collectors.toList()));
+ result.addAll(groupings.values().stream().map(GeneratedTypeBuilder::toInstance).collect(Collectors.toList()));
+ result.addAll(cases.values().stream().map(GeneratedTypeBuilder::toInstance).collect(Collectors.toList()));
+ result.addAll(identities.values().stream().map(GeneratedTOBuilder::toInstance).collect(Collectors.toList()));
+ result.addAll(topLevelNodes.stream().map(GeneratedTypeBuilder::toInstance).collect(Collectors.toList()));
+ result.addAll(augmentations.stream().map(GeneratedTypeBuilder::toInstance).collect(Collectors.toList()));
+
+ return ImmutableList.copyOf(result);
+ }
+
+ public Multimap<Type, Type> getChoiceToCases() {
+ return Multimaps.unmodifiableMultimap(choiceToCases);
+ }
+
+ public GeneratedTypeBuilder getModuleNode() {
+ return moduleNode;
+ }
+
+ public GeneratedTypeBuilder getChildNode(final SchemaPath p) {
+ return childNodes.get(p);
+ }
+
+ public GeneratedTypeBuilder getGrouping(final SchemaPath p) {
+ return groupings.get(p);
+ }
+
+ public GeneratedTypeBuilder getCase(final SchemaPath p) {
+ return cases.get(p);
+ }
+
+ public void addModuleNode(final GeneratedTypeBuilder moduleNode) {
+ this.moduleNode = moduleNode;
+ }
+
+ public void addGeneratedTOBuilder(final GeneratedTOBuilder b) {
+ genTOs.add(b);
+ }
+
+ public void addChildNodeType(final SchemaNode p, final GeneratedTypeBuilder b) {
+ childNodes.put(p.getPath(), b);
+ typeToSchema.put(b,p);
+ }
+
+ public void addGroupingType(final SchemaPath p, final GeneratedTypeBuilder b) {
+ groupings.put(p, b);
+ }
+
+ public void addTypedefType(final SchemaPath p, final Type t) {
+ typedefs.put(p, t);
+ }
+
+ public void addCaseType(final SchemaPath p, final GeneratedTypeBuilder b) {
+ cases.put(p, b);
+ }
+
+ public void addIdentityType(final QName name,final GeneratedTOBuilder b) {
+ identities.put(name,b);
+ }
+
+ public void addTopLevelNodeType(final GeneratedTypeBuilder b) {
+ topLevelNodes.add(b);
+ }
+
+ public void addAugmentType(final GeneratedTypeBuilder b) {
+ augmentations.add(b);
+ }
+
+ public Map<SchemaPath, Type> getTypedefs() {
+ return typedefs;
+ }
+
+ public Map<SchemaPath, GeneratedTypeBuilder> getChildNodes() {
+ return Collections.unmodifiableMap(childNodes);
+ }
+
+ public Map<SchemaPath, GeneratedTypeBuilder> getGroupings() {
+ return Collections.unmodifiableMap(groupings);
+ }
+
+ public Map<SchemaPath, GeneratedTypeBuilder> getCases() {
+ return Collections.unmodifiableMap(cases);
+ }
+
+ public Map<QName,GeneratedTOBuilder> getIdentities() {
+ return Collections.unmodifiableMap(identities);
+ }
+
+ public Set<GeneratedTypeBuilder> getTopLevelNodes() {
+ return Collections.unmodifiableSet(topLevelNodes);
+ }
+
+ public List<GeneratedTypeBuilder> getAugmentations() {
+ return Collections.unmodifiableList(augmentations);
+ }
+
+ public BiMap<Type, AugmentationSchema> getTypeToAugmentation() {
+ return Maps.unmodifiableBiMap(typeToAugmentation);
+ }
+
+ public void addTypeToAugmentation(final GeneratedTypeBuilder builder, final AugmentationSchema schema) {
+ typeToAugmentation.put(builder, schema);
+ typeToSchema.put(builder, schema);
+ }
+
+ public void addChoiceToCaseMapping(final Type choiceType, final Type caseType, final ChoiceCaseNode schema) {
+ choiceToCases.put(choiceType, caseType);
+ caseTypeToSchema.put(caseType, schema);
+ typeToSchema.put(caseType, schema);
+ }
+
+ public BiMap<Type, ChoiceCaseNode> getCaseTypeToSchemas() {
+ return Maps.unmodifiableBiMap(caseTypeToSchema);
+ }
+
+ /**
+ *
+ * Returns mapping of type to its schema.
+ *
+ * Valid values are only instances of {@link DataSchemaNode} or {@link AugmentationSchema}
+ *
+ * @return Mapping from type to corresponding schema
+ */
+ public Map<Type, Object> getTypeToSchema() {
+ return Collections.unmodifiableMap(typeToSchema);
+ }
+
+ protected void addTypeToSchema(Type type, TypeDefinition<?> typedef) {
+ typeToSchema.put(type, typedef);
+ }
+
+ /**
+ * Adds mapping between schema path and inner enum.
+ *
+ * @param path
+ * @param enumBuilder
+ */
+ void addInnerTypedefType(SchemaPath path, EnumBuilder enumBuilder) {
+ innerTypes.put(path, enumBuilder);
+ }
+
+ public Type getInnerType(SchemaPath path) {
+ return innerTypes.get(path);
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2016 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.binding2.generator.impl;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkState;
+
+import com.google.common.annotations.Beta;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import org.opendaylight.mdsal.binding2.generator.spi.TypeProvider;
+import org.opendaylight.mdsal.binding2.generator.util.Binding2Mapping;
+import org.opendaylight.mdsal.binding2.generator.yang.types.TypeProviderImpl;
+import org.opendaylight.mdsal.binding2.model.api.Type;
+import org.opendaylight.mdsal.binding2.model.api.type.builder.GeneratedTypeBuilder;
+import org.opendaylight.yangtools.yang.model.api.Module;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
+import org.opendaylight.yangtools.yang.model.util.DataNodeIterator;
+
+@Beta
+final class ModuleToGenType {
+
+ private ModuleToGenType() {
+ throw new UnsupportedOperationException("Utility class");
+ }
+
+ static Map<Module, ModuleContext> generate(final Module module, final SchemaContext schemaContext,
+ TypeProvider typeProvider, final boolean verboseClassComments) {
+ Map<Module, ModuleContext> genCtx = new HashMap<>();
+
+ genCtx.put(module, new ModuleContext());
+ genCtx = allTypeDefinitionsToGenTypes(module, genCtx, typeProvider);
+
+ //TODO: call generate for other entities (groupings, rpcs, identities, notifications)
+
+ if (!module.getChildNodes().isEmpty()) {
+ final GeneratedTypeBuilder moduleType = GenHelperUtil.moduleToDataType(module, genCtx, verboseClassComments);
+ genCtx.get(module).addModuleNode(moduleType);
+ final String basePackageName = Binding2Mapping.getRootPackageName(module);
+ GenHelperUtil.resolveDataSchemaNodes(module, basePackageName, moduleType, moduleType, module
+ .getChildNodes());
+ }
+
+ return genCtx;
+ }
+
+ /**
+ * Converts all extended type definitions of module to the list of
+ * <code>Type</code> objects.
+ *
+ * @param module
+ * module from which is obtained set of type definitions
+ * @throws IllegalArgumentException
+ * <ul>
+ * <li>if module is null</li>
+ * <li>if name of module is null</li>
+ * </ul>
+ * @throws IllegalStateException
+ * if set of type definitions from module is null
+ */
+ private static Map<Module, ModuleContext> allTypeDefinitionsToGenTypes(final Module module, Map<Module, ModuleContext> genCtx,
+ TypeProvider typeProvider) {
+ checkArgument(module != null, "Module reference cannot be NULL.");
+ checkArgument(module.getName() != null, "Module name cannot be NULL.");
+ final DataNodeIterator it = new DataNodeIterator(module);
+ final List<TypeDefinition<?>> typeDefinitions = it.allTypedefs();
+ checkState(typeDefinitions != null, "Type Definitions for module «module.name» cannot be NULL.");
+
+ typeDefinitions.stream().filter(typedef -> typedef != null).forEach(typedef -> {
+ final Type type = ((TypeProviderImpl) typeProvider).generatedTypeForExtendedDefinitionType(typedef,
+ typedef);
+ if (type != null) {
+ final ModuleContext ctx = genCtx.get(module);
+ ctx.addTypedefType(typedef.getPath(), type);
+ ctx.addTypeToSchema(type, typedef);
+ }
+ });
+ return genCtx;
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2016 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.binding2.generator.impl.util;
+
+import static com.google.common.base.Preconditions.checkArgument;
+
+import com.google.common.annotations.Beta;
+import com.google.common.base.CharMatcher;
+import com.google.common.base.Preconditions;
+import com.google.common.base.Splitter;
+import com.google.common.base.Strings;
+import com.google.common.collect.Iterables;
+import java.util.Map;
+import java.util.StringTokenizer;
+import java.util.regex.Pattern;
+import org.opendaylight.mdsal.binding2.generator.util.Types;
+import org.opendaylight.mdsal.binding2.model.api.GeneratedType;
+import org.opendaylight.mdsal.binding2.model.api.ParameterizedType;
+import org.opendaylight.mdsal.binding2.model.api.Type;
+import org.opendaylight.mdsal.binding2.model.api.WildcardType;
+import org.opendaylight.yangtools.yang.common.QName;
+
+/**
+ * Util class
+ */
+@Beta
+public final class YangTextTemplate {
+ private static final CharMatcher NEWLINE_OR_TAB = CharMatcher.anyOf("\n\t");
+ private static final String DOT = ".";
+ private static final String COMMA = ",";
+ private static final char NEW_LINE = '\n';
+ private static final CharMatcher NL_MATCHER = CharMatcher.is(NEW_LINE);
+ private static final CharMatcher AMP_MATCHER = CharMatcher.is('&');
+ private static final Splitter NL_SPLITTER = Splitter.on(NL_MATCHER);
+ private static final CharMatcher TAB_MATCHER = CharMatcher.is('\t');
+ private static final Pattern SPACES_PATTERN = Pattern.compile(" +");
+
+ private YangTextTemplate() {
+ throw new UnsupportedOperationException("Util class");
+ }
+
+ public static String formatSchemaPath(final String moduleName, final Iterable<QName> schemaPath) {
+ final StringBuilder sb = new StringBuilder();
+ sb.append(moduleName);
+
+ QName currentElement = Iterables.getFirst(schemaPath, null);
+ for (QName pathElement : schemaPath) {
+ sb.append('/');
+ if (!currentElement.getNamespace().equals(pathElement.getNamespace())) {
+ currentElement = pathElement;
+ sb.append(pathElement);
+ } else {
+ sb.append(pathElement.getLocalName());
+ }
+ }
+ return sb.toString();
+ }
+
+ /**
+ * Used in #yangtemplateformodule.scala.txt for formating revision description
+ *
+ * @param text Content of tag description
+ * @param nextLineIndent Number of spaces from left side default is 12
+ * @return formatted description
+ */
+ public static String formatToParagraph(final String text, final int nextLineIndent) {
+ if (Strings.isNullOrEmpty(text)) {
+ return "";
+ }
+ boolean isFirstElementOnNewLineEmptyChar = false;
+ final StringBuilder sb = new StringBuilder();
+ final StringBuilder lineBuilder = new StringBuilder();
+ final String lineIndent = Strings.repeat(" ", nextLineIndent);
+ final String textToFormat = NEWLINE_OR_TAB.removeFrom(text);
+ final String formattedText = textToFormat.replaceAll(" +", " ");
+ final StringTokenizer tokenizer = new StringTokenizer(formattedText, " ", true);
+
+ while (tokenizer.hasMoreElements()) {
+ final String nextElement = tokenizer.nextElement().toString();
+
+ if (lineBuilder.length() + nextElement.length() > 80) {
+ // Trim trailing whitespace
+ for (int i = lineBuilder.length() - 1; i >= 0 && lineBuilder.charAt(i) != ' '; --i) {
+ lineBuilder.setLength(i);
+ }
+ // Trim leading whitespace
+ while (lineBuilder.charAt(0) == ' ') {
+ lineBuilder.deleteCharAt(0);
+ }
+ sb.append(lineBuilder).append('\n');
+ lineBuilder.setLength(0);
+
+ if (nextLineIndent > 0) {
+ sb.append(lineIndent);
+ }
+
+ if (" ".equals(nextElement)) {
+ isFirstElementOnNewLineEmptyChar = true;
+ }
+ }
+ if (isFirstElementOnNewLineEmptyChar) {
+ isFirstElementOnNewLineEmptyChar = false;
+ } else {
+ lineBuilder.append(nextElement);
+ }
+ }
+ return sb.append(lineBuilder).append('\n').toString();
+ }
+
+ /**
+ * Used in all yangtemplates for formating augmentation target
+ *
+ * @param schemaPath path to augmented node
+ * @return path in string format
+ */
+ public static String formatToAugmentPath(final Iterable<QName> schemaPath) {
+ final StringBuilder sb = new StringBuilder();
+ for (QName pathElement : schemaPath) {
+ sb.append("\\(")
+ .append(pathElement.getNamespace())
+ .append(')')
+ .append(pathElement.getLocalName());
+ }
+ return sb.toString();
+ }
+
+ /**
+ * Evaluates if it is necessary to add the package name for type to the map of imports for parentGenType
+ * If it is so the package name is saved to the map imports.
+ *
+ * @param parentGenType generated type for which is the map of necessary imports build
+ * @param type JAVA type for which is the necessary of the package import evaluated
+ * @param imports map of the imports for parentGenType
+ */
+ public static void putTypeIntoImports(final GeneratedType parentGenType, final Type type,
+ final Map<String, String> imports) {
+ checkArgument(parentGenType != null, "Parent Generated Type parameter MUST be specified and cannot be NULL!");
+ checkArgument(type != null, "Type parameter MUST be specified and cannot be NULL!");
+ checkArgument(parentGenType.getPackageName() != null,
+ "Parent Generated Type cannot have Package Name referenced as NULL!");
+
+ final String typeName = Preconditions.checkNotNull(type.getName());
+ final String typePackageName = Preconditions.checkNotNull(type.getPackageName());
+ final String parentTypeName = Preconditions.checkNotNull(parentGenType.getName());
+ if (typeName.equals(parentTypeName) || typePackageName.startsWith("java.lang") || typePackageName.isEmpty()) {
+ return;
+ }
+ if (!imports.containsKey(typeName)) {
+ imports.put(typeName, typePackageName);
+ }
+ if (type instanceof ParameterizedType) {
+ final ParameterizedType paramType = (ParameterizedType) type;
+ final Type[] params = paramType.getActualTypeArguments();
+ if (params != null) {
+ for (Type param : params) {
+ putTypeIntoImports(parentGenType, param, imports);
+ }
+ }
+ }
+ }
+
+ /**
+ * Builds the string which contains either the full path to the type (package name with type) or only type name
+ * if the package is among imports.
+ *
+ * @param parentGenType generated type which contains type
+ * @param type JAVA type for which is the string with type info generated
+ * @param imports map of necessary imports for parentGenType
+ * @return string with type name for type in the full format or in the short format
+ */
+ public static String getExplicitType(final GeneratedType parentGenType, final Type type,
+ final Map<String, String> imports) {
+ checkArgument(type != null, "Type parameter MUST be specified and cannot be NULL!");
+ checkArgument(imports != null, "Imports Map cannot be NULL!");
+
+ final String typePackageName = Preconditions.checkNotNull(type.getPackageName());
+ final String typeName = Preconditions.checkNotNull(type.getName());
+ final String importedPackageName = imports.get(typeName);
+ final StringBuilder builder;
+ if (typePackageName.equals(importedPackageName)) {
+ builder = new StringBuilder(typeName);
+ addActualTypeParameters(builder, type, parentGenType, imports);
+ if (builder.toString().equals("Void")) {
+ return "void";
+ }
+ } else {
+ builder = new StringBuilder();
+ if (!typePackageName.isEmpty()) {
+ builder.append(typePackageName + DOT + typeName);
+ } else {
+ builder.append(type.getName());
+ }
+ if (type.equals(Types.voidType())) {
+ return "void";
+ }
+ addActualTypeParameters(builder, type, parentGenType, imports);
+ }
+ return builder.toString();
+ }
+
+ /**
+ * Adds actual type parameters from type to builder if type is ParametrizedType.
+ *
+ * @param builder string builder which contains type name
+ * @param type JAVA Type for which is the string with type info generated
+ * @param parentGenType generated type which contains type
+ * @param imports map of necessary imports for parentGenType
+ * @return adds actual type parameters to builder
+ */
+ private static StringBuilder addActualTypeParameters(final StringBuilder builder, final Type type,
+ final GeneratedType parentGenType, final Map<String, String> imports) {
+ if (type instanceof ParameterizedType) {
+ final ParameterizedType pType = (ParameterizedType) type;
+ final Type[] pTypes = pType.getActualTypeArguments();
+ builder.append("<");
+ builder.append(getParameters(parentGenType, pTypes, imports));
+ builder.append(">");
+ }
+ return builder;
+ }
+
+ /**
+ * Generates the string with all actual type parameters from
+ *
+ * @param parentGenType generated type for which is the JAVA code generated
+ * @param pTypes array of Type instances = actual type parameters
+ * @param availableImports map of imports for parentGenType
+ * @return string with all actual type parameters from pTypes
+ */
+ private static String getParameters(final GeneratedType parentGenType, final Type[] pTypes,
+ final Map<String, String> availableImports) {
+ if (pTypes == null || pTypes.length == 0) {
+ return "?";
+ }
+ final StringBuilder builder = new StringBuilder();
+ for (int i = 0; i < pTypes.length; i++) {
+ final Type t = pTypes[i];
+
+ String separator = COMMA;
+ if (i == (pTypes.length - 1)) {
+ separator = "";
+ }
+
+ String wildcardParam = "";
+ if (t.equals(Types.voidType())) {
+ builder.append("java.lang.Void")
+ .append(separator);
+ continue;
+ } else {
+
+ if (t instanceof WildcardType) {
+ wildcardParam = "? extends ";
+ }
+
+ builder.append(wildcardParam)
+ .append(getExplicitType(parentGenType, t, availableImports) + separator);
+ }
+ }
+ return builder.toString();
+ }
+
+ /**
+ * Wraps text as documentation
+ *
+ * @param text text for wrapping
+ * @return wrapped text
+ */
+ public static String wrapToDocumentation(String text) {
+ if (text.isEmpty()) {
+ return "";
+ }
+ final StringBuilder sb = new StringBuilder("/**");
+ sb.append(NEW_LINE);
+ Iterable<String> lineSplitText = NL_SPLITTER.split(text);
+ for (final String t : lineSplitText) {
+ sb.append(" *");
+ if (t.isEmpty()) {
+ sb.append(" ");
+ sb.append(t);
+ }
+ sb.append(NEW_LINE);
+ }
+ sb.append(" */");
+ return sb.toString();
+ }
+
+ public static String encodeJavadocSymbols(String description) {
+ if (description == null || description.isEmpty()) {
+ return description;
+ }
+ String ret = description.replace("*/", "*/");
+ return AMP_MATCHER.replaceFrom(ret, "&");
+ }
+}
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright (c) 2016 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.binding2.generator.yang.types;
+
+import static org.opendaylight.yangtools.yang.model.util.SchemaContextUtil.findParentModule;
+
+import com.google.common.annotations.Beta;
+import com.google.common.base.Preconditions;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+import org.opendaylight.mdsal.binding2.generator.spi.TypeProvider;
+import org.opendaylight.mdsal.binding2.model.api.Restrictions;
+import org.opendaylight.mdsal.binding2.model.api.Type;
+import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.Module;
+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.IdentityrefTypeDefinition;
+import org.opendaylight.yangtools.yang.model.api.type.LeafrefTypeDefinition;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+@Beta
+public final class TypeProviderImpl implements TypeProvider {
+
+ private static final Logger LOG = LoggerFactory.getLogger(TypeProviderImpl.class);
+
+ /**
+ * Contains the schema data red from YANG files.
+ */
+ private final SchemaContext schemaContext;
+
+ /**
+ * Map<moduleName, Map<moduleDate, Map<typeName, type>>>
+ */
+ private final Map<String, Map<Date, Map<String, Type>>> genTypeDefsContextMap;
+
+ private final Map<Module, Set<Type>> additionalTypes;
+ /**
+ * Creates new instance of class <code>TypeProviderImpl</code>.
+ *
+ * @param schemaContext
+ * contains the schema data red from YANG files
+ * @throws IllegalArgumentException
+ * if <code>schemaContext</code> equal null.
+ */
+ public TypeProviderImpl(final SchemaContext schemaContext) {
+ this.schemaContext = schemaContext;
+ this.genTypeDefsContextMap = new HashMap<>();
+ this.additionalTypes = new HashMap<>();
+ }
+
+ @Override
+ public Type javaTypeForSchemaDefinitionType(TypeDefinition<?> type, SchemaNode parentNode) {
+ return null;
+ }
+
+ @Override
+ public Type javaTypeForSchemaDefinitionType(TypeDefinition<?> type, SchemaNode parentNode, Restrictions restrictions) {
+ return null;
+ }
+
+ @Override
+ public String getTypeDefaultConstruction(LeafSchemaNode node) {
+ return null;
+ }
+
+ @Override
+ public String getConstructorPropertyName(SchemaNode node) {
+ return null;
+ }
+
+ @Override
+ public String getParamNameFromType(TypeDefinition<?> type) {
+ return null;
+ }
+
+ /**
+ * Converts <code>typeDefinition</code> to concrete JAVA <code>Type</code>.
+ *
+ * @param typeDefinition
+ * type definition which should be converted to JAVA
+ * <code>Type</code>
+ * @return JAVA <code>Type</code> which represents
+ * <code>typeDefinition</code>
+ * @throws IllegalArgumentException
+ * <ul>
+ * <li>if <code>typeDefinition</code> equal null</li>
+ * <li>if Q name of <code>typeDefinition</code></li>
+ * <li>if name of <code>typeDefinition</code></li>
+ * </ul>
+ */
+ public Type generatedTypeForExtendedDefinitionType(final TypeDefinition<?> typeDefinition, final SchemaNode parentNode) {
+ Preconditions.checkArgument(typeDefinition != null, "Type Definition cannot be NULL!");
+ if (typeDefinition.getQName() == null) {
+ throw new IllegalArgumentException(
+ "Type Definition cannot have non specified QName (QName cannot be NULL!)");
+ }
+ Preconditions.checkArgument(typeDefinition.getQName().getLocalName() != null,
+ "Type Definitions Local Name cannot be NULL!");
+
+ final TypeDefinition<?> baseTypeDef = baseTypeDefForExtendedType(typeDefinition);
+ if (!(baseTypeDef instanceof LeafrefTypeDefinition) && !(baseTypeDef instanceof IdentityrefTypeDefinition)) {
+ final Module module = findParentModule(schemaContext, parentNode);
+
+ if (module != null) {
+ final Map<Date, Map<String, Type>> modulesByDate = genTypeDefsContextMap.get(module.getName());
+ final Map<String, Type> genTOs = modulesByDate.get(module.getRevision());
+ if (genTOs != null) {
+ return genTOs.get(typeDefinition.getQName().getLocalName());
+ }
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Gets base type definition for <code>extendTypeDef</code>. The method is
+ * recursively called until non <code>ExtendedType</code> type is found.
+ *
+ * @param extendTypeDef
+ * type definition for which is the base type definition sought
+ * @return type definition which is base type for <code>extendTypeDef</code>
+ * @throws IllegalArgumentException
+ * if <code>extendTypeDef</code> equal null
+ */
+ private static TypeDefinition<?> baseTypeDefForExtendedType(final TypeDefinition<?> extendTypeDef) {
+ Preconditions.checkArgument(extendTypeDef != null, "Type Definition reference cannot be NULL!");
+
+ TypeDefinition<?> ret = extendTypeDef;
+ while (ret.getBaseType() != null) {
+ ret = ret.getBaseType();
+ }
+
+ return ret;
+ }
+
+ public Map<Module, Set<Type>> getAdditionalTypes() {
+ return additionalTypes;
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2016 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.binding2;
+
+import com.google.common.annotations.Beta;
+import java.io.File;
+import java.net.URI;
+import java.util.Set;
+import org.opendaylight.yangtools.yang.model.api.Module;
+import org.opendaylight.yangtools.yang.parser.spi.meta.ReactorException;
+import org.opendaylight.yangtools.yang.parser.spi.source.SourceException;
+import org.opendaylight.yangtools.yang.parser.stmt.reactor.CrossSourceStatementReactor;
+import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.YangInferencePipeline;
+import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.YangStatementSourceImpl;
+import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.effective.EffectiveSchemaContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+@Beta
+public final class TestUtils {
+
+ private static final Logger LOG = LoggerFactory.getLogger(TestUtils.class);
+
+ private TestUtils() {
+ throw new UnsupportedOperationException("Utility class");
+ }
+
+ public static Set<Module> loadModules(final URI resourceDirectory)
+ throws SourceException, ReactorException {
+ final CrossSourceStatementReactor.BuildAction reactor = YangInferencePipeline.RFC6020_REACTOR
+ .newBuild();
+ File[] files = new File(resourceDirectory).listFiles();
+
+ for (File file : files) {
+ if (file.getName().endsWith(".yang")) {
+ addSources(reactor, new YangStatementSourceImpl(file.getPath(), true));
+ } else {
+ LOG.info("Ignoring non-yang file {}", file);
+ }
+ }
+
+ EffectiveSchemaContext ctx = reactor.buildEffective();
+ return ctx.getModules();
+ }
+
+ private static void addSources(final CrossSourceStatementReactor.BuildAction reactor,
+ final YangStatementSourceImpl... sources) {
+ for (YangStatementSourceImpl source : sources) {
+ reactor.addSource(source);
+ }
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2016 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.binding2;
+
+import com.google.common.annotations.Beta;
+import java.net.URISyntaxException;
+import java.util.Set;
+import org.junit.Before;
+import org.junit.Test;
+import org.opendaylight.mdsal.binding2.txt.yangTemplateForModule;
+import org.opendaylight.mdsal.binding2.txt.yangTemplateForNode;
+import org.opendaylight.mdsal.binding2.txt.yangTemplateForNodes;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.Module;
+import org.opendaylight.yangtools.yang.parser.spi.meta.ReactorException;
+
+@Beta
+public class YangTemplateTest {
+
+ private Set<Module> modules;
+
+ @Before
+ public void setup() throws URISyntaxException, ReactorException {
+ modules = TestUtils.loadModules(getClass().getResource("/yang-template").toURI());
+ }
+
+ @Test
+ public void printYangSnippetForModule() {
+ for (Module module : modules) {
+ /**
+ * We should be able to call Scala render method from Binding Generator implementation
+ * for 3 different inputs:
+ * 1. single SchemaNode
+ * 2. set of SchemaNode
+ * 3. whole Module
+ */
+ final String moduleBody = yangTemplateForModule.render(module).body();
+ //FIXME: don't do it this way, only for very first attempt to show results
+ System.out.println("module ".concat(module.getName()).concat(":").concat(moduleBody));
+
+ //TODO: finish following sections
+ for (DataSchemaNode dataSchemaNode : module.getChildNodes()) {
+ final String nodeBody = yangTemplateForNode.render(dataSchemaNode).body();
+ }
+
+ final String rpcsBody = yangTemplateForNodes.render(module.getRpcs()).body();
+ final String notificationsBody = yangTemplateForNodes.render(module.getNotifications()).body();
+
+ //////////
+ }
+
+ }
+}
--- /dev/null
+module yang-template-import {
+ yang-version 1;
+ namespace "org.opendaylight.yang.template";
+ prefix "yti";
+
+ revision 2016-06-23 {
+ description "Simple yang missing deviation statement";
+ }
+
+ leaf yti-leaf {
+ type string;
+ }
+}
\ No newline at end of file
--- /dev/null
+module yang-template-test {
+ yang-version 1;
+ namespace "org.opendaylight.yang.template";
+ prefix "ytemp";
+
+ revision 2016-01-01 {
+ description "Simple yang missing deviation statement";
+ }
+
+ import yang-template-import { prefix yti; revision-date 2016-06-23; }
+
+ typedef simple-typedef {
+ type string;
+ default "simple-typedef";
+ }
+
+ container simple-container {
+ }
+
+ leaf simple-leaf {
+ type string;
+ }
+
+ leaf-list simple-leaf-list {
+ type string;
+ }
+
+ leaf-list simple-leaf-list-userordered {
+ ordered-by user;
+ type string;
+ }
+
+ list simple-list {
+ key "simple-list-leaf-1";
+ unique "simple-list-leaf-2";
+ leaf simple-list-leaf-1 {
+ type string;
+ }
+ leaf simple-list-leaf-2 {
+ type string;
+ }
+ }
+
+ list simple-list-userordered {
+ ordered-by user;
+ key "simple-list-userordered-leaf-1";
+ unique "simple-list-userordered-leaf-2";
+ leaf simple-list-userordered-leaf-1 {
+ type string;
+ }
+ leaf simple-list-userordered-leaf-2 {
+ type string;
+ }
+ }
+
+ choice simple-choice {
+ case simple-case-1 {
+ leaf simple-case-1-leaf {
+ type string;
+ }
+ }
+ case simple-case-2 {
+ leaf simple-case-2-leaf {
+ type string;
+ }
+ }
+ }
+
+ anyxml simple-anyxml;
+
+ grouping simple-grouping {
+ leaf simple-grouping-leaf {
+ description "simple-grouping-leaf description";
+ type string;
+ }
+ }
+
+ container simple-container-uses {
+ uses simple-grouping {
+ refine simple-grouping-leaf {
+ description "refined simple-grouping-leaf description";
+ }
+ }
+ }
+
+ rpc simple-rpc {
+ input {
+ leaf rpc-input-leaf {
+ type string;
+ }
+ }
+ }
+
+ notification simple-notification {
+ leaf notification-leaf {
+ type string;
+ }
+ }
+
+ augment "/simple-container-uses" {
+ leaf augment-leaf {
+ type string;
+ }
+ }
+
+ identity simple-identity {
+ description "simple-identity";
+ }
+
+ extension simple-extension {
+ description "simple-extension";
+ argument "simple-extension-argument";
+ }
+
+ feature simple-feature {
+ description "simple-feature definex if device has some feature... hdd";
+ }
+}
\ No newline at end of file
--- /dev/null
+@*
+ * Copyright (c) 2016 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
+ *@
+
+@**********************************************************
+* Twirl YangTemplate for generating yang snippets. *
+* Twirl is transformed to Scala and compiled. Then, *
+* it can be called from Java with particular input *
+* parameters to render desired output code. *
+* *
+* Note: we should introduce our own format instead of txt *
+***********************************************************@
+
+@import org.opendaylight.mdsal.binding2.generator.impl.util.YangTextTemplate
+@import org.opendaylight.yangtools.yang.common.SimpleDateFormatUtil
+@import org.opendaylight.yangtools.yang.model.api.Module
+
+@(module: Module)
+@if(module != null) {
+ @generateYangSnippet(module)
+}
+
+@generateYangSnippet(module: Module) = {
+ module @{module.getName()} {
+ yang-version @module.getYangVersion();
+ namespace "@module.getNamespace().toString()";
+ prefix "@module.getPrefix()";
+
+ @if(module.getImports() != null && !module.getImports().isEmpty()) {
+ @for(moduleImport <- module.getImports()) {
+ @if(moduleImport != null && !moduleImport.getModuleName()) {
+ import @{moduleImport.getModuleName()} { prefix "@{moduleImport.getPrefix()}"; }
+ }
+ }
+ }
+ @if(module.getRevision() != null) {
+ revision @{SimpleDateFormatUtil.getRevisionFormat().format(module.getRevision())} {
+ description "@{YangTextTemplate.formatToParagraph(module.getDescription(), 12)}";
+ }
+ }
+ @if(module.getChildNodes() != null) {
+ @yangTemplateWriteDataSchemaNodes(module.getChildNodes())
+ }
+ @if(module.getGroupings() != null && !module.getGroupings().isEmpty()) {
+ @yangTemplateWriteGroupingDefs(module.getGroupings())
+ }
+ @if(module.getAugmentations() != null && !module.getAugmentations().isEmpty()) {
+ @yangTemplateWriteAugments(module.getAugmentations())
+ }
+ @if(module.getDeviations() != null && !module.getDeviations().isEmpty()) {
+ @for(deviation <- module.getDeviations()) {
+ @if(deviation != null) {
+ deviation @{deviation.getTargetPath()} {
+ @if(deviation.getReference() != null && !deviation.getReference().isEmpty()) {
+ reference "@{deviation.getReference()}";
+ }
+ @for(deviation <- deviation.getDeviates()) {
+ @if(deviation != null && deviation.getDeviateType() != null ) {
+ deviation @{deviation.getDeviateType().name()};
+ }
+ }
+ }
+ }
+ }
+ }
+ @if(module.getExtensionSchemaNodes() != null && !module.getExtensionSchemaNodes().isEmpty()) {
+ @for(extension <- module.getExtensionSchemaNodes()) {
+ @if(extension != null) {
+ @yangTemplateWriteExtension(extension)
+ }
+ }
+ }
+ @if(module.getFeatures() != null && !module.getFeatures().isEmpty()) {
+ @for(feature <- module.getFeatures()) {
+ @if(feature != null) {
+ @yangTemplateWriteFeature(feature)
+ }
+ }
+ }
+ @if(module.getIdentities() != null && !module.getIdentities().isEmpty()) {
+ @for(identity <- module.getIdentities()) {
+ @if(identity != null) {
+ @yangTemplateWriteIdentity(identity)
+ }
+ }
+ }
+ @if(module.getNotifications() != null && !module.getNotifications().isEmpty()) {
+ @for(notification <- module.getNotifications()) {
+ @if(notification != null) {
+ @yangTemplateWriteNotification(notification)
+ }
+ }
+ }
+ @if(module.getRpcs() != null && !module.getRpcs().isEmpty()) {
+ @for(rpc <- module.getRpcs()) {
+ @if(rpc != null) {
+ @yangTemplateWriteRPC(rpc)
+ }
+ }
+ }
+ @if(module.getUnknownSchemaNodes() != null && !module.getUnknownSchemaNodes().isEmpty()) {
+ @yangTemplateWriteUnknownSchemaNodes(module.getUnknownSchemaNodes())
+ }
+ @if(module.getUses() != null && !module.getUses().isEmpty()) {
+ @yangTemplateWriteUsesNodes(module.getUses())
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+@*
+ * Copyright (c) 2016 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
+ *@
+
+@**********************************************************
+* Twirl YangTemplate for generating yang snippets. *
+* Twirl is transformed to Scala and compiled. Then, *
+* it can be called from Java with particular input *
+* parameters to render desired output code. *
+* *
+* Note: we should introduce our own format instead of txt *
+***********************************************************@
+
+@import org.opendaylight.yangtools.yang.model.api.DataSchemaNode
+@import org.opendaylight.yangtools.yang.model.api.ExtensionDefinition
+@import org.opendaylight.yangtools.yang.model.api.FeatureDefinition
+@import org.opendaylight.yangtools.yang.model.api.GroupingDefinition
+@import org.opendaylight.yangtools.yang.model.api.IdentitySchemaNode
+@import org.opendaylight.yangtools.yang.model.api.NotificationDefinition
+@import org.opendaylight.yangtools.yang.model.api.RpcDefinition
+@import org.opendaylight.yangtools.yang.model.api.SchemaNode
+@import org.opendaylight.yangtools.yang.model.api.TypeDefinition
+@import org.opendaylight.yangtools.yang.model.api.UnknownSchemaNode
+@import org.opendaylight.yangtools.yang.model.api.Status
+@import org.opendaylight.yangtools.yang.model.api.`type`.EnumTypeDefinition
+@import org.opendaylight.yangtools.yang.model.api.`type`.EnumTypeDefinition.EnumPair
+
+@(node: SchemaNode)
+@if(node != null) {
+ @generateYangSnippet(node)
+}
+
+@generateYangSnippet(node: SchemaNode) = {
+ @if(node.isInstanceOf[DataSchemaNode]) {
+ @yangTemplateWriteDataSchemaNode(node.asInstanceOf[DataSchemaNode])
+ }
+ @if(node.isInstanceOf[EnumTypeDefinition.EnumPair]) {
+ enum @{node.asInstanceOf[EnumTypeDefinition.EnumPair].getName()} {
+ @if(node.asInstanceOf[EnumTypeDefinition.EnumPair].getValue() != null) {
+ value @{node.asInstanceOf[EnumTypeDefinition.EnumPair].getValue()};
+ } else {
+ ;
+ }
+ }
+ }
+ @if(node.isInstanceOf[ExtensionDefinition]) {
+ @yangTemplateWriteExtension(node.asInstanceOf[ExtensionDefinition])
+ }
+ @if(node.isInstanceOf[FeatureDefinition]) {
+ @yangTemplateWriteFeature(node.asInstanceOf[FeatureDefinition])
+ }
+ @if(node.isInstanceOf[GroupingDefinition]) {
+ @yangTemplateWriteGroupingDef(node.asInstanceOf[GroupingDefinition])
+ }
+ @if(node.isInstanceOf[IdentitySchemaNode]) {
+ @yangTemplateWriteIdentity(node.asInstanceOf[IdentitySchemaNode])
+ }
+ @if(node.isInstanceOf[NotificationDefinition]) {
+ @yangTemplateWriteNotification(node.asInstanceOf[NotificationDefinition])
+ }
+ @if(node.isInstanceOf[RpcDefinition]) {
+ @yangTemplateWriteRPC(node.asInstanceOf[RpcDefinition])
+ }
+ @if(node.isInstanceOf[TypeDefinition[_]]) {
+ type @{node.asInstanceOf[TypeDefinition[_]].getQName().getLocalName()}
+ @if(node.asInstanceOf[TypeDefinition[_]].getStatus() != Status.CURRENT) {
+ status @{node.asInstanceOf[TypeDefinition[_]].getStatus()};
+ } else {
+ ;
+ }
+ }
+ @if(node.isInstanceOf[UnknownSchemaNode]) {
+ @yangTemplateWriteUnknownSchemaNode(node.asInstanceOf[UnknownSchemaNode])
+ }
+}
\ No newline at end of file
--- /dev/null
+@*
+ * Copyright (c) 2016 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
+ *@
+
+@**********************************************************
+* Twirl YangTemplate for generating yang snippets. *
+* Twirl is transformed to Scala and compiled. Then, *
+* it can be called from Java with particular input *
+* parameters to render desired output code. *
+* *
+* Note: we should introduce our own format instead of txt *
+***********************************************************@
+
+@import org.opendaylight.yangtools.yang.model.api.NotificationDefinition
+@import org.opendaylight.yangtools.yang.model.api.RpcDefinition
+@import org.opendaylight.yangtools.yang.model.api.SchemaNode
+
+@(nodes: Set[_ <: SchemaNode])
+@if(nodes != null) {
+ @for(node <- nodes) {
+ @if(node.isInstanceOf[NotificationDefinition]) {
+ @yangTemplateWriteNotification(node.asInstanceOf[NotificationDefinition])
+ }
+ @if(node.isInstanceOf[RpcDefinition]) {
+ @yangTemplateWriteRPC(node.asInstanceOf[RpcDefinition])
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+@*
+ * Copyright (c) 2016 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
+ *@
+
+@**********************************************************
+* Twirl YangTemplate for generating yang snippets. *
+* Twirl is transformed to Scala and compiled. Then, *
+* it can be called from Java with particular input *
+* parameters to render desired output code. *
+* *
+* Note: we should introduce our own format instead of txt *
+***********************************************************@
+
+@import org.opendaylight.mdsal.binding2.generator.impl.util.YangTextTemplate
+@import org.opendaylight.yangtools.yang.model.api.AugmentationSchema
+
+@(augments: Set[_ <: AugmentationSchema])
+@for(augment <- augments) {
+ @if(augment != null) {
+ augment @{YangTextTemplate.formatToAugmentPath(augment.getTargetPath().getPathFromRoot())} {
+ @if(augment.getWhenCondition() != null && !augment.getWhenCondition().toString().isEmpty()) {
+ when "@augment.getWhenCondition().toString()";
+ }
+ @if(augment.getDescription() != null && !augment.getDescription().isEmpty()) {
+ description "@augment.getDescription().toString()";
+ }
+ @if(augment.getReference() != null && !augment.getReference().isEmpty()) {
+ reference "@augment.getReference().toString()";
+ }
+ @if(augment.getStatus() != null) {
+ status "@augment.getStatus()";
+ }
+ @if(augment.getChildNodes() != null && !augment.getChildNodes().isEmpty()) {
+ @yangTemplateWriteDataSchemaNodes(augment.getChildNodes())
+ }
+ @if(augment.getUses() != null && !augment.getUses().isEmpty()) {
+ @yangTemplateWriteUsesNodes(augment.getUses())
+ }
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+@*
+ * Copyright (c) 2016 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
+ *@
+
+@**********************************************************
+* Twirl YangTemplate for generating yang snippets. *
+* Twirl is transformed to Scala and compiled. Then, *
+* it can be called from Java with particular input *
+* parameters to render desired output code. *
+* *
+* Note: we should introduce our own format instead of txt *
+***********************************************************@
+
+@import org.opendaylight.yangtools.yang.model.api.AnyXmlSchemaNode
+@import org.opendaylight.yangtools.yang.model.api.ChoiceCaseNode
+@import org.opendaylight.yangtools.yang.model.api.ChoiceSchemaNode
+@import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode
+@import org.opendaylight.yangtools.yang.model.api.DataSchemaNode
+@import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode
+@import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode
+@import org.opendaylight.yangtools.yang.model.api.ListSchemaNode
+@import org.opendaylight.yangtools.yang.model.api.SchemaNode
+@import org.opendaylight.yangtools.yang.model.api.Status
+@import org.opendaylight.yangtools.yang.model.api.UnknownSchemaNode
+
+@(dataSchemaNode: DataSchemaNode)
+@if(dataSchemaNode.isInstanceOf[ContainerSchemaNode]) {
+ @writeContSchemaNode(dataSchemaNode.asInstanceOf[ContainerSchemaNode])
+}
+@if(dataSchemaNode.isInstanceOf[AnyXmlSchemaNode]) {
+ anyxml @{dataSchemaNode.asInstanceOf[AnyXmlSchemaNode].getQName().getLocalName()}
+ @if(dataSchemaNode.asInstanceOf[AnyXmlSchemaNode].getStatus() != Status.CURRENT) {
+ ;
+ } else {
+ {
+ status @{dataSchemaNode.asInstanceOf[AnyXmlSchemaNode].getStatus()};
+ }
+ }
+}
+@if(dataSchemaNode.isInstanceOf[LeafSchemaNode]) {
+ leaf @{dataSchemaNode.asInstanceOf[LeafSchemaNode].getQName().getLocalName()} {
+ type @{dataSchemaNode.asInstanceOf[LeafSchemaNode].getType().getQName().getLocalName()};
+ }
+ @if(dataSchemaNode.asInstanceOf[LeafSchemaNode].getStatus() != Status.CURRENT) {
+ status @{dataSchemaNode.asInstanceOf[LeafSchemaNode].getStatus()};
+ }
+}
+@if(dataSchemaNode.isInstanceOf[LeafListSchemaNode]) {
+ leaf-list @{dataSchemaNode.asInstanceOf[LeafListSchemaNode].getQName().getLocalName()} {
+ type @{dataSchemaNode.asInstanceOf[LeafListSchemaNode].getType().getQName().getLocalName()};
+ }
+ @if(dataSchemaNode.asInstanceOf[LeafListSchemaNode].getStatus() != Status.CURRENT) {
+ status @{dataSchemaNode.asInstanceOf[LeafListSchemaNode].getStatus()};
+ }
+}
+@if(dataSchemaNode.isInstanceOf[ChoiceCaseNode]) {
+ case @{dataSchemaNode.asInstanceOf[ChoiceCaseNode].getQName().getLocalName()} {
+ @for(childNode <- dataSchemaNode.asInstanceOf[ChoiceCaseNode].getChildNodes()) {
+ @yangTemplateWriteDataSchemaNode(childNode)
+ }
+ }
+ @if(dataSchemaNode.asInstanceOf[ChoiceCaseNode].getStatus() != Status.CURRENT) {
+ status @{dataSchemaNode.asInstanceOf[ChoiceCaseNode].getStatus()};
+ }
+}
+@if(dataSchemaNode.isInstanceOf[ChoiceSchemaNode]) {
+ choice @{dataSchemaNode.asInstanceOf[ChoiceSchemaNode].getQName().getLocalName()} {
+ @for(childNode <- dataSchemaNode.asInstanceOf[ChoiceSchemaNode].getCases()) {
+ @yangTemplateWriteDataSchemaNode(childNode)
+ }
+ }
+ @if(dataSchemaNode.asInstanceOf[ChoiceSchemaNode].getStatus() != Status.CURRENT) {
+ status @{dataSchemaNode.asInstanceOf[ChoiceSchemaNode].getStatus()};
+ }
+}
+@if(dataSchemaNode.isInstanceOf[ListSchemaNode]) {
+ @writeListSchemaNode(dataSchemaNode.asInstanceOf[ListSchemaNode])
+}
+
+@writeContSchemaNode(container: ContainerSchemaNode) = {
+ container @{container.getQName().getLocalName()} {
+ @if(container.getChildNodes() != null && !container.getChildNodes().isEmpty()) {
+ @yangTemplateWriteDataSchemaNodes(container.getChildNodes())
+ }
+ @if(container.getAvailableAugmentations() != null && !container.getAvailableAugmentations().isEmpty()) {
+ @yangTemplateWriteAugments(container.getAvailableAugmentations())
+ }
+ @if(container.getGroupings() != null && !container.getGroupings().isEmpty()) {
+ @yangTemplateWriteGroupingDefs(container.getGroupings())
+ }
+ @if(container.getUses() != null && !container.getUses().isEmpty()) {
+ @yangTemplateWriteUsesNodes(container.getUses())
+ }
+ @if(container.getStatus() != Status.CURRENT) {
+ status @{container.getStatus()};
+ }
+ @if(container.getUnknownSchemaNodes() != null && !container.getUnknownSchemaNodes().isEmpty()) {
+ @yangTemplateWriteUnknownSchemaNodes(container.getUnknownSchemaNodes())
+ }
+ }
+}
+
+@writeListSchemaNode(list: ListSchemaNode) = {
+ list @{list.getQName().getLocalName()} {
+ key "@for(listKey <- list.getKeyDefinition()) {
+ @{listKey.getLocalName()}
+ }"
+ @if(list.getChildNodes() != null && !list.getChildNodes().isEmpty()) {
+ @yangTemplateWriteDataSchemaNodes(list.getChildNodes())
+ }
+ @if(list.getAvailableAugmentations() != null && !list.getAvailableAugmentations().isEmpty()) {
+ @yangTemplateWriteAugments(list.getAvailableAugmentations())
+ }
+ @if(list.getGroupings() != null && !list.getGroupings().isEmpty()) {
+ @yangTemplateWriteGroupingDefs(list.getGroupings())
+ }
+ @if(list.getUses() != null && !list.getUses().isEmpty()) {
+ @yangTemplateWriteUsesNodes(list.getUses())
+ }
+ @if(list.getStatus() != Status.CURRENT) {
+ status @{list.getStatus()};
+ }
+ @if(list.getUnknownSchemaNodes() != null && !list.getUnknownSchemaNodes().isEmpty()) {
+ @yangTemplateWriteUnknownSchemaNodes(list.getUnknownSchemaNodes())
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+@*
+ * Copyright (c) 2016 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
+ *@
+
+@**********************************************************
+* Twirl YangTemplate for generating yang snippets. *
+* Twirl is transformed to Scala and compiled. Then, *
+* it can be called from Java with particular input *
+* parameters to render desired output code. *
+* *
+* Note: we should introduce our own format instead of txt *
+***********************************************************@
+
+@import org.opendaylight.yangtools.yang.model.api.DataSchemaNode
+
+@(dataSchemaNodes: Collection[_ <: DataSchemaNode])
+@for(dataSchemaNode <- dataSchemaNodes) {
+ @yangTemplateWriteDataSchemaNode(dataSchemaNode)
+}
\ No newline at end of file
--- /dev/null
+@*
+ * Copyright (c) 2016 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
+ *@
+
+@**********************************************************
+* Twirl YangTemplate for generating yang snippets. *
+* Twirl is transformed to Scala and compiled. Then, *
+* it can be called from Java with particular input *
+* parameters to render desired output code. *
+* *
+* Note: we should introduce our own format instead of txt *
+***********************************************************@
+
+@import org.opendaylight.yangtools.yang.model.api.ExtensionDefinition
+
+@(extension: ExtensionDefinition)
+extension @{extension.getQName().getLocalName()} {
+ @if(extension.getDescription() != null && !extension.getDescription().isEmpty()) {
+ description "@{extension.getDescription()}";
+ }
+ @if(extension.getArgument() != null && !extension.getArgument().isEmpty()) {
+ argument "@{extension.getArgument()}";
+ }
+ @if(extension.getReference() != null && !extension.getReference().isEmpty()) {
+ reference "@{extension.getReference()}";
+ }
+ @if(extension.getStatus() != null) {
+ status @{extension.getStatus()};
+ }
+}
\ No newline at end of file
--- /dev/null
+@*
+ * Copyright (c) 2016 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
+ *@
+
+@**********************************************************
+* Twirl YangTemplate for generating yang snippets. *
+* Twirl is transformed to Scala and compiled. Then, *
+* it can be called from Java with particular input *
+* parameters to render desired output code. *
+* *
+* Note: we should introduce our own format instead of txt *
+***********************************************************@
+
+@import org.opendaylight.yangtools.yang.model.api.FeatureDefinition
+
+@(feature: FeatureDefinition)
+feature @{feature.getQName().getLocalName()} {
+ @if(feature.getDescription() != null && !feature.getDescription().isEmpty()) {
+ description "@{feature.getDescription()}";
+ }
+ @if(feature.getReference() != null && !feature.getReference().isEmpty()) {
+ reference "@{feature.getReference()}";
+ }
+ @if(feature.getStatus() != null) {
+ status @{feature.getStatus()};
+ }
+}
\ No newline at end of file
--- /dev/null
+@*
+ * Copyright (c) 2016 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
+ *@
+
+@**********************************************************
+* Twirl YangTemplate for generating yang snippets. *
+* Twirl is transformed to Scala and compiled. Then, *
+* it can be called from Java with particular input *
+* parameters to render desired output code. *
+* *
+* Note: we should introduce our own format instead of txt *
+***********************************************************@
+
+@import org.opendaylight.yangtools.yang.model.api.GroupingDefinition
+@import org.opendaylight.yangtools.yang.model.api.Status
+
+@(groupingDef: GroupingDefinition)
+grouping @{groupingDef.getQName().getLocalName()} {
+ @if(groupingDef.getGroupings() != null && !groupingDef.getGroupings().isEmpty()) {
+ @yangTemplateWriteGroupingDefs(groupingDef.getGroupings())
+ }
+ @if(groupingDef.getChildNodes() != null && !groupingDef.getChildNodes().isEmpty()) {
+ @yangTemplateWriteDataSchemaNodes(groupingDef.getChildNodes())
+ }
+ @if(groupingDef.getStatus() != Status.CURRENT) {
+ status @{groupingDef.getStatus()};
+ }
+ @if(groupingDef.getUnknownSchemaNodes() != null && !groupingDef.getUnknownSchemaNodes().isEmpty()) {
+ @yangTemplateWriteUnknownSchemaNodes(groupingDef.getUnknownSchemaNodes())
+ }
+}
\ No newline at end of file
--- /dev/null
+@*
+ * Copyright (c) 2016 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
+ *@
+
+@**********************************************************
+* Twirl YangTemplate for generating yang snippets. *
+* Twirl is transformed to Scala and compiled. Then, *
+* it can be called from Java with particular input *
+* parameters to render desired output code. *
+* *
+* Note: we should introduce our own format instead of txt *
+***********************************************************@
+
+@import org.opendaylight.yangtools.yang.model.api.GroupingDefinition
+
+@(groupingDefs: Set[_ <: GroupingDefinition])
+@for(groupingDef <- groupingDefs) {
+ @if(groupingDef != null) {
+ @yangTemplateWriteGroupingDef(groupingDef)
+ }
+}
\ No newline at end of file
--- /dev/null
+@*
+ * Copyright (c) 2016 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
+ *@
+
+@**********************************************************
+* Twirl YangTemplate for generating yang snippets. *
+* Twirl is transformed to Scala and compiled. Then, *
+* it can be called from Java with particular input *
+* parameters to render desired output code. *
+* *
+* Note: we should introduce our own format instead of txt *
+***********************************************************@
+
+@import org.opendaylight.yangtools.yang.model.api.IdentitySchemaNode
+
+@(identity: IdentitySchemaNode)
+identity @{identity.getQName().getLocalName()} {
+ @if(identity.getBaseIdentity() != null) {
+ base "(@writeIdentityNs(identity.getBaseIdentity()))@{identity.getBaseIdentity()}";
+ }
+ @if(identity.getDescription() != null && !identity.getDescription().isEmpty()) {
+ description "@{identity.getDescription()}";
+ }
+ @if(identity.getReference() != null && !identity.getReference().isEmpty()) {
+ reference "@{identity.getReference()}";
+ }
+ @if(identity.getStatus() != null) {
+ status @{identity.getStatus()};
+ }
+}
+
+@writeIdentityNs(identity: IdentitySchemaNode) = {
+ @if(identity.getQName().getNamespace() != null) {
+ @{identity.getQName().getNamespace()}:
+ }
+}
\ No newline at end of file
--- /dev/null
+@*
+ * Copyright (c) 2016 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
+ *@
+
+@**********************************************************
+* Twirl YangTemplate for generating yang snippets. *
+* Twirl is transformed to Scala and compiled. Then, *
+* it can be called from Java with particular input *
+* parameters to render desired output code. *
+* *
+* Note: we should introduce our own format instead of txt *
+***********************************************************@
+
+@import org.opendaylight.yangtools.yang.model.api.NotificationDefinition
+@import org.opendaylight.yangtools.yang.model.api.Status
+
+@(notification: NotificationDefinition)
+notification @{notification.getQName().getLocalName()} {
+ @if(notification.getDescription() != null && !notification.getDescription().isEmpty()) {
+ description "@{notification.getDescription()}";
+ }
+ @if(notification.getChildNodes() != null && !notification.getChildNodes().isEmpty()) {
+ @yangTemplateWriteDataSchemaNodes(notification.getChildNodes())
+ }
+ @if(notification.getAvailableAugmentations() != null && !notification.getAvailableAugmentations().isEmpty()) {
+ @yangTemplateWriteAugments(notification.getAvailableAugmentations())
+ }
+ @if(notification.getGroupings() != null && !notification.getGroupings().isEmpty()) {
+ @yangTemplateWriteGroupingDefs(notification.getGroupings())
+ }
+ @if(notification.getUses() != null && !notification.getUses().isEmpty()) {
+ @yangTemplateWriteUsesNodes(notification.getUses())
+ }
+ @if(notification.getReference() != null && !notification.getReference().isEmpty()) {
+ reference "@{notification.getReference()}";
+ }
+ @if(notification.getStatus() != Status.CURRENT) {
+ status @{notification.getStatus()};
+ }
+}
\ No newline at end of file
--- /dev/null
+@*
+ * Copyright (c) 2016 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
+ *@
+
+@**********************************************************
+* Twirl YangTemplate for generating yang snippets. *
+* Twirl is transformed to Scala and compiled. Then, *
+* it can be called from Java with particular input *
+* parameters to render desired output code. *
+* *
+* Note: we should introduce our own format instead of txt *
+***********************************************************@
+
+@import org.opendaylight.yangtools.yang.model.api.RpcDefinition
+@import org.opendaylight.yangtools.yang.model.api.Status
+
+@(rpc: RpcDefinition)
+rpc @{rpc.getQName().getLocalName()} {
+ @if(rpc.getDescription() != null && !rpc.getDescription().isEmpty()) {
+ "@{rpc.getDescription()}";
+ }
+ @if(rpc.getGroupings() != null && !rpc.getGroupings().isEmpty()) {
+ @yangTemplateWriteGroupingDefs(rpc.getGroupings())
+ }
+ @if(rpc.getInput() != null) {
+ input {
+ @if(rpc.getInput().getChildNodes != null && !rpc.getInput().getChildNodes().isEmpty()) {
+ @yangTemplateWriteDataSchemaNodes(rpc.getInput().getChildNodes)
+ }
+ }
+ }
+ @if(rpc.getOutput() != null) {
+ output {
+ @if(rpc.getOutput().getChildNodes != null && !rpc.getOutput().getChildNodes().isEmpty()) {
+ @yangTemplateWriteDataSchemaNodes(rpc.getOutput().getChildNodes)
+ }
+ }
+ }
+ @if(rpc.getReference() != null && !rpc.getReference().isEmpty()) {
+ reference "@{rpc.getReference()}";
+ }
+ @if(rpc.getStatus() != Status.CURRENT) {
+ status @{rpc.getStatus()};
+ }
+}
\ No newline at end of file
--- /dev/null
+@*
+ * Copyright (c) 2016 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
+ *@
+
+@**********************************************************
+* Twirl YangTemplate for generating yang snippets. *
+* Twirl is transformed to Scala and compiled. Then, *
+* it can be called from Java with particular input *
+* parameters to render desired output code. *
+* *
+* Note: we should introduce our own format instead of txt *
+***********************************************************@
+
+@import org.opendaylight.yangtools.yang.model.api.UnknownSchemaNode
+
+@(unknownSchemaNode: UnknownSchemaNode)
+@if(unknownSchemaNode != null) {
+ test
+ @* to do *@
+}
\ No newline at end of file
--- /dev/null
+@*
+ * Copyright (c) 2016 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
+ *@
+
+@**********************************************************
+* Twirl YangTemplate for generating yang snippets. *
+* Twirl is transformed to Scala and compiled. Then, *
+* it can be called from Java with particular input *
+* parameters to render desired output code. *
+* *
+* Note: we should introduce our own format instead of txt *
+***********************************************************@
+
+@import org.opendaylight.yangtools.yang.model.api.UnknownSchemaNode
+
+@(unknownSchemaNodes: List[_ <: UnknownSchemaNode])
+@for(unknownSchemaNode <- unknownSchemaNodes) {
+ @if(unknownSchemaNode != null) {
+ @yangTemplateWriteUnknownSchemaNode(unknownSchemaNode)
+ }
+}
\ No newline at end of file
--- /dev/null
+@*
+ * Copyright (c) 2016 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
+ *@
+
+@**********************************************************
+* Twirl YangTemplate for generating yang snippets. *
+* Twirl is transformed to Scala and compiled. Then, *
+* it can be called from Java with particular input *
+* parameters to render desired output code. *
+* *
+* Note: we should introduce our own format instead of txt *
+***********************************************************@
+
+@import org.opendaylight.yangtools.yang.model.api.DataSchemaNode
+@import org.opendaylight.yangtools.yang.model.api.UsesNode
+
+@(usesNodes: Set[_ <: UsesNode])
+@if(usesNodes != null) {
+ @for(usesNode <- usesNodes) {
+ @if(usesNode != null) {
+ uses @{usesNode.getGroupingPath().getLastComponent().getLocalName()}
+ @if(usesNode.getRefines().isEmpty()) {
+ ;
+ } else {
+ {
+ @for(path <- usesNode.getRefines().keySet()) {
+ refine @{path.getLastComponent()} {
+ @if(usesNode.getRefines().get(path).isInstanceOf[DataSchemaNode]) {
+ @yangTemplateWriteDataSchemaNode(usesNode.getRefines().get(path).asInstanceOf[DataSchemaNode])
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
\ No newline at end of file