From 8bad6bbbb543ad63cd3a88850865a4afdef12b9f Mon Sep 17 00:00:00 2001 From: Martin Ciglan Date: Thu, 16 Jun 2016 14:27:11 +0200 Subject: [PATCH] Bug 1411-4: MDSAL Binding2 Generator Impl - BindingGeneratorImpl decomposition proposal - introduction for Twirl templates for Yang Snippets generation - rather more templates, less logic, more content - JUnit test - to be finished - added several twirl templates for YANG - review comments fixed - apply https://git.opendaylight.org/gerrit/#/c/44939/ for spec v2 Change-Id: I79cb7e9c0d41c23408949dd5d4d40d572cc86652 Signed-off-by: Martin Ciglan Signed-off-by: Filip Gregor (cherry picked from commit a5e2366bfdf89f9b859b0a7ecfe4bdf4b4cc423e) --- .../mdsal-binding2-generator-impl/pom.xml | 2 +- .../generator/impl/AugmentToGenType.java | 410 ++++++++++++ .../generator/impl/BindingGeneratorImpl.java | 134 ++++ .../generator/impl/GenHelperUtil.java | 613 ++++++++++++++++++ .../impl/GeneratedClassLoadingStrategy.java | 25 + .../generator/impl/ModuleContext.java | 211 ++++++ .../generator/impl/ModuleToGenType.java | 88 +++ .../generator/impl/util/YangTextTemplate.java | 299 +++++++++ .../yang/types/TypeProviderImpl.java | 151 +++++ .../mdsal/binding2/TestUtils.java | 58 ++ .../mdsal/binding2/YangTemplateTest.java | 59 ++ .../yang-template/yang-template-import.yang | 13 + .../yang-template/yang-template-test.yang | 118 ++++ .../binding2/yangTemplateForModule.scala.txt | 112 ++++ .../binding2/yangTemplateForNode.scala.txt | 79 +++ .../binding2/yangTemplateForNodes.scala.txt | 32 + .../yangTemplateWriteAugments.scala.txt | 45 ++ .../yangTemplateWriteDataSchemaNode.scala.txt | 131 ++++ ...yangTemplateWriteDataSchemaNodes.scala.txt | 23 + .../yangTemplateWriteExtension.scala.txt | 34 + .../yangTemplateWriteFeature.scala.txt | 31 + .../yangTemplateWriteGroupingDef.scala.txt | 35 + .../yangTemplateWriteGroupingDefs.scala.txt | 25 + .../yangTemplateWriteIdentity.scala.txt | 40 ++ .../yangTemplateWriteNotification.scala.txt | 44 ++ .../binding2/yangTemplateWriteRPC.scala.txt | 49 ++ ...ngTemplateWriteUnknownSchemaNode.scala.txt | 24 + ...gTemplateWriteUnknownSchemaNodes.scala.txt | 25 + .../yangTemplateWriteUsesNodes.scala.txt | 41 ++ 29 files changed, 2950 insertions(+), 1 deletion(-) create mode 100644 binding2/mdsal-binding2-generator-impl/src/main/java/org/opendaylight/mdsal/binding2/generator/impl/AugmentToGenType.java create mode 100644 binding2/mdsal-binding2-generator-impl/src/main/java/org/opendaylight/mdsal/binding2/generator/impl/BindingGeneratorImpl.java create mode 100644 binding2/mdsal-binding2-generator-impl/src/main/java/org/opendaylight/mdsal/binding2/generator/impl/GenHelperUtil.java create mode 100644 binding2/mdsal-binding2-generator-impl/src/main/java/org/opendaylight/mdsal/binding2/generator/impl/GeneratedClassLoadingStrategy.java create mode 100644 binding2/mdsal-binding2-generator-impl/src/main/java/org/opendaylight/mdsal/binding2/generator/impl/ModuleContext.java create mode 100644 binding2/mdsal-binding2-generator-impl/src/main/java/org/opendaylight/mdsal/binding2/generator/impl/ModuleToGenType.java create mode 100644 binding2/mdsal-binding2-generator-impl/src/main/java/org/opendaylight/mdsal/binding2/generator/impl/util/YangTextTemplate.java create mode 100644 binding2/mdsal-binding2-generator-impl/src/main/java/org/opendaylight/mdsal/binding2/generator/yang/types/TypeProviderImpl.java create mode 100644 binding2/mdsal-binding2-generator-impl/src/main/test/java/org/opendaylight/mdsal/binding2/TestUtils.java create mode 100644 binding2/mdsal-binding2-generator-impl/src/main/test/java/org/opendaylight/mdsal/binding2/YangTemplateTest.java create mode 100644 binding2/mdsal-binding2-generator-impl/src/main/test/resources/yang-template/yang-template-import.yang create mode 100644 binding2/mdsal-binding2-generator-impl/src/main/test/resources/yang-template/yang-template-test.yang create mode 100644 binding2/mdsal-binding2-generator-impl/src/main/twirl/org/opendaylight/mdsal/binding2/yangTemplateForModule.scala.txt create mode 100644 binding2/mdsal-binding2-generator-impl/src/main/twirl/org/opendaylight/mdsal/binding2/yangTemplateForNode.scala.txt create mode 100644 binding2/mdsal-binding2-generator-impl/src/main/twirl/org/opendaylight/mdsal/binding2/yangTemplateForNodes.scala.txt create mode 100644 binding2/mdsal-binding2-generator-impl/src/main/twirl/org/opendaylight/mdsal/binding2/yangTemplateWriteAugments.scala.txt create mode 100644 binding2/mdsal-binding2-generator-impl/src/main/twirl/org/opendaylight/mdsal/binding2/yangTemplateWriteDataSchemaNode.scala.txt create mode 100644 binding2/mdsal-binding2-generator-impl/src/main/twirl/org/opendaylight/mdsal/binding2/yangTemplateWriteDataSchemaNodes.scala.txt create mode 100644 binding2/mdsal-binding2-generator-impl/src/main/twirl/org/opendaylight/mdsal/binding2/yangTemplateWriteExtension.scala.txt create mode 100644 binding2/mdsal-binding2-generator-impl/src/main/twirl/org/opendaylight/mdsal/binding2/yangTemplateWriteFeature.scala.txt create mode 100644 binding2/mdsal-binding2-generator-impl/src/main/twirl/org/opendaylight/mdsal/binding2/yangTemplateWriteGroupingDef.scala.txt create mode 100644 binding2/mdsal-binding2-generator-impl/src/main/twirl/org/opendaylight/mdsal/binding2/yangTemplateWriteGroupingDefs.scala.txt create mode 100644 binding2/mdsal-binding2-generator-impl/src/main/twirl/org/opendaylight/mdsal/binding2/yangTemplateWriteIdentity.scala.txt create mode 100644 binding2/mdsal-binding2-generator-impl/src/main/twirl/org/opendaylight/mdsal/binding2/yangTemplateWriteNotification.scala.txt create mode 100644 binding2/mdsal-binding2-generator-impl/src/main/twirl/org/opendaylight/mdsal/binding2/yangTemplateWriteRPC.scala.txt create mode 100644 binding2/mdsal-binding2-generator-impl/src/main/twirl/org/opendaylight/mdsal/binding2/yangTemplateWriteUnknownSchemaNode.scala.txt create mode 100644 binding2/mdsal-binding2-generator-impl/src/main/twirl/org/opendaylight/mdsal/binding2/yangTemplateWriteUnknownSchemaNodes.scala.txt create mode 100644 binding2/mdsal-binding2-generator-impl/src/main/twirl/org/opendaylight/mdsal/binding2/yangTemplateWriteUsesNodes.scala.txt diff --git a/binding2/mdsal-binding2-generator-impl/pom.xml b/binding2/mdsal-binding2-generator-impl/pom.xml index 71ed8e5cd2..9a98a75c18 100644 --- a/binding2/mdsal-binding2-generator-impl/pom.xml +++ b/binding2/mdsal-binding2-generator-impl/pom.xml @@ -104,7 +104,7 @@ - + net.alchim31.maven scala-maven-plugin diff --git a/binding2/mdsal-binding2-generator-impl/src/main/java/org/opendaylight/mdsal/binding2/generator/impl/AugmentToGenType.java b/binding2/mdsal-binding2-generator-impl/src/main/java/org/opendaylight/mdsal/binding2/generator/impl/AugmentToGenType.java new file mode 100644 index 0000000000..6b6e4fa757 --- /dev/null +++ b/binding2/mdsal-binding2-generator-impl/src/main/java/org/opendaylight/mdsal/binding2/generator/impl/AugmentToGenType.java @@ -0,0 +1,410 @@ +/* + * 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 AUGMENT_COMP = (o1, o2) -> { + final Iterator thisIt = o1.getTargetPath().getPathFromRoot().iterator(); + final Iterator 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 augmentation of the module to the list + * Type 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 + *
    + *
  • if the module is null
  • + *
  • if the name of module is null
  • + *
+ * @throws IllegalStateException + * if set of augmentations from module is null + */ + static Map generate(final Module module, final SchemaContext schemaContext, Map genCtx, Map> 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 augmentations = resolveAugmentations(module); + for (final AugmentationSchema augment : augmentations) { + genCtx = augmentationToGenTypes(basePackageName, augment, module, schemaContext, verboseClassComments, + genCtx, genTypeBuilders); + } + return genCtx; + } + + /** + * Returns list of AugmentationSchema 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 AugmentationSchema objects obtained + * from module + * @throws IllegalArgumentException + * if module is null + * @throws IllegalStateException + * if set of module augmentations is null + */ + private static List resolveAugmentations(final Module module) { + checkArgument(module != null, "Module reference cannot be NULL."); + checkState(module.getAugmentations() != null, "Augmentations Set cannot be NULL."); + + final Set augmentations = module.getAugmentations(); + final List sortedAugmentations = new ArrayList<>(augmentations); + Collections.sort(sortedAugmentations, AUGMENT_COMP); + + return sortedAugmentations; + } + + /** + * Converts augSchema to list of Type which + * contains generated type for augmentation. In addition there are also + * generated types for all containers, list and choices which are child of + * augSchema 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 + *
    + *
  • if augmentPackageName equals null
  • + *
  • if augSchema equals null
  • + *
+ * @throws IllegalStateException + * if augment target path is null + * @return + */ + private static Map augmentationToGenTypes(final String augmentPackageName, final AugmentationSchema augSchema, + final Module module, final SchemaContext schemaContext, final boolean verboseClassComments, + Map genCtx, Map> genTypeBuilders) { + + Map 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 usesAugmentationToGenTypes(final SchemaContext schemaContext, final String + augmentPackageName, final AugmentationSchema augSchema, final Module module, final UsesNode usesNode, final DataNodeContainer + usesNodeParent, Map genCtx, + Map> genTypeBuilders, + final boolean verboseClassComments) { + + Map 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 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 refChoiceType + * @throws IllegalArgumentException + *
    + *
  • if basePackageName is null
  • + *
  • if targetType is null
  • + *
  • if augmentedNodes is null
  • + *
+ */ + private static Map generateTypesFromAugmentedChoiceCases(final SchemaContext schemaContext, final Module module, + final String basePackageName, final Type targetType, final ChoiceSchemaNode targetNode, + final Iterable augmentedNodes, final DataNodeContainer usesNodeParent, + Map genCtx, final boolean verboseClassComments, + Map> 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 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; + } +} diff --git a/binding2/mdsal-binding2-generator-impl/src/main/java/org/opendaylight/mdsal/binding2/generator/impl/BindingGeneratorImpl.java b/binding2/mdsal-binding2-generator-impl/src/main/java/org/opendaylight/mdsal/binding2/generator/impl/BindingGeneratorImpl.java new file mode 100644 index 0000000000..bad95da52f --- /dev/null +++ b/binding2/mdsal-binding2-generator-impl/src/main/java/org/opendaylight/mdsal/binding2/generator/impl/BindingGeneratorImpl.java @@ -0,0 +1,134 @@ +/* + * 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> genTypeBuilders = new HashMap<>(); + + private Map 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 context 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 GeneratedType + * GeneratedTransferObjectwhich are generated from + * context data. + * @throws IllegalArgumentException + * if arg context is null + * @throws IllegalStateException + * if context contain no modules + */ + @Override + public List 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 modules = context.getModules(); + return generateTypes(context, modules); + } + + @Override + public List generateTypes(SchemaContext context, Set 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 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 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 additionalTypes = ((TypeProviderImpl) typeProvider).getAdditionalTypes().get(m); + if (additionalTypes != null) { + filteredGenTypes.addAll(additionalTypes); + } + } + + return filteredGenTypes; + } +} diff --git a/binding2/mdsal-binding2-generator-impl/src/main/java/org/opendaylight/mdsal/binding2/generator/impl/GenHelperUtil.java b/binding2/mdsal-binding2-generator-impl/src/main/java/org/opendaylight/mdsal/binding2/generator/impl/GenHelperUtil.java new file mode 100644 index 0000000000..3951410be0 --- /dev/null +++ b/binding2/mdsal-binding2-generator-impl/src/main/java/org/opendaylight/mdsal/binding2/generator/impl/GenHelperUtil.java @@ -0,0 +1,613 @@ +/* + * 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 GeneratedTypeBuilder which is internal + * representation of the module + * @throws IllegalArgumentException + * if module is null + */ + static GeneratedTypeBuilder moduleToDataType(final Module module, Map 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 module. + * + * @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 + * module. + * @throws IllegalArgumentException + * if module 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 uses in + * {@code dataNodeContainer}. For every use is obtained corresponding + * generated type from all groupings + * allGroupings} which is added as implements type to + * builder + * + * @param dataNodeContainer + * element which contains the list of used YANG groupings + * @param builder + * builder to which are added implemented types according to + * dataNodeContainer + * @param genCtx + * @return generated type builder with all implemented types + */ + private static GeneratedTypeBuilder addImplementedInterfaceFromUses(final DataNodeContainer dataNodeContainer, + final GeneratedTypeBuilder builder, Map 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 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("

"); + sb.append("This class represents the following YANG schema fragment defined in module "); + sb.append(module.getName()); + sb.append(""); + sb.append(NEW_LINE); + sb.append("

");
+            sb.append(NEW_LINE);
+            sb.append(Binding2GeneratorUtil.encodeAngleBrackets(yangTemplateForModule.render(module).body()));
+            sb.append("
"); + } + + 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 typeBuilder which represent subnodes of + * node for which typeBuilder 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 typeBuilder 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 typeBuilder 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 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 processUsesAugments(final SchemaContext schemaContext, final + DataNodeContainer node, final Module module, Map genCtx, Map> 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 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 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 addRawAugmentGenTypeDefinition(final Module module, final String augmentPackageName, + final String basePackageName, final Type targetTypeRef, final AugmentationSchema augSchema, + Map> genTypeBuilders, Map genCtx) { + + Map 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 typeBuilder what represents subnodes of + * node for which typeBuilder 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 typeBuilder 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 typeBuilder was created + * @return generated type builder which is the same object as the input + * parameter typeBuilder. 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 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 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 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 genCtx, final SchemaContext schemaContext, + final boolean verboseClassComments, Map> genTypeBuilders) { + return addDefaultInterfaceDefinition(packageName, schemaNode, null, module, genCtx, schemaContext, + verboseClassComments, genTypeBuilders); + } + + /** + * Instantiates generated type builder with packageName and + * schemaNode. + * + * The new builder always implements + * {@link org.opendaylight.mdsal.binding2.spec.TreeNode TreeNode}.
+ * If schemaNode is instance of GroupingDefinition it also + * implements {@link org.opendaylight.mdsal.binding2.spec.Augmentable + * Augmentable}.
+ * If schemaNode is instance of + * {@link org.opendaylight.yangtools.yang.model.api.DataNodeContainer + * DataNodeContainer} it can also implement nodes which are specified in + * uses. + * + * @param packageName + * string with the name of the package to which + * schemaNode 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 schemaNode + */ + private static GeneratedTypeBuilder addDefaultInterfaceDefinition(final String packageName, final SchemaNode + schemaNode, final Type parent, final Module module, Map genCtx, + final SchemaContext schemaContext, final boolean verboseClassComments, Map> 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 + * schemaNode with packageName. + * + * Firstly the generated type builder is searched in + * {@link BindingGeneratorImpl#genTypeBuilders genTypeBuilders}. If it isn't + * found it is created and added to genTypeBuilders. + * + * @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 schemaNode + * @throws IllegalArgumentException + *
    + *
  • if schemaNode is null
  • + *
  • if packageName is null
  • + *
  • if QName of schema node is null
  • + *
  • if schemaNode name is null
  • + *
+ * + */ + private static GeneratedTypeBuilder addRawInterfaceDefinition(final String packageName, final SchemaNode schemaNode, + final SchemaContext schemaContext, final String prefix, final boolean verboseClassComments, + Map> 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) schemaNode.getPath().getPathFromRoot()); + newType.setModuleName(module.getName()); + + //FIXME: update genTypeBuilders for callers + if (!genTypeBuilders.containsKey(packageName)) { + final Map builders = new HashMap<>(); + builders.put(genTypeName, newType); + genTypeBuilders.put(packageName, builders); + } else { + final Map 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("

"); + sb.append("This class represents the following YANG schema fragment defined in module "); + sb.append(module.getName()); + sb.append(""); + sb.append(NEW_LINE); + sb.append("

");
+            sb.append(NEW_LINE);
+            sb.append(Binding2GeneratorUtil.encodeAngleBrackets(yangTemplateForNode.render(schemaNode).body()));
+            sb.append("
"); + sb.append(NEW_LINE); + sb.append("The schema path to identify an instance is"); + sb.append(NEW_LINE); + sb.append(""); + sb.append(YangTextTemplate.formatSchemaPath(module.getName(), schemaNode.getPath().getPathFromRoot())); + sb.append(""); + sb.append(NEW_LINE); + + if (hasBuilderClass(schemaNode)) { + sb.append(NEW_LINE); + sb.append("

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 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; + } + +} diff --git a/binding2/mdsal-binding2-generator-impl/src/main/java/org/opendaylight/mdsal/binding2/generator/impl/GeneratedClassLoadingStrategy.java b/binding2/mdsal-binding2-generator-impl/src/main/java/org/opendaylight/mdsal/binding2/generator/impl/GeneratedClassLoadingStrategy.java new file mode 100644 index 0000000000..ca32561736 --- /dev/null +++ b/binding2/mdsal-binding2-generator-impl/src/main/java/org/opendaylight/mdsal/binding2/generator/impl/GeneratedClassLoadingStrategy.java @@ -0,0 +1,25 @@ +/* + * 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; +} diff --git a/binding2/mdsal-binding2-generator-impl/src/main/java/org/opendaylight/mdsal/binding2/generator/impl/ModuleContext.java b/binding2/mdsal-binding2-generator-impl/src/main/java/org/opendaylight/mdsal/binding2/generator/impl/ModuleContext.java new file mode 100644 index 0000000000..f16296847a --- /dev/null +++ b/binding2/mdsal-binding2-generator-impl/src/main/java/org/opendaylight/mdsal/binding2/generator/impl/ModuleContext.java @@ -0,0 +1,211 @@ +/* + * 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 genTOs = new ArrayList<>(); + private final Map typedefs = new HashMap<>(); + private final Map childNodes = new HashMap<>(); + private final Map groupings = new HashMap<>(); + private final Map cases = new HashMap<>(); + private final Map identities = new HashMap<>(); + private final Set topLevelNodes = new HashSet<>(); + private final List augmentations = new ArrayList<>(); + private final BiMap typeToAugmentation = HashBiMap.create(); + private final Map typeToSchema = new HashMap<>(); + private final Multimap choiceToCases = HashMultimap.create(); + private final BiMap caseTypeToSchema = HashBiMap.create(); + private final Map innerTypes = new HashMap<>(); + + List getGeneratedTypes() { + List 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 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 getTypedefs() { + return typedefs; + } + + public Map getChildNodes() { + return Collections.unmodifiableMap(childNodes); + } + + public Map getGroupings() { + return Collections.unmodifiableMap(groupings); + } + + public Map getCases() { + return Collections.unmodifiableMap(cases); + } + + public Map getIdentities() { + return Collections.unmodifiableMap(identities); + } + + public Set getTopLevelNodes() { + return Collections.unmodifiableSet(topLevelNodes); + } + + public List getAugmentations() { + return Collections.unmodifiableList(augmentations); + } + + public BiMap 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 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 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); + } + +} diff --git a/binding2/mdsal-binding2-generator-impl/src/main/java/org/opendaylight/mdsal/binding2/generator/impl/ModuleToGenType.java b/binding2/mdsal-binding2-generator-impl/src/main/java/org/opendaylight/mdsal/binding2/generator/impl/ModuleToGenType.java new file mode 100644 index 0000000000..5ef8f390d9 --- /dev/null +++ b/binding2/mdsal-binding2-generator-impl/src/main/java/org/opendaylight/mdsal/binding2/generator/impl/ModuleToGenType.java @@ -0,0 +1,88 @@ +/* + * 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 generate(final Module module, final SchemaContext schemaContext, + TypeProvider typeProvider, final boolean verboseClassComments) { + Map 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 + * Type objects. + * + * @param module + * module from which is obtained set of type definitions + * @throws IllegalArgumentException + *

    + *
  • if module is null
  • + *
  • if name of module is null
  • + *
+ * @throws IllegalStateException + * if set of type definitions from module is null + */ + private static Map allTypeDefinitionsToGenTypes(final Module module, Map 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> 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; + } +} diff --git a/binding2/mdsal-binding2-generator-impl/src/main/java/org/opendaylight/mdsal/binding2/generator/impl/util/YangTextTemplate.java b/binding2/mdsal-binding2-generator-impl/src/main/java/org/opendaylight/mdsal/binding2/generator/impl/util/YangTextTemplate.java new file mode 100644 index 0000000000..f59e5a0763 --- /dev/null +++ b/binding2/mdsal-binding2-generator-impl/src/main/java/org/opendaylight/mdsal/binding2/generator/impl/util/YangTextTemplate.java @@ -0,0 +1,299 @@ +/* + * 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 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 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 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 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 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 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 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 diff --git a/binding2/mdsal-binding2-generator-impl/src/main/java/org/opendaylight/mdsal/binding2/generator/yang/types/TypeProviderImpl.java b/binding2/mdsal-binding2-generator-impl/src/main/java/org/opendaylight/mdsal/binding2/generator/yang/types/TypeProviderImpl.java new file mode 100644 index 0000000000..6a90b5d59f --- /dev/null +++ b/binding2/mdsal-binding2-generator-impl/src/main/java/org/opendaylight/mdsal/binding2/generator/yang/types/TypeProviderImpl.java @@ -0,0 +1,151 @@ +/* + * 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>> + */ + private final Map>> genTypeDefsContextMap; + + private final Map> additionalTypes; + /** + * Creates new instance of class TypeProviderImpl. + * + * @param schemaContext + * contains the schema data red from YANG files + * @throws IllegalArgumentException + * if schemaContext 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 typeDefinition to concrete JAVA Type. + * + * @param typeDefinition + * type definition which should be converted to JAVA + * Type + * @return JAVA Type which represents + * typeDefinition + * @throws IllegalArgumentException + *
    + *
  • if typeDefinition equal null
  • + *
  • if Q name of typeDefinition
  • + *
  • if name of typeDefinition
  • + *
+ */ + 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> modulesByDate = genTypeDefsContextMap.get(module.getName()); + final Map genTOs = modulesByDate.get(module.getRevision()); + if (genTOs != null) { + return genTOs.get(typeDefinition.getQName().getLocalName()); + } + } + } + return null; + } + + /** + * Gets base type definition for extendTypeDef. The method is + * recursively called until non ExtendedType type is found. + * + * @param extendTypeDef + * type definition for which is the base type definition sought + * @return type definition which is base type for extendTypeDef + * @throws IllegalArgumentException + * if extendTypeDef 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> getAdditionalTypes() { + return additionalTypes; + } + +} diff --git a/binding2/mdsal-binding2-generator-impl/src/main/test/java/org/opendaylight/mdsal/binding2/TestUtils.java b/binding2/mdsal-binding2-generator-impl/src/main/test/java/org/opendaylight/mdsal/binding2/TestUtils.java new file mode 100644 index 0000000000..bd3c54546b --- /dev/null +++ b/binding2/mdsal-binding2-generator-impl/src/main/test/java/org/opendaylight/mdsal/binding2/TestUtils.java @@ -0,0 +1,58 @@ +/* + * 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 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); + } + } +} diff --git a/binding2/mdsal-binding2-generator-impl/src/main/test/java/org/opendaylight/mdsal/binding2/YangTemplateTest.java b/binding2/mdsal-binding2-generator-impl/src/main/test/java/org/opendaylight/mdsal/binding2/YangTemplateTest.java new file mode 100644 index 0000000000..e473f01d6f --- /dev/null +++ b/binding2/mdsal-binding2-generator-impl/src/main/test/java/org/opendaylight/mdsal/binding2/YangTemplateTest.java @@ -0,0 +1,59 @@ +/* + * 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 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(); + + ////////// + } + + } +} diff --git a/binding2/mdsal-binding2-generator-impl/src/main/test/resources/yang-template/yang-template-import.yang b/binding2/mdsal-binding2-generator-impl/src/main/test/resources/yang-template/yang-template-import.yang new file mode 100644 index 0000000000..191446e077 --- /dev/null +++ b/binding2/mdsal-binding2-generator-impl/src/main/test/resources/yang-template/yang-template-import.yang @@ -0,0 +1,13 @@ +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 diff --git a/binding2/mdsal-binding2-generator-impl/src/main/test/resources/yang-template/yang-template-test.yang b/binding2/mdsal-binding2-generator-impl/src/main/test/resources/yang-template/yang-template-test.yang new file mode 100644 index 0000000000..53532392eb --- /dev/null +++ b/binding2/mdsal-binding2-generator-impl/src/main/test/resources/yang-template/yang-template-test.yang @@ -0,0 +1,118 @@ +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 diff --git a/binding2/mdsal-binding2-generator-impl/src/main/twirl/org/opendaylight/mdsal/binding2/yangTemplateForModule.scala.txt b/binding2/mdsal-binding2-generator-impl/src/main/twirl/org/opendaylight/mdsal/binding2/yangTemplateForModule.scala.txt new file mode 100644 index 0000000000..2517fbb495 --- /dev/null +++ b/binding2/mdsal-binding2-generator-impl/src/main/twirl/org/opendaylight/mdsal/binding2/yangTemplateForModule.scala.txt @@ -0,0 +1,112 @@ +@* + * 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 diff --git a/binding2/mdsal-binding2-generator-impl/src/main/twirl/org/opendaylight/mdsal/binding2/yangTemplateForNode.scala.txt b/binding2/mdsal-binding2-generator-impl/src/main/twirl/org/opendaylight/mdsal/binding2/yangTemplateForNode.scala.txt new file mode 100644 index 0000000000..805f223561 --- /dev/null +++ b/binding2/mdsal-binding2-generator-impl/src/main/twirl/org/opendaylight/mdsal/binding2/yangTemplateForNode.scala.txt @@ -0,0 +1,79 @@ +@* + * 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 diff --git a/binding2/mdsal-binding2-generator-impl/src/main/twirl/org/opendaylight/mdsal/binding2/yangTemplateForNodes.scala.txt b/binding2/mdsal-binding2-generator-impl/src/main/twirl/org/opendaylight/mdsal/binding2/yangTemplateForNodes.scala.txt new file mode 100644 index 0000000000..3d4da7cc84 --- /dev/null +++ b/binding2/mdsal-binding2-generator-impl/src/main/twirl/org/opendaylight/mdsal/binding2/yangTemplateForNodes.scala.txt @@ -0,0 +1,32 @@ +@* + * 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 diff --git a/binding2/mdsal-binding2-generator-impl/src/main/twirl/org/opendaylight/mdsal/binding2/yangTemplateWriteAugments.scala.txt b/binding2/mdsal-binding2-generator-impl/src/main/twirl/org/opendaylight/mdsal/binding2/yangTemplateWriteAugments.scala.txt new file mode 100644 index 0000000000..4820c139d2 --- /dev/null +++ b/binding2/mdsal-binding2-generator-impl/src/main/twirl/org/opendaylight/mdsal/binding2/yangTemplateWriteAugments.scala.txt @@ -0,0 +1,45 @@ +@* + * 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 diff --git a/binding2/mdsal-binding2-generator-impl/src/main/twirl/org/opendaylight/mdsal/binding2/yangTemplateWriteDataSchemaNode.scala.txt b/binding2/mdsal-binding2-generator-impl/src/main/twirl/org/opendaylight/mdsal/binding2/yangTemplateWriteDataSchemaNode.scala.txt new file mode 100644 index 0000000000..a68bf99112 --- /dev/null +++ b/binding2/mdsal-binding2-generator-impl/src/main/twirl/org/opendaylight/mdsal/binding2/yangTemplateWriteDataSchemaNode.scala.txt @@ -0,0 +1,131 @@ +@* + * 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 diff --git a/binding2/mdsal-binding2-generator-impl/src/main/twirl/org/opendaylight/mdsal/binding2/yangTemplateWriteDataSchemaNodes.scala.txt b/binding2/mdsal-binding2-generator-impl/src/main/twirl/org/opendaylight/mdsal/binding2/yangTemplateWriteDataSchemaNodes.scala.txt new file mode 100644 index 0000000000..40e7ac342f --- /dev/null +++ b/binding2/mdsal-binding2-generator-impl/src/main/twirl/org/opendaylight/mdsal/binding2/yangTemplateWriteDataSchemaNodes.scala.txt @@ -0,0 +1,23 @@ +@* + * 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 diff --git a/binding2/mdsal-binding2-generator-impl/src/main/twirl/org/opendaylight/mdsal/binding2/yangTemplateWriteExtension.scala.txt b/binding2/mdsal-binding2-generator-impl/src/main/twirl/org/opendaylight/mdsal/binding2/yangTemplateWriteExtension.scala.txt new file mode 100644 index 0000000000..e637052851 --- /dev/null +++ b/binding2/mdsal-binding2-generator-impl/src/main/twirl/org/opendaylight/mdsal/binding2/yangTemplateWriteExtension.scala.txt @@ -0,0 +1,34 @@ +@* + * 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 diff --git a/binding2/mdsal-binding2-generator-impl/src/main/twirl/org/opendaylight/mdsal/binding2/yangTemplateWriteFeature.scala.txt b/binding2/mdsal-binding2-generator-impl/src/main/twirl/org/opendaylight/mdsal/binding2/yangTemplateWriteFeature.scala.txt new file mode 100644 index 0000000000..e81e358401 --- /dev/null +++ b/binding2/mdsal-binding2-generator-impl/src/main/twirl/org/opendaylight/mdsal/binding2/yangTemplateWriteFeature.scala.txt @@ -0,0 +1,31 @@ +@* + * 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 diff --git a/binding2/mdsal-binding2-generator-impl/src/main/twirl/org/opendaylight/mdsal/binding2/yangTemplateWriteGroupingDef.scala.txt b/binding2/mdsal-binding2-generator-impl/src/main/twirl/org/opendaylight/mdsal/binding2/yangTemplateWriteGroupingDef.scala.txt new file mode 100644 index 0000000000..5b1a56233b --- /dev/null +++ b/binding2/mdsal-binding2-generator-impl/src/main/twirl/org/opendaylight/mdsal/binding2/yangTemplateWriteGroupingDef.scala.txt @@ -0,0 +1,35 @@ +@* + * 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 diff --git a/binding2/mdsal-binding2-generator-impl/src/main/twirl/org/opendaylight/mdsal/binding2/yangTemplateWriteGroupingDefs.scala.txt b/binding2/mdsal-binding2-generator-impl/src/main/twirl/org/opendaylight/mdsal/binding2/yangTemplateWriteGroupingDefs.scala.txt new file mode 100644 index 0000000000..533b65408c --- /dev/null +++ b/binding2/mdsal-binding2-generator-impl/src/main/twirl/org/opendaylight/mdsal/binding2/yangTemplateWriteGroupingDefs.scala.txt @@ -0,0 +1,25 @@ +@* + * 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 diff --git a/binding2/mdsal-binding2-generator-impl/src/main/twirl/org/opendaylight/mdsal/binding2/yangTemplateWriteIdentity.scala.txt b/binding2/mdsal-binding2-generator-impl/src/main/twirl/org/opendaylight/mdsal/binding2/yangTemplateWriteIdentity.scala.txt new file mode 100644 index 0000000000..a72bf084c7 --- /dev/null +++ b/binding2/mdsal-binding2-generator-impl/src/main/twirl/org/opendaylight/mdsal/binding2/yangTemplateWriteIdentity.scala.txt @@ -0,0 +1,40 @@ +@* + * 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 diff --git a/binding2/mdsal-binding2-generator-impl/src/main/twirl/org/opendaylight/mdsal/binding2/yangTemplateWriteNotification.scala.txt b/binding2/mdsal-binding2-generator-impl/src/main/twirl/org/opendaylight/mdsal/binding2/yangTemplateWriteNotification.scala.txt new file mode 100644 index 0000000000..610103ef43 --- /dev/null +++ b/binding2/mdsal-binding2-generator-impl/src/main/twirl/org/opendaylight/mdsal/binding2/yangTemplateWriteNotification.scala.txt @@ -0,0 +1,44 @@ +@* + * 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 diff --git a/binding2/mdsal-binding2-generator-impl/src/main/twirl/org/opendaylight/mdsal/binding2/yangTemplateWriteRPC.scala.txt b/binding2/mdsal-binding2-generator-impl/src/main/twirl/org/opendaylight/mdsal/binding2/yangTemplateWriteRPC.scala.txt new file mode 100644 index 0000000000..2436b722d4 --- /dev/null +++ b/binding2/mdsal-binding2-generator-impl/src/main/twirl/org/opendaylight/mdsal/binding2/yangTemplateWriteRPC.scala.txt @@ -0,0 +1,49 @@ +@* + * 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 diff --git a/binding2/mdsal-binding2-generator-impl/src/main/twirl/org/opendaylight/mdsal/binding2/yangTemplateWriteUnknownSchemaNode.scala.txt b/binding2/mdsal-binding2-generator-impl/src/main/twirl/org/opendaylight/mdsal/binding2/yangTemplateWriteUnknownSchemaNode.scala.txt new file mode 100644 index 0000000000..11a2de87fc --- /dev/null +++ b/binding2/mdsal-binding2-generator-impl/src/main/twirl/org/opendaylight/mdsal/binding2/yangTemplateWriteUnknownSchemaNode.scala.txt @@ -0,0 +1,24 @@ +@* + * 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 diff --git a/binding2/mdsal-binding2-generator-impl/src/main/twirl/org/opendaylight/mdsal/binding2/yangTemplateWriteUnknownSchemaNodes.scala.txt b/binding2/mdsal-binding2-generator-impl/src/main/twirl/org/opendaylight/mdsal/binding2/yangTemplateWriteUnknownSchemaNodes.scala.txt new file mode 100644 index 0000000000..852cdd1a5a --- /dev/null +++ b/binding2/mdsal-binding2-generator-impl/src/main/twirl/org/opendaylight/mdsal/binding2/yangTemplateWriteUnknownSchemaNodes.scala.txt @@ -0,0 +1,25 @@ +@* + * 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 diff --git a/binding2/mdsal-binding2-generator-impl/src/main/twirl/org/opendaylight/mdsal/binding2/yangTemplateWriteUsesNodes.scala.txt b/binding2/mdsal-binding2-generator-impl/src/main/twirl/org/opendaylight/mdsal/binding2/yangTemplateWriteUsesNodes.scala.txt new file mode 100644 index 0000000000..3c9396e729 --- /dev/null +++ b/binding2/mdsal-binding2-generator-impl/src/main/twirl/org/opendaylight/mdsal/binding2/yangTemplateWriteUsesNodes.scala.txt @@ -0,0 +1,41 @@ +@* + * 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 -- 2.36.6