Merge "Bug 1329: Use original definition for searching for java class."
authorMartin Vitez <mvitez@cisco.com>
Mon, 21 Jul 2014 12:45:43 +0000 (12:45 +0000)
committerGerrit Code Review <gerrit@opendaylight.org>
Mon, 21 Jul 2014 12:45:43 +0000 (12:45 +0000)
86 files changed:
.gitignore
code-generator/binding-generator-impl/pom.xml
code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/impl/BindingGeneratorImpl.java
code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/impl/TransformerGenerator.xtend
code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/util/DefaultSourceCodeGenerator.java [new file with mode: 0644]
code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/util/JavassistUtils.java
code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/util/NullSourceCodeGenerator.java [new file with mode: 0644]
code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/util/SourceCodeGenerator.java [new file with mode: 0644]
code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/util/SourceCodeGeneratorFactory.java [new file with mode: 0644]
code-generator/binding-generator-util/src/main/java/org/opendaylight/yangtools/binding/generator/util/BindingGeneratorUtil.java
code-generator/binding-generator-util/src/main/java/org/opendaylight/yangtools/binding/generator/util/generated/type/builder/EnumerationBuilderImpl.java
code-generator/binding-generator-util/src/main/java/org/opendaylight/yangtools/binding/generator/util/generated/type/builder/GeneratedTOBuilderImpl.java
code-generator/binding-generator-util/src/main/java/org/opendaylight/yangtools/binding/generator/util/generated/type/builder/GeneratedTypeBuilderImpl.java
code-generator/binding-java-api-generator/pom.xml
code-generator/binding-java-api-generator/src/main/java/org/opendaylight/yangtools/sal/java/api/generator/BaseTemplate.xtend
code-generator/binding-java-api-generator/src/main/java/org/opendaylight/yangtools/sal/java/api/generator/BuilderTemplate.xtend
code-generator/binding-java-api-generator/src/main/java/org/opendaylight/yangtools/sal/java/api/generator/ClassTemplate.xtend
code-generator/binding-java-api-generator/src/main/java/org/opendaylight/yangtools/sal/java/api/generator/EnumTemplate.xtend
code-generator/binding-java-api-generator/src/main/java/org/opendaylight/yangtools/sal/java/api/generator/InterfaceTemplate.xtend
code-generator/binding-java-api-generator/src/main/java/org/opendaylight/yangtools/sal/java/api/generator/UnionBuilderTemplate.xtend
code-generator/binding-java-api-generator/src/main/java/org/opendaylight/yangtools/sal/java/api/generator/UnionTemplate.xtend
code-generator/binding-java-api-generator/src/test/java/org/opendaylight/yangtools/sal/java/api/generator/test/Bug1276Test.java [new file with mode: 0644]
code-generator/binding-java-api-generator/src/test/java/org/opendaylight/yangtools/sal/java/api/generator/test/Bug532Test.java [new file with mode: 0644]
code-generator/binding-java-api-generator/src/test/java/org/opendaylight/yangtools/sal/java/api/generator/test/CascadeUsesCompilationTest.java
code-generator/binding-java-api-generator/src/test/java/org/opendaylight/yangtools/sal/java/api/generator/test/CompilationTest.java
code-generator/binding-java-api-generator/src/test/java/org/opendaylight/yangtools/sal/java/api/generator/test/CompilationTestUtils.java
code-generator/binding-java-api-generator/src/test/java/org/opendaylight/yangtools/sal/java/api/generator/test/TypedefCompilationTest.java
code-generator/binding-java-api-generator/src/test/resources/compilation/augment-uses-to-augment/bar.yang
code-generator/binding-java-api-generator/src/test/resources/compilation/augment-uses-to-augment/baz.yang
code-generator/binding-java-api-generator/src/test/resources/compilation/augment-uses-to-augment/foo.yang
code-generator/binding-java-api-generator/src/test/resources/compilation/bug1097/foo.yang [new file with mode: 0644]
code-generator/binding-java-api-generator/src/test/resources/compilation/bug1276/foo.yang [new file with mode: 0644]
code-generator/binding-java-api-generator/src/test/resources/compilation/bug1377/foo.yang [new file with mode: 0644]
code-generator/binding-model-api/src/main/java/org/opendaylight/yangtools/sal/binding/model/api/DocumentedType.java [new file with mode: 0644]
code-generator/binding-model-api/src/main/java/org/opendaylight/yangtools/sal/binding/model/api/Enumeration.java
code-generator/binding-model-api/src/main/java/org/opendaylight/yangtools/sal/binding/model/api/GeneratedType.java
code-generator/binding-model-api/src/main/java/org/opendaylight/yangtools/sal/binding/model/api/type/builder/EnumBuilder.java
code-generator/binding-model-api/src/main/java/org/opendaylight/yangtools/sal/binding/model/api/type/builder/GeneratedTypeBuilderBase.java
code-generator/binding-type-provider/src/main/java/org/opendaylight/yangtools/sal/binding/yang/types/TypeProviderImpl.java
code-generator/maven-sal-api-gen-plugin/pom.xml
code-generator/samples/maven-code-gen-sample/pom.xml
code-generator/samples/modeling-sample/pom.xml
common/features/src/main/resources/features.xml
common/parent/pom.xml
common/util/src/main/java/org/opendaylight/yangtools/util/MapAdaptor.java
model/pom.xml
yang/yang-common/pom.xml
yang/yang-common/src/main/java/org/opendaylight/yangtools/yang/common/QName.java
yang/yang-common/src/main/java/org/opendaylight/yangtools/yang/common/RpcError.java
yang/yang-common/src/main/java/org/opendaylight/yangtools/yang/common/RpcResultBuilder.java
yang/yang-common/src/test/java/org/opendaylight/yangtools/yang/common/RpcResultBuilderTest.java
yang/yang-data-api/src/main/java/org/opendaylight/yangtools/yang/data/api/schema/NormalizedNode.java
yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/codec/xml/RandomPrefix.java
yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/codec/xml/XmlDocumentUtils.java
yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/codec/xml/XmlStreamUtils.java
yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/codec/xml/XmlUtils.java
yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/nodes/AbstractImmutableNormalizedNode.java
yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/tree/InMemoryDataTree.java
yang/yang-data-impl/src/test/java/org/opendaylight/yangtools/yang/data/impl/codec/xml/RandomPrefixTest.java [new file with mode: 0644]
yang/yang-data-impl/src/test/java/org/opendaylight/yangtools/yang/data/impl/schema/tree/TreeNodeUtilsTest.java [new file with mode: 0644]
yang/yang-data-operations/src/main/java/org/opendaylight/yangtools/yang/data/operations/DataModificationException.java
yang/yang-model-util/src/main/java/org/opendaylight/yangtools/yang/model/util/AbstractSignedInteger.java
yang/yang-model-util/src/main/java/org/opendaylight/yangtools/yang/model/util/AbstractUnsignedInteger.java
yang/yang-model-util/src/main/java/org/opendaylight/yangtools/yang/model/util/BaseTypes.java
yang/yang-model-util/src/main/java/org/opendaylight/yangtools/yang/model/util/BooleanType.java
yang/yang-model-util/src/main/java/org/opendaylight/yangtools/yang/model/util/ExtendedType.java
yang/yang-model-util/src/main/java/org/opendaylight/yangtools/yang/model/util/InstanceIdentifier.java
yang/yang-model-util/src/main/java/org/opendaylight/yangtools/yang/model/util/Leafref.java
yang/yang-model-util/src/main/java/org/opendaylight/yangtools/yang/model/util/SchemaContextUtil.java
yang/yang-model-util/src/main/java/org/opendaylight/yangtools/yang/model/util/StringType.java
yang/yang-model-util/src/main/java/org/opendaylight/yangtools/yang/model/util/UnionType.java
yang/yang-model-util/src/main/java/org/opendaylight/yangtools/yang/model/util/UnknownType.java
yang/yang-parser-impl/pom.xml
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/builder/impl/AugmentationSchemaBuilderImpl.java
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/builder/impl/BuilderUtils.java
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/builder/impl/CopyUtils.java
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/builder/impl/ListSchemaNodeBuilder.java
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/builder/impl/ModuleBuilder.java
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/builder/impl/TypeUtils.java
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/builder/impl/UnionTypeBuilder.java
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/impl/YangParserImpl.java
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/impl/YangParserListenerImpl.java
yang/yang-parser-impl/src/test/java/org/opendaylight/yangtools/yang/parser/impl/TwoRevisionsTest.java
yang/yang-parser-impl/src/test/java/org/opendaylight/yangtools/yang/parser/impl/YangParserNegativeTest.java
yang/yang-parser-impl/src/test/java/org/opendaylight/yangtools/yang/parser/util/RefineHolderTest.java
yang/yang-parser-impl/src/test/resources/negative-scenario/invalid-list-key-def.yang [new file with mode: 0644]

index d4bca565221656f5c132aaafbbca22f079218dbc..3e8b88f5c0b6dae4377d6260df391bd2cc4a3ae1 100644 (file)
@@ -12,5 +12,5 @@ target
 *.iml
 .idea
 bin
-**/src/main/xtend-gen
+xtend-gen
 target
index fbf4098b0511f36d88e2e8595d5f2d339f8826e7..39a98ad1ef4b301259ebb139471da9e6763ed663 100644 (file)
             <plugin>
                 <groupId>org.eclipse.xtend</groupId>
                 <artifactId>xtend-maven-plugin</artifactId>
-                <executions>
-                    <execution>
-                        <goals>
-                            <goal>compile</goal>
-                        </goals>
-                        <configuration>
-                            <outputDirectory>${basedir}/src/main/xtend-gen</outputDirectory>
-                        </configuration>
-                    </execution>
-                </executions>
-            </plugin>
-            <plugin>
-                <artifactId>maven-clean-plugin</artifactId>
-                <configuration>
-                    <filesets>
-                        <fileset>
-                            <directory>${basedir}/src/main/xtend-gen</directory>
-                            <includes>
-                                <include>**</include>
-                            </includes>
-                        </fileset>
-                    </filesets>
-                </configuration>
             </plugin>
         </plugins>
     </build>
index 66f973fcab1a300c000f48c44d0a8c86f4dca505..15fa0902d0029ee7084d6f64ea63d1e76a1a7257 100644 (file)
@@ -25,9 +25,11 @@ import static org.opendaylight.yangtools.binding.generator.util.Types.VOID;
 import static org.opendaylight.yangtools.binding.generator.util.Types.typeForClass;
 import static org.opendaylight.yangtools.yang.model.util.SchemaContextUtil.findDataSchemaNode;
 import static org.opendaylight.yangtools.yang.model.util.SchemaContextUtil.findNodeInSchemaContext;
-import static org.opendaylight.yangtools.yang.model.util.SchemaContextUtil.findOriginal;
 import static org.opendaylight.yangtools.yang.model.util.SchemaContextUtil.findParentModule;
 
+import com.google.common.base.Splitter;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Sets;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
@@ -36,7 +38,6 @@ import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
-
 import org.opendaylight.yangtools.binding.generator.util.BindingGeneratorUtil;
 import org.opendaylight.yangtools.binding.generator.util.BindingTypes;
 import org.opendaylight.yangtools.binding.generator.util.ReferencedTypeImpl;
@@ -75,6 +76,7 @@ import org.opendaylight.yangtools.yang.model.api.ChoiceNode;
 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.DerivableSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.GroupingDefinition;
 import org.opendaylight.yangtools.yang.model.api.IdentitySchemaNode;
 import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
@@ -101,10 +103,6 @@ import org.opendaylight.yangtools.yang.parser.util.ModuleDependencySort;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import com.google.common.base.Splitter;
-import com.google.common.collect.Iterables;
-import com.google.common.collect.Sets;
-
 public class BindingGeneratorImpl implements BindingGenerator {
     private static final Logger LOG = LoggerFactory.getLogger(BindingGeneratorImpl.class);
 
@@ -292,8 +290,8 @@ public class BindingGeneratorImpl implements BindingGenerator {
         return genType;
     }
 
-    private void containerToGenType(final Module module, final String basePackageName, final GeneratedTypeBuilder parent,
-            final GeneratedTypeBuilder childOf, final ContainerSchemaNode node) {
+    private void containerToGenType(final Module module, final String basePackageName,
+            final GeneratedTypeBuilder parent, final GeneratedTypeBuilder childOf, final ContainerSchemaNode node) {
         final GeneratedTypeBuilder genType = processDataSchemaNode(module, basePackageName, childOf, node);
         if (genType != null) {
             constructGetter(parent, node.getQName().getLocalName(), node.getDescription(), genType);
@@ -577,14 +575,14 @@ public class BindingGeneratorImpl implements BindingGenerator {
      *            information about base of identity
      *
      */
-    private void identityToGenType(final Module module, final String basePackageName, final IdentitySchemaNode identity,
-            final SchemaContext context) {
+    private void identityToGenType(final Module module, final String basePackageName,
+            final IdentitySchemaNode identity, final SchemaContext context) {
         if (identity == null) {
             return;
         }
         final String packageName = packageNameForGeneratedType(basePackageName, identity.getPath());
         final String genTypeName = BindingMapping.getClassName(identity.getQName());
-        final GeneratedTOBuilder newType = new GeneratedTOBuilderImpl(packageName, genTypeName);
+        final GeneratedTOBuilderImpl newType = new GeneratedTOBuilderImpl(packageName, genTypeName);
         final IdentitySchemaNode baseIdentity = identity.getBaseIdentity();
         if (baseIdentity == null) {
             final GeneratedTOBuilderImpl gto = new GeneratedTOBuilderImpl(BaseIdentity.class.getPackage().getName(),
@@ -592,7 +590,8 @@ public class BindingGeneratorImpl implements BindingGenerator {
             newType.setExtendsType(gto.toInstance());
         } else {
             final Module baseIdentityParentModule = SchemaContextUtil.findParentModule(context, baseIdentity);
-            final String returnTypePkgName = BindingMapping.getRootPackageName(module.getQNameModule());
+            final String returnTypePkgName = BindingMapping.getRootPackageName(baseIdentityParentModule
+                    .getQNameModule());
             final String returnTypeName = BindingMapping.getClassName(baseIdentity.getQName());
             final GeneratedTransferObject gto = new GeneratedTOBuilderImpl(returnTypePkgName, returnTypeName)
                     .toInstance();
@@ -600,13 +599,19 @@ public class BindingGeneratorImpl implements BindingGenerator {
         }
         newType.setAbstract(true);
         newType.addComment(identity.getDescription());
+        newType.setDescription(identity.getDescription());
+        newType.setReference(identity.getReference());
+        newType.setModuleName(module.getName());
+        newType.setSchemaPath(identity.getPath().getPathFromRoot());
+
         final QName qname = identity.getQName();
         qnameConstant(newType, BindingMapping.QNAME_STATIC_FIELD_NAME, qname);
 
         genCtx.get(module).addIdentityType(identity.getQName(), newType);
     }
 
-    private static Constant qnameConstant(final GeneratedTypeBuilderBase<?> toBuilder, final String constantName, final QName name) {
+    private static Constant qnameConstant(final GeneratedTypeBuilderBase<?> toBuilder, final String constantName,
+            final QName name) {
         StringBuilder sb = new StringBuilder("org.opendaylight.yangtools.yang.common.QName");
         sb.append(".create(");
         sb.append('"');
@@ -688,6 +693,7 @@ public class BindingGeneratorImpl implements BindingGenerator {
                 && (enumTypeDef.getQName().getLocalName() != null)) {
             final String enumerationName = BindingMapping.getClassName(enumName);
             final EnumBuilder enumBuilder = typeBuilder.addEnumeration(enumerationName);
+            enumBuilder.setDescription(enumTypeDef.getDescription());
             enumBuilder.updateEnumPairsFromEnumTypeDef(enumTypeDef);
             return enumBuilder;
         }
@@ -712,7 +718,13 @@ public class BindingGeneratorImpl implements BindingGenerator {
         checkArgument(module != null, "Module reference cannot be NULL.");
         final String packageName = BindingMapping.getRootPackageName(module.getQNameModule());
         final String moduleName = BindingMapping.getClassName(module.getName()) + postfix;
-        return new GeneratedTypeBuilderImpl(packageName, moduleName);
+
+        final GeneratedTypeBuilderImpl moduleBuilder = new GeneratedTypeBuilderImpl(packageName, moduleName);
+        moduleBuilder.setDescription(module.getDescription());
+        moduleBuilder.setReference(module.getReference());
+        moduleBuilder.setModuleName(moduleName);
+
+        return moduleBuilder;
     }
 
     /**
@@ -739,7 +751,8 @@ public class BindingGeneratorImpl implements BindingGenerator {
      * @throws IllegalStateException
      *             if augment target path is null
      */
-    private void augmentationToGenTypes(final String augmentPackageName, final AugmentationSchema augSchema, final Module module) {
+    private void augmentationToGenTypes(final String augmentPackageName, final AugmentationSchema augSchema,
+            final Module module) {
         checkArgument(augmentPackageName != null, "Package Name cannot be NULL.");
         checkArgument(augSchema != null, "Augmentation Schema cannot be NULL.");
         checkState(augSchema.getTargetPath() != null,
@@ -751,9 +764,11 @@ public class BindingGeneratorImpl implements BindingGenerator {
 
         targetSchemaNode = findDataSchemaNode(schemaContext, targetPath);
         if (targetSchemaNode instanceof DataSchemaNode && ((DataSchemaNode) targetSchemaNode).isAddedByUses()) {
-            targetSchemaNode = findOriginal((DataSchemaNode) targetSchemaNode, schemaContext);
+            if (targetSchemaNode instanceof DerivableSchemaNode) {
+                targetSchemaNode = ((DerivableSchemaNode) targetSchemaNode).getOriginal().orNull();
+            }
             if (targetSchemaNode == null) {
-                throw new NullPointerException("Failed to find target node from grouping in augmentation " + augSchema
+                throw new IllegalStateException("Failed to find target node from grouping in augmentation " + augSchema
                         + " in module " + module.getName());
             }
         }
@@ -781,8 +796,8 @@ public class BindingGeneratorImpl implements BindingGenerator {
         }
     }
 
-    private void usesAugmentationToGenTypes(final String augmentPackageName, final AugmentationSchema augSchema, final Module module,
-            final UsesNode usesNode, final DataNodeContainer usesNodeParent) {
+    private void usesAugmentationToGenTypes(final String augmentPackageName, final AugmentationSchema augSchema,
+            final Module module, final UsesNode usesNode, final DataNodeContainer usesNodeParent) {
         checkArgument(augmentPackageName != null, "Package Name cannot be NULL.");
         checkArgument(augSchema != null, "Augmentation Schema cannot be NULL.");
         checkState(augSchema.getTargetPath() != null,
@@ -1015,7 +1030,8 @@ public class BindingGeneratorImpl implements BindingGenerator {
      *         added to it.
      */
     private GeneratedTypeBuilder augSchemaNodeToMethods(final Module module, final String basePackageName,
-            final GeneratedTypeBuilder typeBuilder, final GeneratedTypeBuilder childOf, final Set<DataSchemaNode> schemaNodes) {
+            final GeneratedTypeBuilder typeBuilder, final GeneratedTypeBuilder childOf,
+            final Set<DataSchemaNode> schemaNodes) {
         if ((schemaNodes != null) && (typeBuilder != null)) {
             for (DataSchemaNode schemaNode : schemaNodes) {
                 if (!schemaNode.isAugmenting()) {
@@ -1087,8 +1103,8 @@ public class BindingGeneratorImpl implements BindingGenerator {
      *             <li>if <code>choiceNode</code> is null</li>
      *             </ul>
      */
-    private void choiceToGeneratedType(final Module module, final String basePackageName, final GeneratedTypeBuilder parent,
-            final ChoiceNode choiceNode) {
+    private void choiceToGeneratedType(final Module module, final String basePackageName,
+            final GeneratedTypeBuilder parent, final ChoiceNode choiceNode) {
         checkArgument(basePackageName != null, "Base Package Name cannot be NULL.");
         checkArgument(choiceNode != null, "Choice Schema Node cannot be NULL.");
 
@@ -1130,8 +1146,8 @@ public class BindingGeneratorImpl implements BindingGenerator {
      *             <li>if <code>caseNodes</code> equals null</li>
      *             </ul>
      */
-    private void generateTypesFromChoiceCases(final Module module, final String basePackageName, final Type refChoiceType,
-            final ChoiceNode choiceNode) {
+    private void generateTypesFromChoiceCases(final Module module, final String basePackageName,
+            final Type refChoiceType, final ChoiceNode choiceNode) {
         checkArgument(basePackageName != null, "Base Package Name cannot be NULL.");
         checkArgument(refChoiceType != null, "Referenced Choice Type cannot be NULL.");
         checkArgument(choiceNode != null, "ChoiceNode cannot be NULL.");
@@ -1161,9 +1177,11 @@ public class BindingGeneratorImpl implements BindingGenerator {
                         SchemaNode targetSchemaNode = findDataSchemaNode(schemaContext, targetPath);
                         if (targetSchemaNode instanceof DataSchemaNode
                                 && ((DataSchemaNode) targetSchemaNode).isAddedByUses()) {
-                            targetSchemaNode = findOriginal((DataSchemaNode) targetSchemaNode, schemaContext);
+                            if (targetSchemaNode instanceof DerivableSchemaNode) {
+                                targetSchemaNode = ((DerivableSchemaNode) targetSchemaNode).getOriginal().orNull();
+                            }
                             if (targetSchemaNode == null) {
-                                throw new NullPointerException(
+                                throw new IllegalStateException(
                                         "Failed to find target node from grouping for augmentation " + augSchema
                                                 + " in module " + module.getName());
                             }
@@ -1174,6 +1192,9 @@ public class BindingGeneratorImpl implements BindingGenerator {
                         parent = findDataSchemaNode(schemaContext, sp.getParent());
                     }
                     GeneratedTypeBuilder childOfType = findChildNodeByPath(parent.getPath());
+                    if (childOfType == null) {
+                        childOfType = findGroupingByPath(parent.getPath());
+                    }
                     resolveDataSchemaNodes(module, basePackageName, caseTypeBuilder, childOfType, caseChildNodes);
                 }
             }
@@ -1209,8 +1230,8 @@ public class BindingGeneratorImpl implements BindingGenerator {
      *             <li>if <code>augmentedNodes</code> is null</li>
      *             </ul>
      */
-    private void generateTypesFromAugmentedChoiceCases(final Module module, final String basePackageName, final Type targetType,
-            final ChoiceNode targetNode, final Set<DataSchemaNode> augmentedNodes) {
+    private void generateTypesFromAugmentedChoiceCases(final Module module, final String basePackageName,
+            final Type targetType, final ChoiceNode targetNode, final Set<DataSchemaNode> augmentedNodes) {
         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.");
@@ -1298,12 +1319,12 @@ public class BindingGeneratorImpl implements BindingGenerator {
                     }
                     ((TypeProviderImpl) typeProvider).putReferencedType(leaf.getPath(), returnType);
                 } else if (typeDef instanceof UnionType) {
-                    genTOBuilder = addTOToTypeBuilder(typeDef, typeBuilder, leaf);
+                    genTOBuilder = addTOToTypeBuilder(typeDef, typeBuilder, leaf, parentModule);
                     if (genTOBuilder != null) {
                         returnType = createReturnTypeForUnion(genTOBuilder, typeDef, typeBuilder, parentModule);
                     }
                 } else if (typeDef instanceof BitsTypeDefinition) {
-                    genTOBuilder = addTOToTypeBuilder(typeDef, typeBuilder, leaf);
+                    genTOBuilder = addTOToTypeBuilder(typeDef, typeBuilder, leaf, parentModule);
                     if (genTOBuilder != null) {
                         returnType = new ReferencedTypeImpl(genTOBuilder.getPackageName(), genTOBuilder.getName());
                     }
@@ -1320,7 +1341,8 @@ public class BindingGeneratorImpl implements BindingGenerator {
         return returnType;
     }
 
-    private void processContextRefExtension(final LeafSchemaNode leaf, final MethodSignatureBuilder getter, final Module module) {
+    private void processContextRefExtension(final LeafSchemaNode leaf, final MethodSignatureBuilder getter,
+            final Module module) {
         for (UnknownSchemaNode node : leaf.getUnknownSchemaNodes()) {
             final QName nodeType = node.getNodeType();
             if ("context-reference".equals(nodeType.getLocalName())) {
@@ -1434,8 +1456,8 @@ public class BindingGeneratorImpl implements BindingGenerator {
      *         <li>true - other cases</li>
      *         </ul>
      */
-    private boolean resolveLeafSchemaNodeAsProperty(final GeneratedTOBuilder toBuilder, final LeafSchemaNode leaf, final Type returnType,
-            final boolean isReadOnly) {
+    private boolean resolveLeafSchemaNodeAsProperty(final GeneratedTOBuilder toBuilder, final LeafSchemaNode leaf,
+            final Type returnType, final boolean isReadOnly) {
         if (returnType == null) {
             return false;
         }
@@ -1485,12 +1507,12 @@ public class BindingGeneratorImpl implements BindingGenerator {
                     returnType = new ReferencedTypeImpl(enumBuilder.getPackageName(), enumBuilder.getName());
                     ((TypeProviderImpl) typeProvider).putReferencedType(node.getPath(), returnType);
                 } else if (typeDef instanceof UnionType) {
-                    final GeneratedTOBuilder genTOBuilder = addTOToTypeBuilder(typeDef, typeBuilder, node);
+                    final GeneratedTOBuilder genTOBuilder = addTOToTypeBuilder(typeDef, typeBuilder, node, parentModule);
                     if (genTOBuilder != null) {
                         returnType = createReturnTypeForUnion(genTOBuilder, typeDef, typeBuilder, parentModule);
                     }
                 } else if (typeDef instanceof BitsTypeDefinition) {
-                    final GeneratedTOBuilder genTOBuilder = addTOToTypeBuilder(typeDef, typeBuilder, node);
+                    final GeneratedTOBuilder genTOBuilder = addTOToTypeBuilder(typeDef, typeBuilder, node, parentModule);
                     returnType = new ReferencedTypeImpl(genTOBuilder.getPackageName(), genTOBuilder.getName());
                 } else {
                     final Restrictions restrictions = BindingGeneratorUtil.getRestrictions(typeDef);
@@ -1509,6 +1531,12 @@ public class BindingGeneratorImpl implements BindingGenerator {
             final GeneratedTypeBuilder typeBuilder, final Module parentModule) {
         final GeneratedTOBuilderImpl returnType = new GeneratedTOBuilderImpl(genTOBuilder.getPackageName(),
                 genTOBuilder.getName());
+
+        returnType.setDescription(typeDef.getDescription());
+        returnType.setReference(typeDef.getReference());
+        returnType.setSchemaPath(typeDef.getPath().getPathFromRoot());
+        returnType.setModuleName(parentModule.getName());
+
         genTOBuilder.setTypedef(true);
         genTOBuilder.setIsUnion(true);
         ((TypeProviderImpl) typeProvider).addUnitsToGenTO(genTOBuilder, typeDef.getUnits());
@@ -1560,7 +1588,8 @@ public class BindingGeneratorImpl implements BindingGenerator {
      *            parent type (can be null)
      * @return generated type builder <code>schemaNode</code>
      */
-    private GeneratedTypeBuilder addDefaultInterfaceDefinition(final String packageName, final SchemaNode schemaNode, final Type parent) {
+    private GeneratedTypeBuilder addDefaultInterfaceDefinition(final String packageName, final SchemaNode schemaNode,
+            final Type parent) {
         final GeneratedTypeBuilder it = addRawInterfaceDefinition(packageName, schemaNode, "");
         if (parent == null) {
             it.addImplementsType(DATA_OBJECT);
@@ -1617,7 +1646,8 @@ public class BindingGeneratorImpl implements BindingGenerator {
      *             </ul>
      *
      */
-    private GeneratedTypeBuilder addRawInterfaceDefinition(final String packageName, final SchemaNode schemaNode, final String prefix) {
+    private GeneratedTypeBuilder addRawInterfaceDefinition(final String packageName, final SchemaNode schemaNode,
+            final String prefix) {
         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.");
@@ -1635,6 +1665,13 @@ public class BindingGeneratorImpl implements BindingGenerator {
         final GeneratedTypeBuilderImpl newType = new GeneratedTypeBuilderImpl(packageName, genTypeName);
         qnameConstant(newType, BindingMapping.QNAME_STATIC_FIELD_NAME, schemaNode.getQName());
         newType.addComment(schemaNode.getDescription());
+        newType.setDescription(schemaNode.getDescription());
+        newType.setReference(schemaNode.getReference());
+        newType.setSchemaPath(schemaNode.getPath().getPathFromRoot());
+
+        final Module module = findParentModule(schemaContext, schemaNode);
+        newType.setModuleName(module.getName());
+
         if (!genTypeBuilders.containsKey(packageName)) {
             final Map<String, GeneratedTypeBuilder> builders = new HashMap<>();
             builders.put(genTypeName, newType);
@@ -1691,8 +1728,8 @@ public class BindingGeneratorImpl implements BindingGenerator {
      * @return method signature builder which represents the getter method of
      *         <code>interfaceBuilder</code>
      */
-    private MethodSignatureBuilder constructGetter(final GeneratedTypeBuilder interfaceBuilder, final String schemaNodeName,
-            final String comment, final Type returnType) {
+    private MethodSignatureBuilder constructGetter(final GeneratedTypeBuilder interfaceBuilder,
+            final String schemaNodeName, final String comment, final Type returnType) {
         final MethodSignatureBuilder getMethod = interfaceBuilder
                 .addMethod(getterMethodName(schemaNodeName, returnType));
         getMethod.setComment(comment);
@@ -1725,7 +1762,8 @@ public class BindingGeneratorImpl implements BindingGenerator {
      *             </ul>
      */
     private void addSchemaNodeToListBuilders(final String basePackageName, final DataSchemaNode schemaNode,
-            final GeneratedTypeBuilder typeBuilder, final GeneratedTOBuilder genTOBuilder, final List<String> listKeys, final Module module) {
+            final GeneratedTypeBuilder typeBuilder, final GeneratedTOBuilder genTOBuilder, final List<String> listKeys,
+            final Module module) {
         checkArgument(schemaNode != null, "Data Schema Node cannot be NULL.");
         checkArgument(typeBuilder != null, "Generated Type Builder cannot be NULL.");
 
@@ -1753,7 +1791,8 @@ public class BindingGeneratorImpl implements BindingGenerator {
         }
     }
 
-    private void typeBuildersToGenTypes(final Module module, final GeneratedTypeBuilder typeBuilder, final GeneratedTOBuilder genTOBuilder) {
+    private void typeBuildersToGenTypes(final Module module, final GeneratedTypeBuilder typeBuilder,
+            final GeneratedTOBuilder genTOBuilder) {
         checkArgument(typeBuilder != null, "Generated Type Builder cannot be NULL.");
 
         if (genTOBuilder != null) {
@@ -1829,8 +1868,8 @@ public class BindingGeneratorImpl implements BindingGenerator {
      * @param leaf
      * @return generated TO builder for <code>typeDef</code>
      */
-    private GeneratedTOBuilder addTOToTypeBuilder(final TypeDefinition<?> typeDef, final GeneratedTypeBuilder typeBuilder,
-            final DataSchemaNode leaf) {
+    private GeneratedTOBuilder addTOToTypeBuilder(final TypeDefinition<?> typeDef,
+            final GeneratedTypeBuilder typeBuilder, final DataSchemaNode leaf, final Module parentModule) {
         final String classNameFromLeaf = BindingMapping.getClassName(leaf.getQName());
         final List<GeneratedTOBuilder> genTOBuilders = new ArrayList<>();
         final String packageName = typeBuilder.getFullyQualifiedName();
@@ -1856,7 +1895,7 @@ public class BindingGeneratorImpl implements BindingGenerator {
 
         } else if (typeDef instanceof BitsTypeDefinition) {
             genTOBuilders.add((((TypeProviderImpl) typeProvider)).provideGeneratedTOBuilderForBitsTypeDefinition(
-                    packageName, typeDef, classNameFromLeaf));
+                    packageName, typeDef, classNameFromLeaf, parentModule.getName()));
         }
         if (genTOBuilders != null && !genTOBuilders.isEmpty()) {
             for (GeneratedTOBuilder genTOBuilder : genTOBuilders) {
index 5d127d6c15cd2eaaf75b2e68fa47e82d4a83fd78..ab6b734c0bb540fdefb7bd5a94b1fa98c0cee7b8 100644 (file)
@@ -72,6 +72,9 @@ import static org.opendaylight.yangtools.sal.binding.generator.impl.CodecMapping
 
 import static extension org.opendaylight.yangtools.sal.binding.generator.util.YangSchemaUtils.*
 import java.util.ArrayList
+import org.opendaylight.yangtools.sal.binding.generator.util.DefaultSourceCodeGenerator
+import org.opendaylight.yangtools.sal.binding.generator.util.SourceCodeGeneratorFactory
+import org.opendaylight.yangtools.sal.binding.generator.util.SourceCodeGenerator
 
 class TransformerGenerator extends AbstractTransformerGenerator {
     private static val LOG = LoggerFactory.getLogger(TransformerGenerator)
@@ -90,6 +93,8 @@ class TransformerGenerator extends AbstractTransformerGenerator {
     val CtClass BINDING_CODEC
     val CtClass ctQName
 
+    val SourceCodeGeneratorFactory sourceCodeGeneratorFactory = new SourceCodeGeneratorFactory();
+
     public new(TypeResolver typeResolver, ClassPool pool) {
         super(typeResolver, pool)
 
@@ -328,17 +333,19 @@ class TransformerGenerator extends AbstractTransformerGenerator {
     private def generateKeyTransformerFor(Class<? extends Object> inputType, GeneratedType typeSpec, ListSchemaNode node) {
         try {
 
+            val SourceCodeGenerator sourceGenerator = sourceCodeGeneratorFactory.getInstance( null );
+
             //log.info("Generating DOM Codec for {} with {}", inputType, inputType.classLoader)
             val properties = typeSpec.allProperties;
             val ctCls = createClass(inputType.codecClassName) [
                 //staticField(Map,"AUGMENTATION_SERIALIZERS");
-                staticField(it, INSTANCE_IDENTIFIER_CODEC, BindingCodec)
-                staticField(it, IDENTITYREF_CODEC, BindingCodec)
-                staticQNameField(node.QName);
+                staticField(it, INSTANCE_IDENTIFIER_CODEC, BindingCodec, sourceGenerator)
+                staticField(it, IDENTITYREF_CODEC, BindingCodec, sourceGenerator)
+                staticQNameField(node.QName, sourceGenerator);
                 implementsType(BINDING_CODEC)
                 method(Object, "toDomStatic", #[QName, Object]) [
                     modifiers = PUBLIC + FINAL + STATIC
-                    bodyChecked = '''
+                    val body = '''
                         {
                             Â«QName.name» _resultName;
                             if($1 != null) {
@@ -357,10 +364,11 @@ class TransformerGenerator extends AbstractTransformerGenerator {
                             return ($r) java.util.Collections.singletonMap(_resultName,_childNodes);
                         }
                     '''
+                    setBodyChecked(body, sourceGenerator)
                 ]
                 method(Object, "fromDomStatic", #[QName, Object]) [
                     modifiers = PUBLIC + FINAL + STATIC
-                    bodyChecked = '''
+                    val body = '''
                         {
                             if($2 == null){
                                 return  null;
@@ -379,9 +387,10 @@ class TransformerGenerator extends AbstractTransformerGenerator {
                             return _value;
                         }
                     '''
+                    setBodyChecked(body, sourceGenerator)
                 ]
                 method(Object, "serialize", Object) [
-                    bodyChecked = '''
+                    val body = '''
                         {
                             java.util.Map.Entry _input =  (java.util.Map.Entry) $1;
                             Â«QName.name» _localQName = («QName.name») _input.getKey();
@@ -389,9 +398,10 @@ class TransformerGenerator extends AbstractTransformerGenerator {
                             return toDomStatic(_localQName,_keyValue);
                         }
                     '''
+                    setBodyChecked(body, sourceGenerator)
                 ]
                 method(Object, "deserialize", Object) [
-                    bodyChecked = '''
+                    val body = '''
                         {
                             Â«QName.name» _qname = QNAME;
                             if($1 instanceof java.util.Map.Entry) {
@@ -400,9 +410,11 @@ class TransformerGenerator extends AbstractTransformerGenerator {
                             return fromDomStatic(_qname,$1);
                         }
                     '''
+                    setBodyChecked(body, sourceGenerator)
                 ]
             ]
             val ret = ctCls.toClassImpl(inputType.classLoader, inputType.protectionDomain)
+            sourceGenerator.outputGeneratedSource( ctCls )
             LOG.debug("DOM Codec for {} was generated {}", inputType, ret)
             return ret as Class<? extends BindingCodec<Map<QName,Object>, ?>>;
         } catch (Exception e) {
@@ -414,17 +426,19 @@ class TransformerGenerator extends AbstractTransformerGenerator {
     private def Class<? extends BindingCodec<Object, Object>> generateCaseCodec(Class<?> inputType, GeneratedType type,
         ChoiceCaseNode node) {
         try {
+            val SourceCodeGenerator sourceGenerator = sourceCodeGeneratorFactory.getInstance( null );
+
             //log.info("Generating DOM Codec for {} with {}, TCCL is: {}", inputType, inputType.classLoader,Thread.currentThread.contextClassLoader)
             val ctCls = createClass(type.codecClassName) [
                 //staticField(Map,"AUGMENTATION_SERIALIZERS");
                 implementsType(BINDING_CODEC)
-                staticQNameField(node.QName);
-                staticField(it, INSTANCE_IDENTIFIER_CODEC, BindingCodec)
-                staticField(it, AUGMENTATION_CODEC, BindingCodec)
-                staticField(it, IDENTITYREF_CODEC, BindingCodec)
+                staticQNameField(node.QName, sourceGenerator);
+                staticField(it, INSTANCE_IDENTIFIER_CODEC, BindingCodec, sourceGenerator)
+                staticField(it, AUGMENTATION_CODEC, BindingCodec, sourceGenerator)
+                staticField(it, IDENTITYREF_CODEC, BindingCodec, sourceGenerator)
                 method(Object, "toDomStatic", #[QName, Object]) [
                     modifiers = PUBLIC + FINAL + STATIC
-                    bodyChecked = '''
+                    val body = '''
                         {
                             Â«QName.name» _resultName = Â«QName.name».create($1,QNAME.getLocalName());
                             java.util.List _childNodes = new java.util.ArrayList();
@@ -433,9 +447,10 @@ class TransformerGenerator extends AbstractTransformerGenerator {
                             return ($r) _childNodes;
                         }
                     '''
+                    setBodyChecked( body, sourceGenerator)
                 ]
                 method(Object, "serialize", Object) [
-                    bodyChecked = '''
+                    val body = '''
                         {
                             java.util.Map.Entry _input = (java.util.Map.Entry) $1;
                             Â«QName.name» _localName = QNAME;
@@ -445,23 +460,27 @@ class TransformerGenerator extends AbstractTransformerGenerator {
                             return toDomStatic(_localName,_input.getValue());
                         }
                     '''
+                    setBodyChecked( body, sourceGenerator)
                 ]
                 method(Object, "fromDomStatic", #[QName, Object, InstanceIdentifier]) [
                     modifiers = PUBLIC + FINAL + STATIC
-                    bodyChecked = deserializeBody(type, node, getBindingIdentifierByPath(node.path))
+                    setBodyChecked( deserializeBody(type, node, getBindingIdentifierByPath(node.path)),
+                                    sourceGenerator )
                 ]
                 method(Object, "deserialize", #[Object, InstanceIdentifier]) [
-                    bodyChecked = '''
+                    val body = '''
                         {
                             //System.out.println("«type.name»#deserialize: " +$1);
                             java.util.Map.Entry _input = (java.util.Map.Entry) $1;
                             return fromDomStatic((«QName.name»)_input.getKey(),_input.getValue(),$2);
                         }
                     '''
+                    setBodyChecked( body, sourceGenerator)
                 ]
             ]
 
             val ret = ctCls.toClassImpl(inputType.classLoader, inputType.protectionDomain)  as Class<? extends BindingCodec<Object, Object>>
+            sourceGenerator.outputGeneratedSource( ctCls )
             listener?.onDataContainerCodecCreated(inputType, ret);
             LOG.debug("DOM Codec for {} was generated {}", inputType, ret)
             return ret;
@@ -475,21 +494,24 @@ class TransformerGenerator extends AbstractTransformerGenerator {
         Class<?> inputType, GeneratedType typeSpec, SchemaNode node) {
         try {
 
+            val SourceCodeGenerator sourceGenerator = sourceCodeGeneratorFactory.getInstance( null );
+
             //log.info("Generating DOM Codec for {} with {}", inputType, inputType.classLoader)
             val ctCls = createClass(typeSpec.codecClassName) [
                 //staticField(Map,"AUGMENTATION_SERIALIZERS");
-                staticQNameField(node.QName);
-                staticField(it, INSTANCE_IDENTIFIER_CODEC, BindingCodec)
-                staticField(it, IDENTITYREF_CODEC, BindingCodec)
-                staticField(it, AUGMENTATION_CODEC, BindingCodec)
+                staticQNameField(node.QName, sourceGenerator);
+                staticField(it, INSTANCE_IDENTIFIER_CODEC, BindingCodec, sourceGenerator)
+                staticField(it, IDENTITYREF_CODEC, BindingCodec, sourceGenerator)
+                staticField(it, AUGMENTATION_CODEC, BindingCodec, sourceGenerator)
                 implementsType(BINDING_CODEC)
 
                 method(Object, "toDomStatic", #[QName, Object]) [
                     modifiers = PUBLIC + FINAL + STATIC
-                    bodyChecked = serializeBodyFacade(typeSpec, node)
+                    setBodyChecked( serializeBodyFacade(typeSpec, node), sourceGenerator )
                 ]
                 method(Object, "serialize", Object) [
-                    bodyChecked = '''
+                    val body = '''
                         {
                             java.util.Map.Entry _input = (java.util.Map.Entry) $1;
                             Â«QName.name» _localName = QNAME;
@@ -499,15 +521,17 @@ class TransformerGenerator extends AbstractTransformerGenerator {
                             return toDomStatic(_localName,_input.getValue());
                         }
                     '''
+                    setBodyChecked( body, sourceGenerator )
                 ]
 
                 method(Object, "fromDomStatic", #[QName, Object, InstanceIdentifier]) [
                     modifiers = PUBLIC + FINAL + STATIC
-                    bodyChecked = deserializeBody(typeSpec, node, getBindingIdentifierByPath(node.path))
+                    setBodyChecked( deserializeBody(typeSpec, node, getBindingIdentifierByPath(node.path)),
+                                    sourceGenerator )
                 ]
 
                 method(Object, "deserialize", #[Object, InstanceIdentifier]) [
-                    bodyChecked = '''
+                    val body = '''
                         {
                             Â«QName.name» _qname = QNAME;
                             if($1 instanceof java.util.Map.Entry) {
@@ -516,10 +540,14 @@ class TransformerGenerator extends AbstractTransformerGenerator {
                             return fromDomStatic(_qname,$1,$2);
                         }
                     '''
+                    setBodyChecked( body, sourceGenerator )
                 ]
             ]
 
             val ret = ctCls.toClassImpl(inputType.classLoader, inputType.protectionDomain) as Class<? extends BindingCodec<Map<QName,Object>, Object>>
+
+            sourceGenerator.outputGeneratedSource( ctCls )
+
             listener?.onDataContainerCodecCreated(inputType, ret);
             LOG.debug("DOM Codec for {} was generated {}", inputType, ret)
             return ret;
@@ -533,19 +561,21 @@ class TransformerGenerator extends AbstractTransformerGenerator {
         Class<?> inputType, GeneratedType type, AugmentationSchema node) {
         try {
 
+            val SourceCodeGenerator sourceGenerator = sourceCodeGeneratorFactory.getInstance( null );
+
             //log.info("Generating DOM Codec for {} with {}", inputType, inputType.classLoader)
             val properties = type.allProperties
             val ctCls = createClass(type.codecClassName) [
                 //staticField(Map,"AUGMENTATION_SERIALIZERS");
-                staticQNameField(node.augmentationQName);
-                staticField(it, INSTANCE_IDENTIFIER_CODEC, BindingCodec)
-                staticField(it, AUGMENTATION_CODEC, BindingCodec)
-                staticField(it, IDENTITYREF_CODEC, BindingCodec)
+                staticQNameField(node.augmentationQName, sourceGenerator);
+                staticField(it, INSTANCE_IDENTIFIER_CODEC, BindingCodec, sourceGenerator)
+                staticField(it, AUGMENTATION_CODEC, BindingCodec, sourceGenerator)
+                staticField(it, IDENTITYREF_CODEC, BindingCodec, sourceGenerator)
                 implementsType(BINDING_CODEC)
 
                 method(Object, "toDomStatic", #[QName, Object]) [
                     modifiers = PUBLIC + FINAL + STATIC
-                    bodyChecked = '''
+                    val body = '''
                         {
                             ////System.out.println("Qname " + $1);
                             ////System.out.println("Value " + $2);
@@ -560,23 +590,25 @@ class TransformerGenerator extends AbstractTransformerGenerator {
                             return ($r) _childNodes;
                         }
                     '''
+                    setBodyChecked( body, sourceGenerator )
                 ]
                 method(Object, "serialize", Object) [
-                    bodyChecked = '''
+                    val body = '''
                         {
-                        java.util.Map.Entry _input = (java.util.Map.Entry) $1;
-                        Â«QName.name» _localName = QNAME;
-                        if(_input.getKey() != null) {
-                            _localName = («QName.name») _input.getKey();
-                        }
-                        return toDomStatic(_localName,_input.getValue());
+                            java.util.Map.Entry _input = (java.util.Map.Entry) $1;
+                            Â«QName.name» _localName = QNAME;
+                            if(_input.getKey() != null) {
+                                _localName = («QName.name») _input.getKey();
+                            }
+                            return toDomStatic(_localName,_input.getValue());
                         }
                     '''
+                    setBodyChecked( body, sourceGenerator )
                 ]
 
                 method(Object, "fromDomStatic", #[QName, Object, InstanceIdentifier]) [
                     modifiers = PUBLIC + FINAL + STATIC
-                    bodyChecked = '''
+                    val body = '''
                         {
                             Â«QName.name» _localQName = QNAME;
 
@@ -598,16 +630,21 @@ class TransformerGenerator extends AbstractTransformerGenerator {
                             return _builder.build();
                         }
                     '''
+                    setBodyChecked( body, sourceGenerator )
                 ]
 
                 method(Object, "deserialize", #[Object, InstanceIdentifier]) [
-                    bodyChecked = '''
-                        return fromDomStatic(QNAME,$1,$2);
+                    val body = '''
+                        {
+                            return fromDomStatic(QNAME,$1,$2);
+                        }
                     '''
+                    setBodyChecked( body, sourceGenerator )
                 ]
             ]
 
             val ret = ctCls.toClassImpl(inputType.classLoader, inputType.protectionDomain) as Class<? extends BindingCodec<Map<QName,Object>, Object>>
+            sourceGenerator.outputGeneratedSource( ctCls )
             listener?.onDataContainerCodecCreated(inputType, ret);
             return ret;
         } catch (Exception e) {
@@ -620,18 +657,20 @@ class TransformerGenerator extends AbstractTransformerGenerator {
         Class<?> inputType, GeneratedType typeSpec, ChoiceNode node) {
         try {
 
+            val SourceCodeGenerator sourceGenerator = sourceCodeGeneratorFactory.getInstance( null );
+
             //log.info("Generating DOM Codec for {} with {}", inputType, inputType.classLoader)
             val ctCls = createClass(typeSpec.codecClassName) [
                 //staticField(Map,"AUGMENTATION_SERIALIZERS");
                 //staticQNameField(inputType);
-                staticField(it, INSTANCE_IDENTIFIER_CODEC, BindingCodec)
-                staticField(it, IDENTITYREF_CODEC, BindingCodec)
-                staticField(it, DISPATCH_CODEC, BindingCodec)
+                staticField(it, INSTANCE_IDENTIFIER_CODEC, BindingCodec, sourceGenerator)
+                staticField(it, IDENTITYREF_CODEC, BindingCodec, sourceGenerator)
+                staticField(it, DISPATCH_CODEC, BindingCodec, sourceGenerator)
                 //staticField(it,QNAME_TO_CASE_MAP,BindingCodec)
                 implementsType(BINDING_CODEC)
                 method(List, "toDomStatic", #[QName, Object]) [
                     modifiers = PUBLIC + FINAL + STATIC
-                    bodyChecked = '''
+                    val body = '''
                         {
                             if($2 == null) {
                                 return null;
@@ -645,15 +684,19 @@ class TransformerGenerator extends AbstractTransformerGenerator {
                             return («List.name») _ret;
                         }
                     '''
+                    setBodyChecked( body, sourceGenerator )
                 ]
                 method(Object, "serialize", Object) [
-                    bodyChecked = '''
-                        throw new Â«UnsupportedOperationException.name»("Direct invocation not supported.");
+                    val body = '''
+                        {
+                            throw new Â«UnsupportedOperationException.name»("Direct invocation not supported.");
+                        }
                     '''
+                    setBodyChecked( body, sourceGenerator )
                 ]
                 method(Object, "fromDomStatic", #[QName, Map, InstanceIdentifier]) [
                     modifiers = PUBLIC + FINAL + STATIC
-                    bodyChecked = '''
+                    val body = '''
                         {
                             if («DISPATCH_CODEC» == null) {
                                 throw new Â«IllegalStateException.name»("Implementation of codec was not initialized.");
@@ -661,15 +704,20 @@ class TransformerGenerator extends AbstractTransformerGenerator {
                             return Â«DISPATCH_CODEC».deserialize($2,$3);
                         }
                     '''
+                    setBodyChecked( body, sourceGenerator )
                 ]
                 method(Object, "deserialize", #[Object, InstanceIdentifier]) [
-                    bodyChecked = '''
-                        throw new Â«UnsupportedOperationException.name»("Direct invocation not supported.");
+                    val body = '''
+                        {
+                            throw new Â«UnsupportedOperationException.name»("Direct invocation not supported.");
+                        }
                     '''
+                    setBodyChecked( body, sourceGenerator )
                 ]
             ]
 
             val rawRet = ctCls.toClassImpl(inputType.classLoader, inputType.protectionDomain)
+            sourceGenerator.outputGeneratedSource( ctCls )
             val ret = rawRet as Class<? extends BindingCodec<Map<QName,Object>, Object>>;
             listener?.onChoiceCodecCreated(inputType, ret, node);
             LOG.debug("DOM Codec for {} was generated {}", inputType, ret)
@@ -908,10 +956,13 @@ class TransformerGenerator extends AbstractTransformerGenerator {
         Class<?> inputType, GeneratedTransferObject typeSpec, TypeDefinition<?> typeDef) {
         try {
 
+            val SourceCodeGenerator sourceGenerator = sourceCodeGeneratorFactory.getInstance( null );
+
             val returnType = typeSpec.valueReturnType;
             if (returnType == null) {
-                val ctCls = createDummyImplementation(inputType, typeSpec);
+                val ctCls = createDummyImplementation(inputType, typeSpec, sourceGenerator);
                 val ret = ctCls.toClassImpl(inputType.classLoader, inputType.protectionDomain)
+                sourceGenerator.outputGeneratedSource( ctCls )
                 return ret as Class<? extends BindingCodec<Map<QName,Object>, Object>>;
             }
 
@@ -919,14 +970,14 @@ class TransformerGenerator extends AbstractTransformerGenerator {
                 //staticField(Map,"AUGMENTATION_SERIALIZERS");
                 if (inputType.isYangBindingAvailable) {
                     implementsType(BINDING_CODEC)
-                    staticField(it, INSTANCE_IDENTIFIER_CODEC, BindingCodec)
-                    staticField(it, IDENTITYREF_CODEC, BindingCodec)
+                    staticField(it, INSTANCE_IDENTIFIER_CODEC, BindingCodec, sourceGenerator)
+                    staticField(it, IDENTITYREF_CODEC, BindingCodec, sourceGenerator)
                     implementsType(BindingDeserializer.asCtClass)
                 }
                 method(Object, "toDomValue", Object) [
                     modifiers = PUBLIC + FINAL + STATIC
                     val ctSpec = typeSpec.asCtClass;
-                    bodyChecked = '''
+                    val body = '''
                         {
                             ////System.out.println("«inputType.simpleName»#toDomValue: "+$1);
 
@@ -941,17 +992,19 @@ class TransformerGenerator extends AbstractTransformerGenerator {
                             return _domValue;
                         }
                     '''
+                    setBodyChecked( body, sourceGenerator )
                 ]
                 method(Object, "serialize", Object) [
-                    bodyChecked = '''
+                    val body = '''
                         {
                             return toDomValue($1);
                         }
                     '''
+                    setBodyChecked( body, sourceGenerator )
                 ]
                 method(Object, "fromDomValue", Object) [
                     modifiers = PUBLIC + FINAL + STATIC
-                    bodyChecked = '''
+                    val body = '''
                         {
                             ////System.out.println("«inputType.simpleName»#fromDomValue: "+$1);
 
@@ -963,16 +1016,20 @@ class TransformerGenerator extends AbstractTransformerGenerator {
                             return _value;
                         }
                     '''
+                    setBodyChecked( body, sourceGenerator )
                 ]
                 method(Object, "deserialize", Object) [
-                    bodyChecked = '''{
+                    val body = '''
+                        {
                             return fromDomValue($1);
-                    }
+                        }
                     '''
+                    setBodyChecked( body, sourceGenerator )
                 ]
             ]
 
             val ret = ctCls.toClassImpl(inputType.classLoader, inputType.protectionDomain)
+            sourceGenerator.outputGeneratedSource( ctCls )
             LOG.debug("DOM Codec for {} was generated {}", inputType, ret)
             return ret as Class<? extends BindingCodec<Map<QName,Object>, Object>>;
         } catch (Exception e) {
@@ -986,20 +1043,22 @@ class TransformerGenerator extends AbstractTransformerGenerator {
     private def dispatch Class<? extends BindingCodec<Map<QName, Object>, Object>> generateValueTransformer(
         Class<?> inputType, GeneratedTransferObject typeSpec, UnionTypeDefinition typeDef) {
         try {
+            val SourceCodeGenerator sourceGenerator = sourceCodeGeneratorFactory.getInstance( null );
+
             val ctCls = createClass(typeSpec.codecClassName) [
                 val properties = typeSpec.allProperties;
                 val getterToTypeDefinition = XtendHelper.getTypes(typeDef).toMap[type|type.QName.getterName];
                 //staticField(Map,"AUGMENTATION_SERIALIZERS");
                 if (inputType.isYangBindingAvailable) {
                     implementsType(BINDING_CODEC)
-                    staticField(it, INSTANCE_IDENTIFIER_CODEC, BindingCodec)
-                    staticField(it, IDENTITYREF_CODEC, BindingCodec)
+                    staticField(it, INSTANCE_IDENTIFIER_CODEC, BindingCodec, sourceGenerator)
+                    staticField(it, IDENTITYREF_CODEC, BindingCodec, sourceGenerator)
                     implementsType(BindingDeserializer.asCtClass)
                 }
                 method(Object, "toDomValue", Object) [
                     modifiers = PUBLIC + FINAL + STATIC
                     val ctSpec = inputType.asCtClass;
-                    bodyChecked = '''
+                    val body = '''
                         {
                             ////System.out.println("«inputType.simpleName»#toDomValue: "+$1);
 
@@ -1021,17 +1080,19 @@ class TransformerGenerator extends AbstractTransformerGenerator {
                             return null;
                         }
                     '''
+                    setBodyChecked( body, sourceGenerator )
                 ]
                 method(Object, "serialize", Object) [
-                    bodyChecked = '''
+                    val body = '''
                         {
                             return toDomValue($1);
                         }
                     '''
+                    setBodyChecked( body, sourceGenerator )
                 ]
                 method(Object, "fromDomValue", Object) [
                     modifiers = PUBLIC + FINAL + STATIC
-                    bodyChecked = '''
+                    val body = '''
                         {
                             ////System.out.println("«inputType.simpleName»#fromDomValue: "+$1);
 
@@ -1045,16 +1106,20 @@ class TransformerGenerator extends AbstractTransformerGenerator {
                             return null;
                         }
                     '''
+                    setBodyChecked( body, sourceGenerator )
                 ]
                 method(Object, "deserialize", Object) [
-                    bodyChecked = '''{
+                    val body = '''
+                        {
                             return fromDomValue($1);
-                    }
+                        }
                     '''
+                    setBodyChecked( body, sourceGenerator )
                 ]
             ]
 
             val ret = ctCls.toClassImpl(inputType.classLoader, inputType.protectionDomain)
+            sourceGenerator.outputGeneratedSource( ctCls )
             LOG.debug("DOM Codec for {} was generated {}", inputType, ret)
             return ret as Class<? extends BindingCodec<Map<QName,Object>, Object>>;
         } catch (Exception e) {
@@ -1068,18 +1133,20 @@ class TransformerGenerator extends AbstractTransformerGenerator {
     private def dispatch Class<? extends BindingCodec<Map<QName, Object>, Object>> generateValueTransformer(
         Class<?> inputType, GeneratedTransferObject typeSpec, BitsTypeDefinition typeDef) {
         try {
+            val SourceCodeGenerator sourceGenerator = sourceCodeGeneratorFactory.getInstance( null );
+
             val ctCls = createClass(typeSpec.codecClassName) [
                 //staticField(Map,"AUGMENTATION_SERIALIZERS");
                 if (inputType.isYangBindingAvailable) {
                     implementsType(BINDING_CODEC)
-                    staticField(it, INSTANCE_IDENTIFIER_CODEC, BindingCodec)
-                    staticField(it, IDENTITYREF_CODEC, BindingCodec)
+                    staticField(it, INSTANCE_IDENTIFIER_CODEC, BindingCodec, sourceGenerator)
+                    staticField(it, IDENTITYREF_CODEC, BindingCodec, sourceGenerator)
                     implementsType(BindingDeserializer.asCtClass)
                 }
                 method(Object, "toDomValue", Object) [
                     modifiers = PUBLIC + FINAL + STATIC
                     val ctSpec = typeSpec.asCtClass;
-                    bodyChecked = '''
+                    val body = '''
                         {
                             ////System.out.println("«inputType.simpleName»#toDomValue: "+$1);
 
@@ -1102,21 +1169,20 @@ class TransformerGenerator extends AbstractTransformerGenerator {
                             return _domValue;
                         }
                     '''
+                    setBodyChecked( body, sourceGenerator )
                 ]
                 method(Object, "serialize", Object) [
-                    bodyChecked = '''
+                    val body = '''
                         {
                             return toDomValue($1);
                         }
                     '''
+                    setBodyChecked( body, sourceGenerator )
                 ]
                 method(Object, "fromDomValue", Object) [
                     modifiers = PUBLIC + FINAL + STATIC
-                    val sortedBits = new ArrayList(typeDef.bits)
-                    Collections.sort(sortedBits, [o1, o2|
-                        o1.propertyName.compareTo(o2.propertyName)
-                    ])
-                    bodyChecked = '''
+                    val sortedBits = typeDef.bits.sort[o1, o2|o1.propertyName.compareTo(o2.propertyName)]
+                    val body = '''
                         {
                             //System.out.println("«inputType.simpleName»#fromDomValue: "+$1);
 
@@ -1131,16 +1197,20 @@ class TransformerGenerator extends AbstractTransformerGenerator {
                             return new Â«inputType.resolvedName»(«FOR bit : sortedBits SEPARATOR ","»«bit.propertyName»«ENDFOR»);
                         }
                     '''
+                    setBodyChecked( body, sourceGenerator )
                 ]
                 method(Object, "deserialize", Object) [
-                    bodyChecked = '''{
+                    val body = '''
+                        {
                             return fromDomValue($1);
-                    }
+                        }
                     '''
+                    setBodyChecked( body, sourceGenerator )
                 ]
             ]
 
             val ret = ctCls.toClassImpl(inputType.classLoader, inputType.protectionDomain)
+            sourceGenerator.outputGeneratedSource( ctCls )
             LOG.debug("DOM Codec for {} was generated {}", inputType, ret)
             return ret as Class<? extends BindingCodec<Map<QName,Object>, Object>>;
         } catch (Exception e) {
@@ -1170,42 +1240,48 @@ class TransformerGenerator extends AbstractTransformerGenerator {
         }
     }
 
-    private def createDummyImplementation(Class<?> object, GeneratedTransferObject typeSpec) {
+    private def createDummyImplementation(Class<?> object, GeneratedTransferObject typeSpec,
+                                          SourceCodeGenerator sourceGenerator ) {
         LOG.trace("Generating Dummy DOM Codec for {} with {}", object, object.classLoader)
         return createClass(typeSpec.codecClassName) [
             if (object.isYangBindingAvailable) {
                 implementsType(BINDING_CODEC)
-                staticField(it, INSTANCE_IDENTIFIER_CODEC, BindingCodec)
-                staticField(it, IDENTITYREF_CODEC, BindingCodec)
+                staticField(it, INSTANCE_IDENTIFIER_CODEC, BindingCodec, sourceGenerator)
+                staticField(it, IDENTITYREF_CODEC, BindingCodec, sourceGenerator)
                 implementsType(BindingDeserializer.asCtClass)
             }
             //implementsType(BindingDeserializer.asCtClass)
             method(Object, "toDomValue", Object) [
                 modifiers = PUBLIC + FINAL + STATIC
-                bodyChecked = '''{
-                    if($1 == null) {
-                        return null;
-                    }
-                    return $1.toString();
-
+                val body = '''
+                    {
+                        if($1 == null) {
+                            return null;
+                        }
+                        return $1.toString();
                     }'''
+                setBodyChecked( body, sourceGenerator )
             ]
             method(Object, "serialize", Object) [
-                bodyChecked = '''
+                val body = '''
                     {
                         return toDomValue($1);
                     }
                 '''
+                setBodyChecked( body, sourceGenerator )
             ]
             method(Object, "fromDomValue", Object) [
                 modifiers = PUBLIC + FINAL + STATIC
-                bodyChecked = '''return null;'''
+                val body = '''return null;'''
+                setBodyChecked( body, sourceGenerator )
             ]
             method(Object, "deserialize", Object) [
-                bodyChecked = '''{
+                val body = '''
+                    {
                         return fromDomValue($1);
                     }
                     '''
+                setBodyChecked( body, sourceGenerator )
             ]
         ]
     }
@@ -1233,13 +1309,16 @@ class TransformerGenerator extends AbstractTransformerGenerator {
         }
         val enumSchema = enumSchemaType;
         try {
+            val SourceCodeGenerator sourceGenerator = sourceCodeGeneratorFactory.getInstance( null );
+
             //log.info("Generating DOM Codec for {} with {}", inputType, inputType.classLoader)
             val ctCls = createClass(typeSpec.codecClassName) [
                 //staticField(Map,"AUGMENTATION_SERIALIZERS");
                 //implementsType(BINDING_CODEC)
                 method(Object, "toDomValue", Object) [
                     modifiers = PUBLIC + FINAL + STATIC
-                    bodyChecked = '''{
+                    val body = '''
+                        {
                             if($1 == null) {
                                 return null;
                             }
@@ -1252,15 +1331,19 @@ class TransformerGenerator extends AbstractTransformerGenerator {
                             return null;
                         }
                     '''
+                    setBodyChecked( body, sourceGenerator )
                 ]
                 method(Object, "serialize", Object) [
-                    bodyChecked = '''
-                        return toDomValue($1);
+                    val body = '''
+                        {
+                            return toDomValue($1);
+                        }
                     '''
+                    setBodyChecked( body, sourceGenerator )
                 ]
                 method(Object, "fromDomValue", Object) [
                     modifiers = PUBLIC + FINAL + STATIC
-                    bodyChecked = '''
+                    val body = '''
                         {
                             if($1 == null) {
                                 return null;
@@ -1274,15 +1357,20 @@ class TransformerGenerator extends AbstractTransformerGenerator {
                             return null;
                         }
                     '''
+                    setBodyChecked( body, sourceGenerator )
                 ]
                 method(Object, "deserialize", Object) [
-                    bodyChecked = '''
-                        return fromDomValue($1);
+                    val body = '''
+                        {
+                            return fromDomValue($1);
+                        }
                     '''
+                    setBodyChecked( body, sourceGenerator )
                 ]
             ]
 
             val ret = ctCls.toClassImpl(inputType.classLoader, inputType.protectionDomain)
+            sourceGenerator.outputGeneratedSource( ctCls )
             LOG.debug("DOM Codec for {} was generated {}", inputType, ret)
             return ret;
         } catch (CodeGenerationException e) {
@@ -1347,11 +1435,13 @@ class TransformerGenerator extends AbstractTransformerGenerator {
     */
     private def getBuilderName(GeneratedType type) '''«type.resolvedName»Builder'''
 
-    private def staticQNameField(CtClass it, QName node) {
+    private def staticQNameField(CtClass it, QName node, SourceCodeGenerator sourceGenerator) {
         val field = new CtField(ctQName, "QNAME", it);
         field.modifiers = PUBLIC + FINAL + STATIC;
-        addField(field,
-            '''«QName.asCtClass.name».create("«node.namespace»","«node.formattedRevision»","«node.localName»")''')
+        val code = '''«QName.asCtClass.name».create("«node.namespace»","«node.formattedRevision»","«node.localName»")'''
+        addField(field, code )
+
+        sourceGenerator.appendField( field, code );
     }
 
     private def String serializeBodyImpl(GeneratedType type, DataNodeContainer nodeContainer) '''
@@ -1605,9 +1695,11 @@ class TransformerGenerator extends AbstractTransformerGenerator {
         throw exception;
     }
 
-    private def setBodyChecked(CtMethod method, String body) {
+    private def setBodyChecked(CtMethod method, String body, SourceCodeGenerator sourceGenerator ) {
         try {
             method.setBody(body);
+
+            sourceGenerator.appendMethod( method, body );
         } catch (CannotCompileException e) {
             LOG.error("Cannot compile method: {}#{} {}, Reason: {} Body: {}", method.declaringClass, method.name,
                 method.signature, e.message, body)
diff --git a/code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/util/DefaultSourceCodeGenerator.java b/code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/util/DefaultSourceCodeGenerator.java
new file mode 100644 (file)
index 0000000..5df91cd
--- /dev/null
@@ -0,0 +1,139 @@
+/*
+ * Copyright (c) 2014 Brocade Communications 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.yangtools.sal.binding.generator.util;
+
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javassist.CtClass;
+import javassist.CtField;
+import javassist.CtMethod;
+import javassist.Modifier;
+import javassist.NotFoundException;
+
+/**
+ * The default implementation of the SourceCodeGenerator interface that generates readable source code
+ * for a runtime generated class. The appendField/appendMethod methods output source code to a temporary
+ * StringBuilder. When outputGeneratedSource is called, the entire class source code is generated and
+ * written to a file under a specified directory.
+ *
+ * @author Thomas Pantelis
+ */
+public class DefaultSourceCodeGenerator implements SourceCodeGenerator {
+    private static final Logger LOG = LoggerFactory.getLogger(DefaultSourceCodeGenerator.class);
+
+    private static final String GENERATED_SOURCE_DIR_PROP = "org.opendaylight.yangtools.sal.generatedCodecSourceDir";
+
+    private final StringBuilder builder = new StringBuilder();
+    private final String generatedSourceDir;
+
+    /**
+     * Constructor.
+     *
+     * @param generatedSourceDir the directory in which to put generated source files. If null, the directory
+     *     is obtained from a system property (<i>org.opendaylight.yangtools.sal.generatedCodecSourceDir</i>) or
+     *     defaults to "generated-codecs".
+     */
+    public DefaultSourceCodeGenerator( String generatedSourceDir ) {
+        if( generatedSourceDir != null ) {
+            this.generatedSourceDir = generatedSourceDir;
+        }
+        else {
+            this.generatedSourceDir = System.getProperty( GENERATED_SOURCE_DIR_PROP, "generated-codecs" );
+        }
+    }
+
+    @Override
+    public void appendField(CtField field, String value) {
+        try {
+            builder.append('\n')
+                    .append(Modifier.toString(field.getModifiers()))
+                    .append(' ').append(field.getType().getName()).append(' ')
+                    .append(field.getName());
+            if (value != null) {
+                builder.append(" = ").append(value);
+            }
+
+            builder.append(";\n");
+        } catch (NotFoundException e) {
+            LOG.error("Error building field source for " + field.getName(), e);
+        }
+    }
+
+    @Override
+    public void appendMethod(CtMethod method, String code) {
+        try {
+            builder.append('\n')
+                    .append(Modifier.toString(method.getModifiers()))
+                    .append(' ').append(method.getReturnType().getName())
+                    .append(' ').append(method.getName()).append("( ");
+
+            CtClass[] paramTypes = method.getParameterTypes();
+            if (paramTypes != null) {
+                for (int i = 0; i < paramTypes.length; i++) {
+                    if (i > 0)
+                        builder.append(", ");
+                    builder.append(paramTypes[i].getName()).append(" $")
+                            .append(i + 1);
+                }
+            }
+
+            builder.append(" )\n").append(code).append("\n\n");
+        } catch (NotFoundException e) {
+            LOG.error("Error building method source for " + method.getName(), e);
+        }
+    }
+
+    @Override
+    public void outputGeneratedSource(CtClass ctClass) {
+        String name = ctClass.getName();
+
+        StringBuilder classBuilder = new StringBuilder();
+        classBuilder.append(Modifier.toString(ctClass.getModifiers()))
+                .append(" class ").append(ctClass.getSimpleName());
+
+        try {
+            CtClass superClass = ctClass.getSuperclass();
+            if (superClass != null) {
+                classBuilder.append(" extends ").append(superClass.getName());
+            }
+
+            CtClass[] interfaces = ctClass.getInterfaces();
+            if (interfaces.length > 0) {
+                classBuilder.append(" implements ");
+                for (int i = 0; i < interfaces.length; i++) {
+                    if (i > 0) {
+                        classBuilder.append(", ");
+                    }
+
+                    classBuilder.append(interfaces[i].getName());
+                }
+            }
+
+            classBuilder.append(" {\n").append(builder.toString())
+                    .append("\n}");
+        } catch (NotFoundException e) {
+            LOG.error("Error building class source for " + name, e);
+            return;
+        }
+
+        File dir = new File(generatedSourceDir);
+        dir.mkdir();
+        try (FileWriter writer = new FileWriter(new File(dir, name + ".java"))) {
+            writer.append(classBuilder.toString());
+            writer.flush();
+        } catch (IOException e) {
+            LOG.error("Error writing class source for " + name, e);
+        }
+    }
+}
index 252fca7107953dff0ff04cc49882d48e334ee076..7f92e704ee08c2214530751cc54a0a26c5266e5a 100644 (file)
@@ -23,7 +23,6 @@ import javassist.CtMethod;
 import javassist.LoaderClassPath;
 import javassist.Modifier;
 import javassist.NotFoundException;
-
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -149,9 +148,20 @@ public final class JavassistUtils {
     }
 
     public CtField staticField(final CtClass it, final String name, final Class<? extends Object> returnValue) throws CannotCompileException {
+        return staticField(it, name, returnValue, null);
+    }
+
+    public CtField staticField(final CtClass it, final String name,
+                               final Class<? extends Object> returnValue,
+                               SourceCodeGenerator sourceGenerator) throws CannotCompileException {
         final CtField field = new CtField(asCtClass(returnValue), name, it);
         field.setModifiers(Modifier.PUBLIC + Modifier.STATIC);
         it.addField(field);
+
+        if (sourceGenerator != null) {
+            sourceGenerator.appendField(field, null);
+        }
+
         return field;
     }
 
diff --git a/code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/util/NullSourceCodeGenerator.java b/code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/util/NullSourceCodeGenerator.java
new file mode 100644 (file)
index 0000000..f087d54
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2014 Brocade Communications 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.yangtools.sal.binding.generator.util;
+
+import javassist.CtClass;
+import javassist.CtField;
+import javassist.CtMethod;
+
+/**
+ * Implementation of the SourceCodeGenerator interface that does nothing.
+ *
+ * @author Thomas Pantelis
+ */
+public class NullSourceCodeGenerator implements SourceCodeGenerator {
+
+    @Override
+    public void appendField( CtField field, String value ) {
+    }
+
+    @Override
+    public void appendMethod( CtMethod method, String code ) {
+    }
+
+    @Override
+    public void outputGeneratedSource( CtClass ctClass ) {
+    }
+}
diff --git a/code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/util/SourceCodeGenerator.java b/code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/util/SourceCodeGenerator.java
new file mode 100644 (file)
index 0000000..bfbb031
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2014 Brocade Communications 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.yangtools.sal.binding.generator.util;
+
+import javassist.CtClass;
+import javassist.CtField;
+import javassist.CtMethod;
+
+/**
+ * Interface for a class that that generates readable source code for a runtime generated class.
+ * The appendField/appendMethod methods append source code to a temporary output. When outputGeneratedSource
+ * is called, the entire class source code is generated and outputted.
+ *
+ * @author Thomas Pantelis
+ */
+public interface SourceCodeGenerator {
+
+    /**
+     * Appends the given class field and value to the temporary output.
+     */
+    void appendField( CtField field, String value );
+
+    /**
+     * Appends the given method and source code body to the temporary output.
+     */
+    void appendMethod( CtMethod method, String code );
+
+    /**
+     * Generates the full source code for the given class and outputs it.
+     */
+    void outputGeneratedSource( CtClass ctClass );
+}
\ No newline at end of file
diff --git a/code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/util/SourceCodeGeneratorFactory.java b/code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/util/SourceCodeGeneratorFactory.java
new file mode 100644 (file)
index 0000000..23549c6
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2014 Brocade Communications 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.yangtools.sal.binding.generator.util;
+
+/**
+ * Factory class for creating SourceCodeGenerator instances.
+ *
+ * @author Thomas Pantelis
+ */
+public class SourceCodeGeneratorFactory {
+
+    private static final String GENERATE_CODEC_SOURCE_PROP = "org.opendaylight.yangtools.sal.generateCodecSource";
+
+    private static final SourceCodeGenerator NULL_GENERATOR = new NullSourceCodeGenerator();
+
+    /**
+     * Gets a SourceCodeGenerator instance.
+     * <p>
+     * Generation of source code is controlled by the <i>org.opendaylight.yangtools.sal.generateCodecSource</i>
+     * system property. If set to true, a DefaultSourceCodeGenerator instance is returned, otherwise a
+     * NullSourceCodeGenerator is returned.
+     *
+     * @param generatedSourceDir the directory in which to put generated source files. If null,
+     *     a default is used (see DefaultSourceCodeGenerator).
+     */
+    public SourceCodeGenerator getInstance( String generatedSourceDir ) {
+
+        boolean generateSource = Boolean.valueOf( System.getProperty( GENERATE_CODEC_SOURCE_PROP, "false") );
+        if( generateSource ) {
+            return new DefaultSourceCodeGenerator( generatedSourceDir );
+        }
+
+        return NULL_GENERATOR;
+    }
+}
index 2a5b7462dd040ca83e543e4fa502ef3a573bc9c1..0b7e071fa8452696d8262416dc7f3f1136bb1b47 100644 (file)
@@ -7,12 +7,16 @@
  */
 package org.opendaylight.yangtools.binding.generator.util;
 
+import com.google.common.base.CharMatcher;
+import com.google.common.collect.Iterables;
+
 import java.io.ByteArrayOutputStream;
 import java.io.DataOutputStream;
 import java.io.IOException;
 import java.security.MessageDigest;
 import java.security.NoSuchAlgorithmException;
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.Collections;
 import java.util.Comparator;
 import java.util.Iterator;
@@ -39,9 +43,6 @@ import org.opendaylight.yangtools.yang.model.api.type.RangeConstraint;
 import org.opendaylight.yangtools.yang.model.api.type.UnsignedIntegerTypeDefinition;
 import org.opendaylight.yangtools.yang.model.util.ExtendedType;
 
-import com.google.common.base.CharMatcher;
-import com.google.common.collect.Iterables;
-
 /**
  * Contains the methods for converting strings to valid JAVA language strings
  * (package names, class names, attribute names).
@@ -63,6 +64,42 @@ public final class BindingGeneratorUtil {
     private static final CharMatcher DOT_MATCHER = CharMatcher.is('.');
     private static final CharMatcher DASH_COLON_MATCHER = CharMatcher.anyOf("-:");
 
+    private static final Restrictions EMPTY_RESTRICTIONS = new Restrictions() {
+        @Override
+        public List<LengthConstraint> getLengthConstraints() {
+            return Collections.emptyList();
+        }
+
+        @Override
+        public List<PatternConstraint> getPatternConstraints() {
+            return Collections.emptyList();
+        }
+
+        @Override
+        public List<RangeConstraint> getRangeConstraints() {
+            return Collections.emptyList();
+        }
+
+        @Override
+        public boolean isEmpty() {
+            return true;
+        }
+    };
+
+    private static final Comparator<TypeMemberBuilder<?>> SUID_MEMBER_COMPARATOR = new Comparator<TypeMemberBuilder<?>>() {
+        @Override
+        public int compare(final TypeMemberBuilder<?> o1, final TypeMemberBuilder<?> o2) {
+            return o1.getName().compareTo(o2.getName());
+        }
+    };
+
+    private static final Comparator<Type> SUID_NAME_COMPARATOR = new Comparator<Type>() {
+        @Override
+        public int compare(final Type o1, final Type o2) {
+            return o1.getFullyQualifiedName().compareTo(o2.getFullyQualifiedName());
+        }
+    };
+
     /**
      * Converts <code>parameterName</code> to valid JAVA parameter name.
      *
@@ -291,6 +328,16 @@ public final class BindingGeneratorUtil {
         return sb.toString();
     }
 
+    private static <T> Iterable<T> sortedCollection(final Comparator<? super T> comparator, final Collection<T> input) {
+        if (input.size() > 1) {
+            final List<T> ret = new ArrayList<>(input);
+            Collections.sort(ret, comparator);
+            return ret;
+        } else {
+            return input;
+        }
+    }
+
     public static long computeDefaultSUID(final GeneratedTypeBuilderBase<?> to) {
         try {
             ByteArrayOutputStream bout = new ByteArrayOutputStream();
@@ -299,33 +346,15 @@ public final class BindingGeneratorUtil {
             dout.writeUTF(to.getName());
             dout.writeInt(to.isAbstract() ? 3 : 7);
 
-            List<Type> impl = to.getImplementsTypes();
-            Collections.sort(impl, new Comparator<Type>() {
-                @Override
-                public int compare(final Type o1, final Type o2) {
-                    return o1.getFullyQualifiedName().compareTo(o2.getFullyQualifiedName());
-                }
-            });
-            for (Type ifc : impl) {
+            for (Type ifc : sortedCollection(SUID_NAME_COMPARATOR, to.getImplementsTypes())) {
                 dout.writeUTF(ifc.getFullyQualifiedName());
             }
 
-            Comparator<TypeMemberBuilder<?>> comparator = new Comparator<TypeMemberBuilder<?>>() {
-                @Override
-                public int compare(final TypeMemberBuilder<?> o1, final TypeMemberBuilder<?> o2) {
-                    return o1.getName().compareTo(o2.getName());
-                }
-            };
-
-            List<GeneratedPropertyBuilder> props = to.getProperties();
-            Collections.sort(props, comparator);
-            for (GeneratedPropertyBuilder gp : props) {
+            for (GeneratedPropertyBuilder gp : sortedCollection(SUID_MEMBER_COMPARATOR, to.getProperties())) {
                 dout.writeUTF(gp.getName());
             }
 
-            List<MethodSignatureBuilder> methods = to.getMethodDefinitions();
-            Collections.sort(methods, comparator);
-            for (MethodSignatureBuilder m : methods) {
+            for (MethodSignatureBuilder m : sortedCollection(SUID_MEMBER_COMPARATOR, to.getMethodDefinitions())) {
                 if (!(m.getAccessModifier().equals(AccessModifier.PRIVATE))) {
                     dout.writeUTF(m.getName());
                     dout.write(m.getAccessModifier().ordinal());
@@ -334,42 +363,52 @@ public final class BindingGeneratorUtil {
 
             dout.flush();
 
-            MessageDigest md = MessageDigest.getInstance("SHA");
-            byte[] hashBytes = md.digest(bout.toByteArray());
-            long hash = 0;
-            for (int i = Math.min(hashBytes.length, 8) - 1; i >= 0; i--) {
-                hash = (hash << 8) | (hashBytes[i] & 0xFF);
+            try {
+                MessageDigest md = MessageDigest.getInstance("SHA");
+                byte[] hashBytes = md.digest(bout.toByteArray());
+                long hash = 0;
+                for (int i = Math.min(hashBytes.length, 8) - 1; i >= 0; i--) {
+                    hash = (hash << 8) | (hashBytes[i] & 0xFF);
+                }
+                return hash;
+            } catch (NoSuchAlgorithmException ex) {
+                throw new SecurityException(ex.getMessage());
             }
-            return hash;
         } catch (IOException ex) {
             throw new InternalError();
-        } catch (NoSuchAlgorithmException ex) {
-            throw new SecurityException(ex.getMessage());
         }
     }
 
     public static Restrictions getRestrictions(final TypeDefinition<?> type) {
-        final List<LengthConstraint> length = new ArrayList<>();
-        final List<PatternConstraint> pattern = new ArrayList<>();
-        final List<RangeConstraint> range = new ArrayList<>();
-
-        if (type instanceof ExtendedType) {
-            ExtendedType ext = (ExtendedType)type;
-            TypeDefinition<?> base = ext.getBaseType();
-            length.addAll(ext.getLengthConstraints());
-            pattern.addAll(ext.getPatternConstraints());
-            range.addAll(ext.getRangeConstraints());
-
-            if (base instanceof IntegerTypeDefinition && range.isEmpty()) {
-                range.addAll(((IntegerTypeDefinition)base).getRangeConstraints());
-            } else if (base instanceof UnsignedIntegerTypeDefinition && range.isEmpty()) {
-                range.addAll(((UnsignedIntegerTypeDefinition)base).getRangeConstraints());
-            } else if (base instanceof DecimalTypeDefinition && range.isEmpty()) {
-                range.addAll(((DecimalTypeDefinition)base).getRangeConstraints());
+        // Base types have no constraints, so get over it quickly
+        if (!(type instanceof ExtendedType)) {
+            return EMPTY_RESTRICTIONS;
+        }
+
+        // Take care of the extended types ...
+        final ExtendedType ext = (ExtendedType)type;
+        final List<LengthConstraint> length = ext.getLengthConstraints();
+        final List<PatternConstraint> pattern = ext.getPatternConstraints();
+
+        List<RangeConstraint> tmp = ext.getRangeConstraints();
+        if (tmp.isEmpty()) {
+            final TypeDefinition<?> base = ext.getBaseType();
+            if (base instanceof IntegerTypeDefinition) {
+                tmp = ((IntegerTypeDefinition)base).getRangeConstraints();
+            } else if (base instanceof UnsignedIntegerTypeDefinition) {
+                tmp = ((UnsignedIntegerTypeDefinition)base).getRangeConstraints();
+            } else if (base instanceof DecimalTypeDefinition) {
+                tmp = ((DecimalTypeDefinition)base).getRangeConstraints();
             }
+        }
 
+        // Now, this may have ended up being empty, too...
+        if (length.isEmpty() && pattern.isEmpty() && tmp.isEmpty()) {
+            return EMPTY_RESTRICTIONS;
         }
 
+        // Nope, not empty allocate a holder
+        final List<RangeConstraint> range = tmp;
         return new Restrictions() {
             @Override
             public List<RangeConstraint> getRangeConstraints() {
@@ -385,7 +424,7 @@ public final class BindingGeneratorUtil {
             }
             @Override
             public boolean isEmpty() {
-                return range.isEmpty() && pattern.isEmpty() && length.isEmpty();
+                return false;
             }
         };
     }
index 870fcd9ec864546637ff8ed34dd2b75e78c9663c..be8d905e6baafa1a4690bd6d40d3aa6246cce785 100644 (file)
@@ -22,6 +22,8 @@ import org.opendaylight.yangtools.sal.binding.model.api.Type;
 import org.opendaylight.yangtools.sal.binding.model.api.type.builder.AnnotationTypeBuilder;
 import org.opendaylight.yangtools.sal.binding.model.api.type.builder.EnumBuilder;
 import org.opendaylight.yangtools.yang.binding.BindingMapping;
+import org.opendaylight.yangtools.yang.common.QName;
+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;
 
@@ -30,6 +32,10 @@ public final class EnumerationBuilderImpl extends AbstractBaseType implements En
     private final String name;
     private final List<Enumeration.Pair> values;
     private final List<AnnotationTypeBuilder> annotationBuilders = new ArrayList<>();
+    private String description;
+    private String reference;
+    private String moduleName;
+    private Iterable<QName> schemaPath;
 
     public EnumerationBuilderImpl(final String packageName, final String name) {
         super(packageName, name);
@@ -38,6 +44,24 @@ public final class EnumerationBuilderImpl extends AbstractBaseType implements En
         values = new ArrayList<>();
     }
 
+    public void setReference(final String reference) {
+        this.reference = reference;
+    }
+
+    public void setModuleName(final String moduleName) {
+        this.moduleName = moduleName;
+    }
+
+    public void setSchemaPath(final Iterable<QName> schemaPath) {
+        this.schemaPath = schemaPath;
+    }
+
+    @Override
+    public void setDescription(String description) {
+        this.description = description;
+
+    }
+
     @Override
     public AnnotationTypeBuilder addAnnotation(final String packageName, final String name) {
         if (packageName != null && name != null) {
@@ -50,13 +74,38 @@ public final class EnumerationBuilderImpl extends AbstractBaseType implements En
     }
 
     @Override
-    public void addValue(final String name, final Integer value) {
-        values.add(new EnumPairImpl(name, value));
+    public void addValue(final String name, final Integer value, final String description) {
+        values.add(new EnumPairImpl(name, value, description));
     }
 
     @Override
     public Enumeration toInstance(final Type definingType) {
-        return new EnumerationImpl(definingType, annotationBuilders, packageName, name, values);
+        return new EnumerationImpl(definingType, annotationBuilders, packageName, name, values,
+                description, reference, moduleName, schemaPath);
+    }
+
+    @Override
+    public void updateEnumPairsFromEnumTypeDef(final EnumTypeDefinition enumTypeDef) {
+        final List<EnumPair> enums = enumTypeDef.getValues();
+        if (enums != null) {
+            int listIndex = 0;
+            for (final EnumPair enumPair : enums) {
+                if (enumPair != null) {
+                    final String enumPairName = BindingMapping.getClassName(enumPair.getName());
+                    Integer enumPairValue = enumPair.getValue();
+
+                    if (enumPairValue == null) {
+                        enumPairValue = listIndex;
+                    }
+                    else {
+                        listIndex = enumPairValue;
+                    }
+
+                    this.addValue(enumPairName, enumPairValue, enumPair.getDescription());
+                    listIndex++;
+                }
+            }
+        }
     }
 
     /*
@@ -125,36 +174,17 @@ public final class EnumerationBuilderImpl extends AbstractBaseType implements En
         return builder.toString();
     }
 
-    @Override
-    public void updateEnumPairsFromEnumTypeDef(final EnumTypeDefinition enumTypeDef) {
-        final List<EnumPair> enums = enumTypeDef.getValues();
-        if (enums != null) {
-            int listIndex = 0;
-            for (final EnumPair enumPair : enums) {
-                if (enumPair != null) {
-                    final String enumPairName = BindingMapping.getClassName(enumPair.getName());
-                    Integer enumPairValue = enumPair.getValue();
-
-                    if (enumPairValue == null) {
-                        enumPairValue = listIndex;
-                    }
-                    this.addValue(enumPairName, enumPairValue);
-                    listIndex++;
-                }
-            }
-        }
-
-    }
-
     private static final class EnumPairImpl implements Enumeration.Pair {
 
         private final String name;
         private final Integer value;
+        private final String description;
 
-        public EnumPairImpl(String name, Integer value) {
+        public EnumPairImpl(String name, Integer value, String description) {
             super();
             this.name = name;
             this.value = value;
+            this.description = description;
         }
 
         @Override
@@ -230,6 +260,23 @@ public final class EnumerationBuilderImpl extends AbstractBaseType implements En
             builder.append("]");
             return builder.toString();
         }
+
+        @Override
+        public String getDescription() {
+            return description;
+        }
+
+        @Override
+        public String getReference() {
+            return null;
+        }
+
+        @Override
+        public Status getStatus() {
+            // TODO Auto-generated method stub
+            return null;
+        }
+
     }
 
     private static final class EnumerationImpl implements Enumeration {
@@ -237,11 +284,16 @@ public final class EnumerationBuilderImpl extends AbstractBaseType implements En
         private final Type definingType;
         private final String packageName;
         private final String name;
+        private final String description;
+        private final String reference;
+        private final String moduleName;
+        private final Iterable<QName> schemaPath;
         private final List<Pair> values;
         private List<AnnotationType> annotations = new ArrayList<>();
 
         public EnumerationImpl(final Type definingType, final List<AnnotationTypeBuilder> annotationBuilders,
-                final String packageName, final String name, final List<Pair> values) {
+                final String packageName, final String name, final List<Pair> values, final String description,
+                final String reference, final String moduleName, final Iterable<QName> schemaPath) {
             super();
             this.definingType = definingType;
             for (final AnnotationTypeBuilder builder : annotationBuilders) {
@@ -251,6 +303,10 @@ public final class EnumerationBuilderImpl extends AbstractBaseType implements En
             this.packageName = packageName;
             this.name = name;
             this.values = Collections.unmodifiableList(values);
+            this.description = description;
+            this.reference = reference;
+            this.moduleName = moduleName;
+            this.schemaPath = schemaPath;
         }
 
         @Override
@@ -434,5 +490,25 @@ public final class EnumerationBuilderImpl extends AbstractBaseType implements En
         public List<GeneratedProperty> getProperties() {
             return Collections.emptyList();
         }
+
+        @Override
+        public String getDescription() {
+            return description;
+        }
+
+        @Override
+        public String getReference() {
+            return reference;
+        }
+
+        @Override
+        public Iterable<QName> getSchemaPath() {
+            return schemaPath;
+        }
+
+        @Override
+        public String getModuleName() {
+            return moduleName;
+        }
     }
 }
index b3b1c7ce256ddff61166bc341dbafdfdc1b966ab..18efb661d6b980417f5abc2ac898e8c856895332 100644 (file)
@@ -18,6 +18,7 @@ import org.opendaylight.yangtools.sal.binding.model.api.Type;
 import org.opendaylight.yangtools.sal.binding.model.api.type.builder.GeneratedPropertyBuilder;
 import org.opendaylight.yangtools.sal.binding.model.api.type.builder.GeneratedTOBuilder;
 import org.opendaylight.yangtools.sal.binding.model.api.type.builder.MethodSignatureBuilder;
+import org.opendaylight.yangtools.yang.common.QName;
 
 public final class GeneratedTOBuilderImpl extends AbstractGeneratedTypeBuilder<GeneratedTOBuilder> implements
         GeneratedTOBuilder {
@@ -31,6 +32,10 @@ public final class GeneratedTOBuilderImpl extends AbstractGeneratedTypeBuilder<G
     private boolean isUnionTypeBuilder = false;
     private Restrictions restrictions;
     private GeneratedPropertyBuilder SUID;
+    private String reference;
+    private String description;
+    private String moduleName;
+    private Iterable<QName> schemaPath;
 
     public GeneratedTOBuilderImpl(final String packageName, final String name) {
         super(packageName, name);
@@ -102,7 +107,8 @@ public final class GeneratedTOBuilderImpl extends AbstractGeneratedTypeBuilder<G
 
     @Override
     public GeneratedTransferObject toInstance() {
-        // FIXME: can we compact the arrays now? It needs to be thread-safe, though
+        // FIXME: can we compact the arrays now? It needs to be thread-safe,
+        // though
         return new GeneratedTransferObjectImpl(this);
     }
 
@@ -148,6 +154,26 @@ public final class GeneratedTOBuilderImpl extends AbstractGeneratedTypeBuilder<G
         this.isUnionTypeBuilder = isUnionTypeBuilder;
     }
 
+    @Override
+    public void setDescription(String description) {
+        this.description = description;
+    }
+
+    @Override
+    public void setModuleName(String moduleName) {
+        this.moduleName = moduleName;
+    }
+
+    @Override
+    public void setSchemaPath(Iterable<QName> schemaPath) {
+        this.schemaPath = schemaPath;
+    }
+
+    @Override
+    public void setReference(String reference) {
+        this.reference = reference;
+    }
+
     private static final class GeneratedTransferObjectImpl extends AbstractGeneratedType implements
             GeneratedTransferObject {
 
@@ -160,6 +186,10 @@ public final class GeneratedTOBuilderImpl extends AbstractGeneratedTypeBuilder<G
         private final boolean isUnionTypeBuilder;
         private final Restrictions restrictions;
         private final GeneratedProperty SUID;
+        private final String reference;
+        private final String description;
+        private final String moduleName;
+        private final Iterable<QName> schemaPath;
 
         public GeneratedTransferObjectImpl(final GeneratedTOBuilderImpl builder) {
             super(builder);
@@ -171,6 +201,11 @@ public final class GeneratedTOBuilderImpl extends AbstractGeneratedTypeBuilder<G
             this.isUnionType = builder.isUnionType;
             this.isUnionTypeBuilder = builder.isUnionTypeBuilder;
             this.restrictions = builder.restrictions;
+            this.reference = builder.reference;
+            this.description = builder.description;
+            this.moduleName = builder.moduleName;
+            this.schemaPath = builder.schemaPath;
+
             if (builder.SUID == null) {
                 this.SUID = null;
             } else {
@@ -225,7 +260,7 @@ public final class GeneratedTOBuilderImpl extends AbstractGeneratedTypeBuilder<G
 
         @Override
         public String toString() {
-            if(isTypedef) {
+            if (isTypedef) {
                 return serializeTypedef(this);
             }
             StringBuilder builder = new StringBuilder();
@@ -283,5 +318,24 @@ public final class GeneratedTOBuilderImpl extends AbstractGeneratedTypeBuilder<G
             }
         }
 
+        @Override
+        public String getDescription() {
+            return description;
+        }
+
+        @Override
+        public String getReference() {
+            return reference;
+        }
+
+        @Override
+        public Iterable<QName> getSchemaPath() {
+            return schemaPath;
+        }
+
+        @Override
+        public String getModuleName() {
+            return moduleName;
+        }
     }
 }
index 27fe08f411808d90baae77d78ac9758f5b75c649..92c5629eab8861674bb2532957d4ab0bb9239256 100644 (file)
@@ -7,13 +7,19 @@
  */
 package org.opendaylight.yangtools.binding.generator.util.generated.type.builder;
 
-
 import org.opendaylight.yangtools.sal.binding.model.api.GeneratedType;
 import org.opendaylight.yangtools.sal.binding.model.api.type.builder.GeneratedTypeBuilder;
+import org.opendaylight.yangtools.yang.common.QName;
+
+public final class GeneratedTypeBuilderImpl extends AbstractGeneratedTypeBuilder<GeneratedTypeBuilder> implements
+        GeneratedTypeBuilder {
 
-public final class GeneratedTypeBuilderImpl extends AbstractGeneratedTypeBuilder<GeneratedTypeBuilder> implements GeneratedTypeBuilder {
+    private String description;
+    private String reference;
+    private String moduleName;
+    private Iterable<QName> schemaPath;
 
-    public GeneratedTypeBuilderImpl(String packageName, String name) {
+    public GeneratedTypeBuilderImpl(final String packageName, final String name) {
         super(packageName, name);
         setAbstract(true);
     }
@@ -23,6 +29,26 @@ public final class GeneratedTypeBuilderImpl extends AbstractGeneratedTypeBuilder
         return new GeneratedTypeImpl(this);
     }
 
+    @Override
+    public void setDescription(String description) {
+        this.description = description;
+    }
+
+    @Override
+    public void setModuleName(String moduleName) {
+        this.moduleName = moduleName;
+    }
+
+    @Override
+    public void setSchemaPath(Iterable<QName> schemaPath) {
+        this.schemaPath = schemaPath;
+    }
+
+    @Override
+    public void setReference(String reference) {
+        this.reference = reference;
+    }
+
     @Override
     public String toString() {
         StringBuilder builder = new StringBuilder();
@@ -48,7 +74,7 @@ public final class GeneratedTypeBuilderImpl extends AbstractGeneratedTypeBuilder
         builder.append("]");
         return builder.toString();
     }
-    
+
     @Override
     protected GeneratedTypeBuilderImpl thisInstance() {
         return this;
@@ -56,8 +82,38 @@ public final class GeneratedTypeBuilderImpl extends AbstractGeneratedTypeBuilder
 
     private static final class GeneratedTypeImpl extends AbstractGeneratedType {
 
+        private final String description;
+        private final String reference;
+        private final String moduleName;
+        private final Iterable<QName> schemaPath;
+
         public GeneratedTypeImpl(GeneratedTypeBuilderImpl builder) {
             super(builder);
+
+            this.description = builder.description;
+            this.reference = builder.reference;
+            this.moduleName = builder.moduleName;
+            this.schemaPath = builder.schemaPath;
+        }
+
+        @Override
+        public String getDescription() {
+            return description;
+        }
+
+        @Override
+        public String getReference() {
+            return reference;
+        }
+
+        @Override
+        public Iterable<QName> getSchemaPath() {
+            return schemaPath;
+        }
+
+        @Override
+        public String getModuleName() {
+            return moduleName;
         }
     }
 }
index 5b16fa7eec7432b8ce85b6a1a2fab4869d09ec45..871e57b7ac6b7ebdd02ba8f11cdaeace31efdb13 100644 (file)
@@ -41,9 +41,6 @@
                 <groupId>org.eclipse.xtend</groupId>
                 <artifactId>xtend-maven-plugin</artifactId>
             </plugin>
-            <plugin>
-                <artifactId>maven-clean-plugin</artifactId>
-            </plugin>
 <!--      <plugin>
         <artifactId>maven-enforcer-plugin</artifactId>
         <executions>
             <groupId>org.codehaus.plexus</groupId>
             <artifactId>plexus-slf4j-logging</artifactId>
         </dependency>
+        <dependency>
+            <groupId>org.mockito</groupId>
+            <artifactId>mockito-core</artifactId>
+        </dependency>
     </dependencies>
 
 </project>
index c1b1074d5d45b06e0db40be6181d250030ed27e0..24d0a7fd6031f30b2410033337f7f6bef89f59f4 100644 (file)
@@ -7,29 +7,31 @@
  */
 package org.opendaylight.yangtools.sal.java.api.generator
 
-import org.opendaylight.yangtools.sal.binding.model.api.GeneratedProperty
-import org.opendaylight.yangtools.sal.binding.model.api.GeneratedType
-import java.util.Map
-import org.opendaylight.yangtools.sal.binding.model.api.Type
-import org.opendaylight.yangtools.binding.generator.util.Types
-import com.google.common.base.Splitter
-import org.opendaylight.yangtools.sal.binding.model.api.MethodSignature
+import com.google.common.collect.ImmutableList
 import com.google.common.collect.Range
+import java.math.BigDecimal
+import java.math.BigInteger
+import java.util.Arrays
+import java.util.Collection
+import java.util.HashMap
 import java.util.List
+import java.util.Map
+import java.util.StringTokenizer
+import org.opendaylight.yangtools.binding.generator.util.Types
 import org.opendaylight.yangtools.sal.binding.model.api.ConcreteType
-import org.opendaylight.yangtools.sal.binding.model.api.Restrictions
+import org.opendaylight.yangtools.sal.binding.model.api.GeneratedProperty
 import org.opendaylight.yangtools.sal.binding.model.api.GeneratedTransferObject
-import java.util.Collection
-import java.util.Arrays
-import java.util.HashMap
-import com.google.common.collect.ImmutableList
-import java.math.BigInteger
-import java.math.BigDecimal
+import org.opendaylight.yangtools.sal.binding.model.api.GeneratedType
+import org.opendaylight.yangtools.sal.binding.model.api.MethodSignature
+import org.opendaylight.yangtools.sal.binding.model.api.Restrictions
+import org.opendaylight.yangtools.sal.binding.model.api.Type
+import org.opendaylight.yangtools.yang.common.QName
 
 abstract class BaseTemplate {
     protected val GeneratedType type;
     protected val Map<String, String> importMap;
-    static val paragraphSplitter = Splitter.on("\n\n").omitEmptyStrings();
+
+    private static final String NEW_LINE = '\n'
 
     new(GeneratedType _type) {
         if (_type == null) {
@@ -50,7 +52,7 @@ abstract class BaseTemplate {
         '''
             Â«packageDefinition»
             Â«imports»
-            
+
             Â«_body»
         '''.toString
     }
@@ -63,7 +65,7 @@ abstract class BaseTemplate {
                 Â«ENDIF»
             Â«ENDFOR»
         Â«ENDIF»
-        
+
     '''
 
     protected abstract def CharSequence body();
@@ -154,22 +156,204 @@ abstract class BaseTemplate {
      * @return string with comment in JAVA format
      */
     def protected CharSequence asJavadoc(String comment) {
-        if(comment == null) return '';
+        if(comment == null) return ''
         var txt = comment
         if (txt.contains("*/")) {
             txt = txt.replace("*/", "&#42;&#47;")
         }
-        val paragraphs = paragraphSplitter.split(txt)
+        txt = comment.trim
+        txt = formatToParagraph(txt)
 
         return '''
-            /**
-              Â«FOR p : paragraphs SEPARATOR "<p>"»
-                  Â«p»
-              Â«ENDFOR»
-            **/
+            Â«wrapToDocumentation(txt)»
         '''
     }
 
+    def String wrapToDocumentation(String text) {
+        val StringTokenizer tokenizer = new StringTokenizer(text, "\n", false)
+        val StringBuilder sb = new StringBuilder()
+
+        if(text.empty)
+            return ""
+
+        sb.append("/**")
+        sb.append(NEW_LINE)
+
+        while(tokenizer.hasMoreTokens) {
+            sb.append(" * ")
+            sb.append(tokenizer.nextToken)
+            sb.append(NEW_LINE)
+        }
+        sb.append(" */")
+
+        return sb.toString
+    }
+
+    def protected String formatDataForJavaDoc(GeneratedType type) {
+        val typeDescription = type.description
+        val typeReference = type.reference
+        val typeModuleName = type.moduleName
+        val typeSchemaPath = type.schemaPath
+
+        return '''
+            Â«IF !type.isDocumentationParametersNullOrEmtpy»
+               Â«IF typeDescription != null && !typeDescription.empty»
+                Â«formatToParagraph(typeDescription)»
+               Â«ENDIF»
+               Â«IF typeReference != null && !typeReference.empty»
+                Reference:
+                    Â«formatReference(typeReference)»
+               Â«ENDIF»
+               Â«IF typeModuleName != null && !typeModuleName.empty»
+                Module name:
+                    Â«typeModuleName»
+               Â«ENDIF»
+               Â«IF typeSchemaPath != null && !typeSchemaPath.empty»
+                Schema path:
+                    Â«formatPath(typeSchemaPath)»
+               Â«ENDIF»
+            Â«ENDIF»
+        '''.toString
+    }
+
+    def formatPath(Iterable<QName> schemaPath) {
+        var currentElement = schemaPath.head
+        val StringBuilder sb = new StringBuilder()
+        sb.append('[')
+        sb.append(currentElement)
+
+        for(pathElement : schemaPath) {
+            if(!currentElement.namespace.equals(pathElement.namespace)) {
+                currentElement = pathElement
+                sb.append('/')
+                sb.append(pathElement)
+            }
+            else {
+                sb.append('/')
+                sb.append(pathElement.localName)
+            }
+        }
+        sb.append(']')
+        return sb.toString
+    }
+
+    def formatReference(String reference) {
+        if(reference == null || reference.isEmpty)
+            return reference
+
+        val StringTokenizer tokenizer = new StringTokenizer(reference, " ", true)
+        val StringBuilder sb = new StringBuilder();
+
+        while(tokenizer.hasMoreTokens) {
+            var String oneElement = tokenizer.nextToken
+            if (oneElement.contains("http://")) {
+                oneElement = asLink(oneElement)
+            }
+            sb.append(oneElement)
+        }
+        return sb.toString
+    }
+
+    def asLink(String text) {
+        val StringBuilder sb = new StringBuilder()
+        var tempText = text
+        var char lastChar = ' '
+        var boolean badEnding = false
+
+        if(text.endsWith(".") || text.endsWith(":") || text.endsWith(",")) {
+            tempText = text.substring(0, text.length - 1)
+            lastChar = text.charAt(text.length - 1)
+            badEnding = true
+        }
+        sb.append("<a href = \"")
+        sb.append(tempText)
+        sb.append("\">")
+        sb.append(tempText)
+        sb.append("</a>")
+
+        if(badEnding)
+            sb.append(lastChar)
+
+        return sb.toString
+    }
+
+    protected def formatToParagraph(String text) {
+        if(text == null || text.isEmpty)
+            return text
+
+        var formattedText = text
+        val StringBuilder sb = new StringBuilder();
+        var StringBuilder lineBuilder = new StringBuilder();
+        var boolean isFirstElementOnNewLineEmptyChar = false;
+
+        formattedText = formattedText.replace("*/", "&#42;&#47;")
+        formattedText = formattedText.replace(NEW_LINE, "")
+        formattedText = formattedText.replace("\t", "")
+        formattedText = formattedText.replaceAll(" +", " ");
+
+        val StringTokenizer tokenizer = new StringTokenizer(formattedText, " ", true);
+
+        while(tokenizer.hasMoreElements) {
+            val nextElement = tokenizer.nextElement.toString
+
+            if(lineBuilder.length + nextElement.length > 80) {
+                if (lineBuilder.charAt(lineBuilder.length - 1) == ' ') {
+                    lineBuilder.setLength(0)
+                    lineBuilder.append(lineBuilder.substring(0, lineBuilder.length - 1))
+                }
+                if (lineBuilder.charAt(0) == ' ') {
+                    lineBuilder.setLength(0)
+                    lineBuilder.append(lineBuilder.substring(1))
+                }
+
+                sb.append(lineBuilder);
+                lineBuilder.setLength(0)
+                sb.append(NEW_LINE)
+
+                if(nextElement.toString == ' ')
+                    isFirstElementOnNewLineEmptyChar = !isFirstElementOnNewLineEmptyChar;
+            }
+
+            if(isFirstElementOnNewLineEmptyChar) {
+                isFirstElementOnNewLineEmptyChar = !isFirstElementOnNewLineEmptyChar
+            }
+
+            else {
+                lineBuilder.append(nextElement)
+            }
+        }
+        sb.append(lineBuilder)
+        sb.append(NEW_LINE)
+
+        return sb.toString
+    }
+
+    def isDocumentationParametersNullOrEmtpy(GeneratedType type) {
+        var boolean isNullOrEmpty = true
+        val String typeDescription = type.description
+        val String typeReference = type.reference
+        val String typeModuleName = type.moduleName
+        val Iterable<QName> typeSchemaPath = type.schemaPath
+
+        if(typeDescription != null && !typeDescription.empty) {
+            isNullOrEmpty = false
+            return isNullOrEmpty
+        }
+        if(typeReference != null && !typeReference.empty) {
+            isNullOrEmpty = false
+            return isNullOrEmpty
+        }
+        if(typeModuleName != null && !typeModuleName.empty) {
+            isNullOrEmpty = false
+            return isNullOrEmpty
+        }
+        if(typeSchemaPath != null && !typeSchemaPath.empty) {
+            isNullOrEmpty = false
+            return isNullOrEmpty
+        }
+        return isNullOrEmpty
+    }
+
     def generateRestrictions(Type type, String paramName, Type returnType) '''
         Â«val restrictions = type.getRestrictions»
         Â«IF restrictions !== null»
index c97838ed02125b073a37d61ec53d00e2b72d5546..7645504e6c7584a1f1c3d2857e0bc6197383caa2 100644 (file)
@@ -31,6 +31,7 @@ import java.util.Collection
 import org.opendaylight.yangtools.yang.binding.Identifiable
 import com.google.common.collect.Range
 import org.opendaylight.yangtools.sal.binding.model.api.ConcreteType
+import com.google.common.collect.ImmutableList
 
 /**
  * Template for generating JAVA builder classes. 
@@ -139,12 +140,12 @@ class BuilderTemplate extends BaseTemplate {
         return if (lastDotIndex == -1) "" else fullyQualifiedName.substring(0, lastDotIndex)
     }
 
-       /**
-        * Returns the name of tye type from <code>fullyQualifiedName</code>
-        * 
-        * @param fullyQualifiedName string with fully qualified type name (package + type)
-        * @return string with the name of the type
-        */
+    /**
+     * Returns the name of tye type from <code>fullyQualifiedName</code>
+     *
+     * @param fullyQualifiedName string with fully qualified type name (package + type)
+     * @return string with the name of the type
+     */
     def private String getName(String fullyQualifiedName) {
         val lastDotIndex = fullyQualifiedName.lastIndexOf(Constants.DOT)
         return if (lastDotIndex == -1) fullyQualifiedName else fullyQualifiedName.substring(lastDotIndex + 1)
@@ -176,10 +177,10 @@ class BuilderTemplate extends BaseTemplate {
      * @param method method signature from which is the method name and return type obtained
      * @return generated property instance for the getter <code>method</code>
      * @throws IllegalArgumentException<ul>
-     *         <li>if the <code>method</code> equals <code>null</code></li>
-     *         <li>if the name of the <code>method</code> equals <code>null</code></li>
-     *         <li>if the name of the <code>method</code> is empty</li>
-     *         <li>if the return type of the <code>method</code> equals <code>null</code></li>
+     *  <li>if the <code>method</code> equals <code>null</code></li>
+     *  <li>if the name of the <code>method</code> equals <code>null</code></li>
+     *  <li>if the name of the <code>method</code> is empty</li>
+     *  <li>if the return type of the <code>method</code> equals <code>null</code></li>
      * </ul>
      */
     def private GeneratedProperty propertyFromGetter(MethodSignature method) {
@@ -204,7 +205,7 @@ class BuilderTemplate extends BaseTemplate {
      * @return string with JAVA source code
      */
     override body() '''
-
+        Â«wrapToDocumentation(formatDataForJavaDoc(type))»
         public class Â«type.name»«BUILDER» {
 
             Â«generateFields(false)»
@@ -213,6 +214,8 @@ class BuilderTemplate extends BaseTemplate {
 
             Â«generateConstructorsFromIfcs(type)»
 
+            Â«generateCopyConstructor(false)»
+
             Â«generateMethodFieldsFrom(type)»
 
             Â«generateGetters(false)»
@@ -231,7 +234,7 @@ class BuilderTemplate extends BaseTemplate {
 
                 Â«generateAugmentField(false)»
 
-                Â«generateConstructor»
+                Â«generateCopyConstructor(true)»
 
                 Â«generateGetters(true)»
 
@@ -316,7 +319,7 @@ class BuilderTemplate extends BaseTemplate {
 
     def private generateMethodFieldsFromComment(GeneratedType type) '''
         /**
-         Set fields from given grouping argument. Valid argument is instance of one of following types:
+         *Set fields from given grouping argument. Valid argument is instance of one of following types:
          * <ul>
          Â«FOR impl : type.getAllIfcs»
          * <li>«impl.fullyQualifiedName»</li>
@@ -501,13 +504,8 @@ class BuilderTemplate extends BaseTemplate {
         }
     '''
 
-    /**
-     * Template method which generate constructor for IMPL class.
-     * 
-     * @return string with IMPL class constructor
-     */
-    def private generateConstructor() '''
-        private Â«type.name»«IMPL»(«type.name»«BUILDER» builder) {
+    def private CharSequence generateCopyConstructor(boolean impl) '''
+        Â«IF impl»private«ELSE»public«ENDIF» Â«type.name»«IF impl»«IMPL»«ELSE»«BUILDER»«ENDIF»(«type.name»«IF impl»«BUILDER»«ENDIF» base) {
             Â«val allProps = new ArrayList(properties)»
             Â«val isList = implementsIfc(type, Types.parameterizedTypeFor(Types.typeForClass(Identifiable), type))»
             Â«val keyType = type.getKey»
@@ -522,37 +520,49 @@ class BuilderTemplate extends BaseTemplate {
                     Â«removeProperty(allProps, field.name)»
                 Â«ENDFOR»
                 Â«removeProperty(allProps, "key")»
-                if (builder.getKey() == null) {
+                if (base.getKey() == null) {
                     this._key = new Â«keyType.importedName»(
                         Â«FOR keyProp : keyProps SEPARATOR ", "»
-                            builder.«keyProp.getterMethodName»()
+                            base.«keyProp.getterMethodName»()
                         Â«ENDFOR»
                     );
                     Â«FOR field : keyProps»
-                        this.«field.fieldName» = builder.«field.getterMethodName»();
+                        this.«field.fieldName» = base.«field.getterMethodName»();
                     Â«ENDFOR»
                 } else {
-                    this._key = builder.getKey();
+                    this._key = base.getKey();
                     Â«FOR field : keyProps»
                            this.«field.fieldName» = _key.«field.getterMethodName»();
                     Â«ENDFOR»
                 }
             Â«ENDIF»
             Â«FOR field : allProps»
-                this.«field.fieldName» = builder.«field.getterMethodName»();
+                Â«IF List.canonicalName.equals(field.returnType.fullyQualifiedName)»
+                    if (base.«field.getterMethodName»() == null || base.«field.getterMethodName»().isEmpty()) {
+                        this.«field.fieldName» = Â«Collections.importedName».emptyList();
+                    } else {
+                        this.«field.fieldName» = Â«ImmutableList.importedName».copyOf(base.«field.getterMethodName»());
+                    }
+                Â«ELSE»
+                    this.«field.fieldName» = base.«field.getterMethodName»();
+                Â«ENDIF»
             Â«ENDFOR»
             Â«IF augmentField != null»
-               switch (builder.«augmentField.name».size()) {
-                case 0:
-                    this.«augmentField.name» = Â«Collections.importedName».emptyMap();
-                    break;
-                case 1:
-                    final Â«Map.importedName».Entry<«Class.importedName»<? extends Â«augmentField.returnType.importedName»>, Â«augmentField.returnType.importedName»> e = builder.«augmentField.name».entrySet().iterator().next();
-                    this.«augmentField.name» = Â«Collections.importedName».<«Class.importedName»<? extends Â«augmentField.returnType.importedName»>, Â«augmentField.returnType.importedName»>singletonMap(e.getKey(), e.getValue());
-                    break;
-                default :
-                    this.«augmentField.name» = new Â«HashMap.importedName»<>(builder.«augmentField.name»);
-                }
+                Â«IF !impl»if (base instanceof Â«type.name»«IMPL») {«ENDIF»
+                    Â«IF !impl»«type.name»«IMPL» _impl = («type.name»«IMPL») base;«ENDIF»
+                    Â«val prop = if (impl) "base" else "_impl"»
+                    switch («prop».«augmentField.name».size()) {
+                    case 0:
+                        this.«augmentField.name» = Â«Collections.importedName».emptyMap();
+                        break;
+                    case 1:
+                        final Â«Map.importedName».Entry<«Class.importedName»<? extends Â«augmentField.returnType.importedName»>, Â«augmentField.returnType.importedName»> e = Â«prop».«augmentField.name».entrySet().iterator().next();
+                        this.«augmentField.name» = Â«Collections.importedName».<«Class.importedName»<? extends Â«augmentField.returnType.importedName»>, Â«augmentField.returnType.importedName»>singletonMap(e.getKey(), e.getValue());
+                        break;
+                    default :
+                        this.«augmentField.name» = new Â«HashMap.importedName»<>(«prop».«augmentField.name»);
+                    }
+                Â«IF !impl»}«ENDIF»
             Â«ENDIF»
         }
     '''
@@ -733,4 +743,3 @@ class BuilderTemplate extends BaseTemplate {
     '''
 
 }
-
index fed70f50ea5beb0a2b7709694f2c557650be7877..e92f84e489ae1e3db0bea4faf4569b3ae2e8f304 100644 (file)
@@ -100,7 +100,7 @@ class ClassTemplate extends BaseTemplate {
      * @return string with class source code in JAVA format
      */
     def protected generateBody(boolean isInnerClass) '''
-        Â«type.comment.asJavadoc»
+        Â«wrapToDocumentation(formatDataForJavaDoc(type))»
         Â«generateClassDeclaration(isInnerClass)» {
             Â«suidDeclaration»
             Â«innerClassesDeclarations»
@@ -368,12 +368,11 @@ class ClassTemplate extends BaseTemplate {
         Â«IF restrictions != null»
             Â«val prop = getPropByName("value")»
             Â«IF prop != null»
-                Â«val numberClass = prop.returnType.importedNumber»
                 Â«IF !(restrictions.lengthConstraints.empty)»
-                    private static Â«List.importedName»<«Range.importedName»<«numberClass»>> _length;
+                    private static Â«List.importedName»<«Range.importedName»<«prop.returnType.importedNumber»>> _length;
                 Â«ENDIF»
                 Â«IF !(restrictions.rangeConstraints.empty)»
-                    private static Â«List.importedName»<«Range.importedName»<«numberClass»>> _range;
+                    private static Â«List.importedName»<«Range.importedName»<«prop.returnType.importedNumber»>> _range;
                 Â«ENDIF»
             Â«ENDIF»
         Â«ENDIF»
@@ -384,7 +383,6 @@ class ClassTemplate extends BaseTemplate {
         Â«ENDIF»
     '''
 
-
     /**
      * Template method which generates the method <code>hashCode()</code>.
      *
index fecae3de47dd1b7efa0fea1b694b4deeda3f5941..cc05fb49120d10dbfc12e065d76440dd837ae6f8 100644 (file)
@@ -41,17 +41,22 @@ class EnumTemplate extends BaseTemplate {
         return body
     }
     
+    def writeEnumItem(String name, int value, String description) '''
+        Â«asJavadoc(formatToParagraph(description))»
+        Â«name»(«value»)
+    '''
+
     /**
      * Template method which generates enumeration body (declaration + enumeration items).
      * 
      * @return string with the enumeration body 
      */
     override body() '''
+        Â«wrapToDocumentation(formatDataForJavaDoc(enums))»
         public enum Â«enums.name» {
-        Â«FOR v : enums.values SEPARATOR ",\n"»
-            Â«"    "»«v.name»(«v.value»)«
-        ENDFOR»;
-        
+            Â«writeEnumeration(enums)»
+
+
             int value;
             static java.util.Map<java.lang.Integer, Â«enums.name»> valueMap;
 
@@ -83,4 +88,11 @@ class EnumTemplate extends BaseTemplate {
             }
         }
     '''
+
+    def writeEnumeration(Enumeration enumeration)
+    '''
+    Â«FOR v : enumeration.values SEPARATOR ",\n" AFTER ";"»
+    Â«writeEnumItem(v.name, v.value, v.description)»«
+    ENDFOR»
+    '''
 }
index 54c2eeb45d16a6f641eee1a0c48831c64de979dc..b9210287cf07fe2a3414b5ff4ff3ba303e9925cb 100644 (file)
@@ -58,15 +58,13 @@ class InterfaceTemplate extends BaseTemplate {
         enclosedGeneratedTypes = genType.enclosedTypes
     }
     
-
-    
     /**
      * Template method which generate the whole body of the interface.
      * 
      * @return string with code for interface body in JAVA format
      */
     override body() '''
-        Â«type.comment.asJavadoc»
+        Â«wrapToDocumentation(formatDataForJavaDoc(type))»
         public interface Â«type.name»
             Â«superInterfaces»
         {
index edce4bdcffa51bbd3174919dd3e2b4888b34e67b..dbed6c75153613df5fdb0701f947934120841101 100644 (file)
@@ -25,7 +25,7 @@ class UnionBuilderTemplate extends ClassTemplate {
     }
 
     def override body() '''
-        Â«type.comment.asJavadoc»
+        Â«wrapToDocumentation(formatDataForJavaDoc(type))»
         public class Â«type.name» {
 
             Â«generateMethods»
index f9c27fe86529d2f8175dc2c1f45805b986f881b2..94cfe1e8d05cec8076711637a6da1129e06d8fed 100644 (file)
@@ -9,6 +9,7 @@ package org.opendaylight.yangtools.sal.java.api.generator
 
 import org.opendaylight.yangtools.sal.binding.model.api.GeneratedTransferObject
 import java.beans.ConstructorProperties
+import org.opendaylight.yangtools.sal.binding.model.api.Enumeration
 
 /**
  * Template for generating JAVA class. 
@@ -37,14 +38,15 @@ class UnionTemplate extends ClassTemplate {
 
     private def unionConstructors() '''
         Â«FOR property : finalProperties SEPARATOR "\n"»
-            Â«val isCharArray = "char[]".equals(property.returnType.name)»
+            Â«val propRet = property.returnType»
+            Â«val isCharArray = "char[]".equals(propRet.name)»
             Â«IF isCharArray»
                 /**
                  * Constructor provided only for using in JMX. Don't use it for
                  * construction new object of this union type. 
                  */
                 @«ConstructorProperties.importedName»("«property.name»")
-                public Â«type.name»(«property.returnType.importedName» Â«property.fieldName») {
+                public Â«type.name»(«propRet.importedName» Â«property.fieldName») {
                     Â«String.importedName» defVal = new Â«String.importedName»(«property.fieldName»);
                     Â«type.name» defInst = Â«type.name»Builder.getDefaultInstance(defVal);
                     Â«FOR other : finalProperties»
@@ -61,7 +63,28 @@ class UnionTemplate extends ClassTemplate {
                     super(«parentProperties.asArguments»);
                     this.«property.fieldName» = Â«property.fieldName»;
                     Â«FOR other : finalProperties»
-                        Â«IF property != other»this.«other.fieldName» = null;«ENDIF»
+                        Â«IF property != other»
+                            Â«IF "value".equals(other.name)»
+                                Â«IF "java.lang.String".equals(propRet.fullyQualifiedName)»
+                                    Â«Â«Â« type string
+                                    this.«other.fieldName» = Â«property.fieldName».toCharArray();
+                                Â«ELSEIF "byte[]".equals(propRet.name)»
+                                    Â«Â«Â« type binary
+                                    this.«other.fieldName» = new Â«String.importedName»(«property.fieldName»).toCharArray();
+                                Â«ELSEIF propRet.fullyQualifiedName.startsWith("java.lang") || propRet instanceof Enumeration»
+                                    Â«Â«Â« type int*, uint or enumeration*
+                                    this.«other.fieldName» = Â«property.fieldName».toString().toCharArray();
+                                Â«ELSEIF propRet instanceof GeneratedTransferObject && (propRet as GeneratedTransferObject).unionType»
+                                    Â«Â«Â« union type
+                                    this.«other.fieldName» = Â«property.fieldName».getValue();
+                                Â«ELSE»
+                                    Â«Â«Â« generated type
+                                    this.«other.fieldName» = Â«property.fieldName».getValue().toString().toCharArray();
+                                Â«ENDIF»
+                            Â«ELSE»
+                                this.«other.fieldName» = null;
+                            Â«ENDIF»
+                        Â«ENDIF»
                     Â«ENDFOR»
                 }
             Â«ENDIF»
diff --git a/code-generator/binding-java-api-generator/src/test/java/org/opendaylight/yangtools/sal/java/api/generator/test/Bug1276Test.java b/code-generator/binding-java-api-generator/src/test/java/org/opendaylight/yangtools/sal/java/api/generator/test/Bug1276Test.java
new file mode 100644 (file)
index 0000000..d2653f2
--- /dev/null
@@ -0,0 +1,105 @@
+/*
+ * 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.yangtools.sal.java.api.generator.test;
+
+import static org.junit.Assert.assertTrue;
+import static org.opendaylight.yangtools.sal.java.api.generator.test.CompilationTestUtils.BASE_PKG;
+import static org.opendaylight.yangtools.sal.java.api.generator.test.CompilationTestUtils.COMPILER_OUTPUT_PATH;
+import static org.opendaylight.yangtools.sal.java.api.generator.test.CompilationTestUtils.FS;
+import static org.opendaylight.yangtools.sal.java.api.generator.test.CompilationTestUtils.GENERATOR_OUTPUT_PATH;
+import static org.opendaylight.yangtools.sal.java.api.generator.test.CompilationTestUtils.assertContainsConstructor;
+import static org.opendaylight.yangtools.sal.java.api.generator.test.CompilationTestUtils.cleanUp;
+import static org.opendaylight.yangtools.sal.java.api.generator.test.CompilationTestUtils.getSourceFiles;
+import static org.opendaylight.yangtools.sal.java.api.generator.test.CompilationTestUtils.testCompilation;
+
+import java.io.File;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Method;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+import org.junit.Test;
+import org.opendaylight.yangtools.sal.binding.model.api.Type;
+import org.opendaylight.yangtools.sal.java.api.generator.GeneratorJavaFile;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+
+/**
+ * Previous construction of union constructor
+ *
+ * <code>
+ * public IpAddress(Arg1 _arg1) {
+ *     super();
+ *     this._arg1 = _arg1;
+ *     this._arg2 = null;
+ *     this._value = null;
+ * }
+ * </code>
+ *
+ * was incorrect and setting
+ *
+ * <code>this._value == null</code>
+ *
+ * was replaced with setting _value to correct value, for example:
+ *
+ * <code>this._value = arg1.getValue()</code> or
+ * <code>this._value = _arg1.getValue().toString().toCharArray()</code>
+ *
+ */
+public class Bug1276Test extends BaseCompilationTest {
+
+    @Test
+    public void test() throws Exception {
+        final File sourcesOutputDir = new File(GENERATOR_OUTPUT_PATH + FS + "bug1276");
+        assertTrue("Failed to create test file '" + sourcesOutputDir + "'", sourcesOutputDir.mkdir());
+        final File compiledOutputDir = new File(COMPILER_OUTPUT_PATH + FS + "bug1276");
+        assertTrue("Failed to create test file '" + compiledOutputDir + "'", compiledOutputDir.mkdir());
+
+        generateTestSources("/compilation/bug1276", sourcesOutputDir);
+
+        // Test if sources are compilable
+        testCompilation(sourcesOutputDir, compiledOutputDir);
+
+        ClassLoader loader = new URLClassLoader(new URL[] { compiledOutputDir.toURI().toURL() });
+        Class<?> ipAddressClass = Class.forName(BASE_PKG + ".test.yang.union.rev140715.IpAddress", true, loader);
+        Class<?> ipv4AddressClass = Class.forName(BASE_PKG + ".test.yang.union.rev140715.Ipv4Address", true, loader);
+        Class<?> hostClass = Class.forName(BASE_PKG + ".test.yang.union.rev140715.Host", true, loader);
+
+        Constructor<?> ipAddressConstructor = assertContainsConstructor(ipAddressClass, ipv4AddressClass);
+        Constructor<?> ipv4addressConstructor = assertContainsConstructor(ipv4AddressClass, String.class);
+        Constructor<?> hostConstructor = assertContainsConstructor(hostClass, ipAddressClass);
+
+        // test IpAddress with Ipv4Address argument
+        Object ipv4address = ipv4addressConstructor.newInstance("192.168.0.1");
+        Object ipAddress = ipAddressConstructor.newInstance(ipv4address);
+        Method getValue = ipAddressClass.getDeclaredMethod("getValue");
+        char[] expected = "192.168.0.1".toCharArray();
+        Object actual = getValue.invoke(ipAddress);
+        assertTrue(actual instanceof char[]);
+        assertTrue(Arrays.equals(expected, (char[]) actual));
+
+        // test Host with IpAddress argument
+        Object host = hostConstructor.newInstance(ipAddress);
+        getValue = hostClass.getDeclaredMethod("getValue");
+        actual = getValue.invoke(host);
+        assertTrue(actual instanceof char[]);
+        assertTrue(Arrays.equals(expected, (char[]) actual));
+
+        cleanUp(sourcesOutputDir, compiledOutputDir);
+    }
+
+    private void generateTestSources(String resourceDirPath, File sourcesOutputDir) throws Exception {
+        final List<File> sourceFiles = getSourceFiles(resourceDirPath);
+        final SchemaContext context = parser.parseFiles(sourceFiles);
+        final List<Type> types = bindingGenerator.generateTypes(context);
+        final GeneratorJavaFile generator = new GeneratorJavaFile(new HashSet<>(types));
+        generator.generateToFile(sourcesOutputDir);
+    }
+
+}
diff --git a/code-generator/binding-java-api-generator/src/test/java/org/opendaylight/yangtools/sal/java/api/generator/test/Bug532Test.java b/code-generator/binding-java-api-generator/src/test/java/org/opendaylight/yangtools/sal/java/api/generator/test/Bug532Test.java
new file mode 100644 (file)
index 0000000..e816a68
--- /dev/null
@@ -0,0 +1,118 @@
+/*
+ * 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.yangtools.sal.java.api.generator.test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.opendaylight.yangtools.sal.java.api.generator.test.CompilationTestUtils.BASE_PKG;
+import static org.opendaylight.yangtools.sal.java.api.generator.test.CompilationTestUtils.COMPILER_OUTPUT_PATH;
+import static org.opendaylight.yangtools.sal.java.api.generator.test.CompilationTestUtils.FS;
+import static org.opendaylight.yangtools.sal.java.api.generator.test.CompilationTestUtils.GENERATOR_OUTPUT_PATH;
+import static org.opendaylight.yangtools.sal.java.api.generator.test.CompilationTestUtils.cleanUp;
+import static org.opendaylight.yangtools.sal.java.api.generator.test.CompilationTestUtils.getSourceFiles;
+import static org.opendaylight.yangtools.sal.java.api.generator.test.CompilationTestUtils.testCompilation;
+
+import com.google.common.collect.Lists;
+import java.io.File;
+import java.lang.reflect.Constructor;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.util.HashSet;
+import java.util.List;
+import org.junit.Test;
+import org.mockito.Mockito;
+import org.opendaylight.yangtools.sal.binding.model.api.Type;
+import org.opendaylight.yangtools.sal.java.api.generator.GeneratorJavaFile;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+
+/**
+ * Test correct functionality of copy constructor of generated builder classes.
+ */
+public class Bug532Test extends BaseCompilationTest {
+
+    @Test
+    public void test() throws Exception {
+        final File sourcesOutputDir = new File(GENERATOR_OUTPUT_PATH + FS + "bug532");
+        assertTrue("Failed to create test file '" + sourcesOutputDir + "'", sourcesOutputDir.mkdir());
+        final File compiledOutputDir = new File(COMPILER_OUTPUT_PATH + FS + "bug532");
+        assertTrue("Failed to create test file '" + compiledOutputDir + "'", compiledOutputDir.mkdir());
+
+        generateTestSources("/compilation/list-gen", sourcesOutputDir);
+
+        // Test if sources are compilable
+        testCompilation(sourcesOutputDir, compiledOutputDir);
+
+        ClassLoader loader = new URLClassLoader(new URL[] { compiledOutputDir.toURI().toURL() });
+        Class<?> linksKeyClass = Class.forName(BASE_PKG + ".urn.opendaylight.test.rev131008.LinksKey", true, loader);
+        Class<?> linksClass = Class.forName(BASE_PKG + ".urn.opendaylight.test.rev131008.Links", true, loader);
+        Class<?> linksBuilderClass = Class.forName(BASE_PKG + ".urn.opendaylight.test.rev131008.LinksBuilder", true,
+                loader);
+        Class<?> levelClass = Class.forName(BASE_PKG + ".urn.opendaylight.test.rev131008.links.Level", true, loader);
+        Class<?> nodeClass = Class.forName(BASE_PKG + ".urn.opendaylight.test.rev131008.links.Node", true, loader);
+        Class<?> nodeListClass = Class.forName(BASE_PKG + ".urn.opendaylight.test.rev131008.links.NodeList", true,
+                loader);
+
+        // init default values
+        Byte expectedId = Byte.valueOf("5");
+        String expectedName = "test-link";
+        Integer expectedSize = Integer.valueOf(10);
+        Object expectedLevel = Mockito.mock(levelClass);
+        Integer expectedLinksId = Integer.valueOf(11);
+        Object expectedNode = Mockito.mock(nodeClass);
+        List<?> expectedNodeList = Lists.newArrayList(Mockito.mock(nodeListClass), Mockito.mock(nodeListClass));
+        Constructor<?> keyConstructor = linksKeyClass.getDeclaredConstructor(Byte.class, String.class, Integer.class);
+        Object expectedKey = keyConstructor.newInstance(expectedId, expectedName, expectedSize);
+
+        // create Links object
+        Object linksBuilder = linksBuilderClass.newInstance();
+        linksBuilderClass.getDeclaredMethod("setKey", linksKeyClass).invoke(linksBuilder, expectedKey);
+        linksBuilderClass.getDeclaredMethod("setLevel", levelClass).invoke(linksBuilder, expectedLevel);
+        linksBuilderClass.getDeclaredMethod("setLinksId", Integer.class).invoke(linksBuilder, expectedLinksId);
+        linksBuilderClass.getDeclaredMethod("setNode", nodeClass).invoke(linksBuilder, expectedNode);
+        linksBuilderClass.getDeclaredMethod("setNodeList", List.class).invoke(linksBuilder, expectedNodeList);
+        Object links = linksBuilderClass.getDeclaredMethod("build").invoke(linksBuilder);
+
+        // create LinksBuilder object with constructor with Links object
+        // argument
+        Constructor<?> linksBuilderConstructor = linksBuilderClass.getDeclaredConstructor(linksClass);
+        assertNotNull(linksBuilderConstructor);
+        Object linksBuilderTested = linksBuilderConstructor.newInstance(links);
+
+        // get values from LinksBuilder
+        Object actualKey = linksBuilderClass.getDeclaredMethod("getKey").invoke(linksBuilderTested);
+        Object actualId = linksBuilderClass.getDeclaredMethod("getId").invoke(linksBuilderTested);
+        Object actualName = linksBuilderClass.getDeclaredMethod("getName").invoke(linksBuilderTested);
+        Object actualSize = linksBuilderClass.getDeclaredMethod("getSize").invoke(linksBuilderTested);
+        Object actualLevel = linksBuilderClass.getDeclaredMethod("getLevel").invoke(linksBuilderTested);
+        Object actualLinksId = linksBuilderClass.getDeclaredMethod("getLinksId").invoke(linksBuilderTested);
+        Object actualNode = linksBuilderClass.getDeclaredMethod("getNode").invoke(linksBuilderTested);
+        Object actualNodeList = linksBuilderClass.getDeclaredMethod("getNodeList").invoke(linksBuilderTested);
+
+        // test
+        assertEquals(expectedKey, actualKey);
+        assertEquals(expectedId, actualId);
+        assertEquals(expectedName, actualName);
+        assertEquals(expectedSize, actualSize);
+        assertEquals(expectedLevel, actualLevel);
+        assertEquals(expectedLinksId, actualLinksId);
+        assertEquals(expectedNode, actualNode);
+        assertEquals(expectedNodeList, actualNodeList);
+
+        cleanUp(sourcesOutputDir, compiledOutputDir);
+    }
+
+    private void generateTestSources(String resourceDirPath, File sourcesOutputDir) throws Exception {
+        final List<File> sourceFiles = getSourceFiles(resourceDirPath);
+        final SchemaContext context = parser.parseFiles(sourceFiles);
+        final List<Type> types = bindingGenerator.generateTypes(context);
+        final GeneratorJavaFile generator = new GeneratorJavaFile(new HashSet<>(types));
+        generator.generateToFile(sourcesOutputDir);
+    }
+
+}
index b49be322c6d9ea2292649f4c77334c47a428286b..58d213cbbbec98dc682582a2e0fe022162ffb70b 100644 (file)
@@ -97,7 +97,7 @@ public class CascadeUsesCompilationTest extends BaseCompilationTest {
         // test generated builder for 'container nodes'
         assertFalse(nodesBuilderClass.isInterface());
         Constructor<?>[] nodesBuilderConstructors = nodesBuilderClass.getConstructors();
-        assertEquals(5, nodesBuilderConstructors.length);
+        assertEquals(6, nodesBuilderConstructors.length);
 
         // test generation of builder constructors from uses in 'container nodes'
         Constructor<?> defaultConstructor = null;
index 5597486584d53d219d12217e75d44f6ae33bbca7..db2fa44ac5abcb9f0c1b05ceebdcfd330f2a34e4 100644 (file)
@@ -23,10 +23,13 @@ import static org.opendaylight.yangtools.sal.java.api.generator.test.Compilation
 import static org.opendaylight.yangtools.sal.java.api.generator.test.CompilationTestUtils.assertContainsRestrictionCheck;
 import static org.opendaylight.yangtools.sal.java.api.generator.test.CompilationTestUtils.assertFilesCount;
 import static org.opendaylight.yangtools.sal.java.api.generator.test.CompilationTestUtils.assertImplementsIfc;
+import static org.opendaylight.yangtools.sal.java.api.generator.test.CompilationTestUtils.assertImplementsParameterizedIfc;
 import static org.opendaylight.yangtools.sal.java.api.generator.test.CompilationTestUtils.cleanUp;
 import static org.opendaylight.yangtools.sal.java.api.generator.test.CompilationTestUtils.getSourceFiles;
 import static org.opendaylight.yangtools.sal.java.api.generator.test.CompilationTestUtils.testCompilation;
 
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Lists;
 import com.google.common.collect.Range;
 import java.io.File;
 import java.lang.annotation.Annotation;
@@ -39,11 +42,14 @@ import java.math.BigInteger;
 import java.net.URL;
 import java.net.URLClassLoader;
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.HashSet;
 import java.util.List;
 import org.junit.Test;
+import org.mockito.Mockito;
 import org.opendaylight.yangtools.sal.binding.model.api.Type;
 import org.opendaylight.yangtools.sal.java.api.generator.GeneratorJavaFile;
+import org.opendaylight.yangtools.yang.binding.ChildOf;
 import org.opendaylight.yangtools.yang.binding.annotations.RoutingContext;
 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
 
@@ -535,6 +541,80 @@ public class CompilationTest extends BaseCompilationTest {
         cleanUp(sourcesOutputDir, compiledOutputDir);
     }
 
+    /**
+     * Test if class generated for node from grouping implements ChildOf.
+     *
+     * @throws Exception
+     */
+    @Test
+    public void testBug1377() throws Exception {
+        final File sourcesOutputDir = new File(GENERATOR_OUTPUT_PATH + FS + "bug1377");
+        assertTrue("Failed to create test file '" + sourcesOutputDir + "'", sourcesOutputDir.mkdir());
+        final File compiledOutputDir = new File(COMPILER_OUTPUT_PATH + FS + "bug1377");
+        assertTrue("Failed to create test file '" + compiledOutputDir + "'", compiledOutputDir.mkdir());
+
+        generateTestSources("/compilation/bug1377", sourcesOutputDir);
+
+        // Test if sources are compilable
+        testCompilation(sourcesOutputDir, compiledOutputDir);
+
+        ClassLoader loader = new URLClassLoader(new URL[] { compiledOutputDir.toURI().toURL() });
+        Class<?> outputActionClass = Class.forName(BASE_PKG
+                + ".urn.test.foo.rev140717.action.action.output.action._case.OutputAction", true, loader);
+        Class<?> actionClass = Class.forName(BASE_PKG + ".urn.test.foo.rev140717.Action", true, loader);
+
+        // Test generated 'container output-action'
+        assertTrue(outputActionClass.isInterface());
+        assertImplementsParameterizedIfc(outputActionClass, ChildOf.class.toString(), actionClass.getCanonicalName());
+
+        cleanUp(sourcesOutputDir, compiledOutputDir);
+    }
+
+    @Test
+    public void testBug1097() throws Exception {
+        final File sourcesOutputDir = new File(GENERATOR_OUTPUT_PATH + FS + "bug1097");
+        assertTrue("Failed to create test file '" + sourcesOutputDir + "'", sourcesOutputDir.mkdir());
+        final File compiledOutputDir = new File(COMPILER_OUTPUT_PATH + FS + "bug1097");
+        assertTrue("Failed to create test file '" + compiledOutputDir + "'", compiledOutputDir.mkdir());
+
+        generateTestSources("/compilation/bug1097", sourcesOutputDir);
+
+        // Test if sources are compilable
+        testCompilation(sourcesOutputDir, compiledOutputDir);
+
+        ClassLoader loader = new URLClassLoader(new URL[] { compiledOutputDir.toURI().toURL() });
+        Class<?> linkClass = Class.forName(BASE_PKG + ".urn.test.foo.rev140717.Link", true, loader);
+        Class<?> linkBuilderClass = Class.forName(BASE_PKG + ".urn.test.foo.rev140717.LinkBuilder", true, loader);
+        Class<?> nodeClass = Class.forName(BASE_PKG + ".urn.test.foo.rev140717.link.Node", true, loader);
+
+        // Test LinkBuilder without setting any value
+        Object linkBuilder = linkBuilderClass.newInstance();
+        Method build = linkBuilderClass.getDeclaredMethod("build");
+        Object link = build.invoke(linkBuilder);
+        Method getNodes = linkClass.getDeclaredMethod("getNode");
+        Object node = getNodes.invoke(link);
+        assertEquals(Collections.emptyList(), node);
+
+        // Test LinkBuilder with setting an empty list
+        linkBuilder = linkBuilderClass.newInstance();
+        Method setNode = linkBuilderClass.getDeclaredMethod("setNode", List.class);
+        setNode.invoke(linkBuilder, Collections.emptyList());
+        link = build.invoke(linkBuilder);
+        node = getNodes.invoke(link);
+        assertEquals(Collections.emptyList(), node);
+
+        // Test LinkBuilder with setting list with values
+        linkBuilder = linkBuilderClass.newInstance();
+        List<?> testList = Lists.newArrayList(Mockito.mock(nodeClass), Mockito.mock(nodeClass));
+        setNode.invoke(linkBuilder, testList);
+        link = build.invoke(linkBuilder);
+        node = getNodes.invoke(link);
+        assertEquals(testList, node);
+        assertTrue(node instanceof ImmutableList);
+
+        cleanUp(sourcesOutputDir, compiledOutputDir);
+    }
+
     @Test
     public void classNamesColisionTest() throws Exception {
         final File sourcesOutputDir = new File(GENERATOR_OUTPUT_PATH + FS + "class-name-collision");
index 755b3af7b2febfab103ac907eb3637bd788e4ddb..d3ac8d7eec5bc0c2e0e3c127143f8fbb77751155 100644 (file)
@@ -40,6 +40,8 @@ public class CompilationTestUtils {
     static final String COMPILER_OUTPUT_PATH = TEST_PATH + FS + "bin";
     static final File COMPILER_OUTPUT_DIR = new File(COMPILER_OUTPUT_PATH);
 
+    static final String AUGMENTATION = "interface org.opendaylight.yangtools.yang.binding.Augmentation";
+
     static final String BASE_PATH = "org" + FS + "opendaylight" + FS + "yang" + FS + "gen" + FS + "v1";
     static final String NS_TEST = BASE_PATH + FS + "urn" + FS + "opendaylight" + FS + "test" + FS + "rev131008";
     static final String NS_FOO = BASE_PATH + FS + "urn" + FS + "opendaylight" + FS + "foo" + FS + "rev131008";
@@ -322,8 +324,7 @@ public class CompilationTestUtils {
      *            fully qualified name of expected parameter type
      */
     static void testAugmentation(Class<?> clazz, String genericTypeName) {
-        final String ifcName = "interface org.opendaylight.yangtools.yang.binding.Augmentation";
-        assertImplementsParameterizedIfc(clazz, ifcName, genericTypeName);
+        assertImplementsParameterizedIfc(clazz, AUGMENTATION, genericTypeName);
     }
 
     /**
index a80133d17368b05540179809d2bdab182248e729..9c739dfb266eaac28071c82dcd1fcad9fafaa379 100644 (file)
@@ -229,7 +229,8 @@ public class TypedefCompilationTest extends BaseCompilationTest {
 
         // typedef string-ext3
         assertFalse(stringExt3Class.isInterface());
-        assertContainsFieldWithValue(stringExt3Class, "serialVersionUID", Long.TYPE, -2751063130555484180L, String.class);
+        assertContainsFieldWithValue(stringExt3Class, "serialVersionUID", Long.TYPE, -2751063130555484180L,
+                String.class);
         assertEquals(1, stringExt3Class.getDeclaredFields().length);
         expectedConstructor = assertContainsConstructor(stringExt3Class, String.class);
         assertContainsConstructor(stringExt3Class, stringExt3Class);
@@ -245,7 +246,8 @@ public class TypedefCompilationTest extends BaseCompilationTest {
         assertFalse(myDecimalTypeClass.isInterface());
         assertContainsField(myDecimalTypeClass, VAL, BigDecimal.class);
         assertContainsField(myDecimalTypeClass, RANGE, List.class);
-        assertContainsFieldWithValue(myDecimalTypeClass, "serialVersionUID", Long.TYPE, 3143735729419861095L, BigDecimal.class);
+        assertContainsFieldWithValue(myDecimalTypeClass, "serialVersionUID", Long.TYPE, 3143735729419861095L,
+                BigDecimal.class);
         assertEquals(3, myDecimalTypeClass.getDeclaredFields().length);
         assertContainsMethod(myDecimalTypeClass, BigDecimal.class, "getValue");
         expectedConstructor = assertContainsConstructor(myDecimalTypeClass, BigDecimal.class);
@@ -293,7 +295,8 @@ public class TypedefCompilationTest extends BaseCompilationTest {
         assertFalse(unionExt1Class.isInterface());
         assertContainsField(unionExt1Class, "_int16", Short.class);
         assertContainsField(unionExt1Class, "_int32", Integer.class);
-        assertContainsFieldWithValue(unionExt1Class, "serialVersionUID", Long.TYPE, -5610530488718168882L, Short.class);
+        assertContainsFieldWithValue(unionExt1Class, "serialVersionUID", Long.TYPE, -5610530488718168882L,
+                new Class<?>[] { Short.class }, Short.valueOf("1"));
         assertEquals(4, unionExt1Class.getDeclaredFields().length);
         assertContainsMethod(unionExt1Class, Short.class, "getInt16");
         assertContainsMethod(unionExt1Class, Integer.class, "getInt32");
@@ -305,7 +308,8 @@ public class TypedefCompilationTest extends BaseCompilationTest {
 
         // typedef union-ext2
         assertFalse(unionExt2Class.isInterface());
-        assertContainsFieldWithValue(unionExt2Class, "serialVersionUID", Long.TYPE, -8833407459073585206L, Short.class);
+        assertContainsFieldWithValue(unionExt2Class, "serialVersionUID", Long.TYPE, -8833407459073585206L,
+                new Class<?>[] { Short.class }, Short.valueOf("1"));
         assertEquals(1, unionExt2Class.getDeclaredFields().length);
         assertEquals(0, unionExt2Class.getDeclaredMethods().length);
         assertContainsConstructor(unionExt2Class, Short.class);
@@ -318,8 +322,10 @@ public class TypedefCompilationTest extends BaseCompilationTest {
         assertFalse(unionExt3Class.isInterface());
         assertContainsField(unionExt3Class, "_string", String.class);
         assertContainsField(unionExt3Class, "_unionExt2", unionExt2Class);
-        assertContainsFieldWithValue(unionExt3Class, UNITS, String.class, "object id", String.class);
-        assertContainsFieldWithValue(unionExt3Class, "serialVersionUID", Long.TYPE, 4347887914884631036L, String.class);
+        assertContainsFieldWithValue(unionExt3Class, UNITS, String.class, "object id", new Class<?>[] { String.class },
+                "");
+        assertContainsFieldWithValue(unionExt3Class, "serialVersionUID", Long.TYPE, 4347887914884631036L,
+                new Class<?>[] { String.class }, "");
         assertEquals(5, unionExt3Class.getDeclaredFields().length);
         assertContainsMethod(unionExt3Class, String.class, "getString");
         assertContainsMethod(unionExt3Class, unionExt2Class, "getUnionExt2");
@@ -335,7 +341,8 @@ public class TypedefCompilationTest extends BaseCompilationTest {
         assertContainsField(unionExt4Class, "_int32Ext2", int32Ext2Class);
         assertContainsField(unionExt4Class, "_empty", Boolean.class);
         assertContainsField(unionExt4Class, "_myDecimalType", myDecimalTypeClass);
-        assertContainsFieldWithValue(unionExt4Class, "serialVersionUID", Long.TYPE, 4299836385615211130L, Boolean.class);
+        assertContainsFieldWithValue(unionExt4Class, "serialVersionUID", Long.TYPE, 4299836385615211130L,
+                new Class<?>[] { Boolean.class }, false);
         assertEquals(6, unionExt4Class.getDeclaredFields().length);
         assertContainsMethod(unionExt4Class, unionExt3Class, "getUnionExt3");
         assertContainsMethod(unionExt4Class, int32Ext2Class, "getInt32Ext2");
index 0b41762aeb07be4cab6507aee211394719dd6905..069fbe1619b75d5be2d0ccd3b01e9bf4118bd00f 100644 (file)
@@ -9,14 +9,25 @@ module bar {
     yang-version 1;
     namespace "urn:opendaylight.bar";
     prefix "bar";
+       
+       description "bar - Network topology is the arrangement of the various elements (links, nodes, etc.) of a computer network.[1][2] Essentially, it is the topological[3] structure of a network, and may be depicted physically or logically. Physical topology is the placement of the various components of a network, including device location and cable installation, while logical topology illustrates how data flows within a network, regardless of its physical design. Distances between nodes, physical interconnections, transmission rates, or signal types may differ between two networks, yet their topologies may be identical.";
+       reference "RFC 6020 - http://tools.ietf.org/html/rfc6020";
 
     revision "2013-10-08" {
     }
 
     container network-topology {
+               description "network-topology - Network topology is the arrangement of the various elements (links, nodes, etc.) of a computer network.[1][2] Essentially, it is the topological[3] structure of a network, and may be depicted physically or logically. Physical topology is the placement of the various components of a network, including device location and cable installation, while logical topology illustrates how data flows within a network, regardless of its physical design. Distances between nodes, physical interconnections, transmission rates, or signal types may differ between two networks, yet their topologies may be identical.";
+               reference "RFC 6020 - http://tools.ietf.org/html/rfc6020";
+               
         list topology {
+                       description "topology - Network topology is the arrangement of the various elements (links, nodes, etc.) of a computer network.[1][2] Essentially, it is the topological[3] structure of a network, and may be depicted physically or logically. Physical topology is the placement of the various components of a network, including device location and cable installation, while logical topology illustrates how data flows within a network, regardless of its physical design. Distances between nodes, physical interconnections, transmission rates, or signal types may differ between two networks, yet their topologies may be identical.";
+                       reference "RFC 6020 - http://tools.ietf.org/html/rfc6020";
+                       
             key "topology-id";
             leaf topology-id {
+                               description "topology-id - Network topology is the arrangement of the various elements (links, nodes, etc.) of a computer network.[1][2] Essentially, it is the topological[3] structure of a network, and may be depicted physically or logically. Physical topology is the placement of the various components of a network, including device location and cable installation, while logical topology illustrates how data flows within a network, regardless of its physical design. Distances between nodes, physical interconnections, transmission rates, or signal types may differ between two networks, yet their topologies may be identical.";
+                               reference "RFC 6020 - http://tools.ietf.org/html/rfc6020";
                 type int32;
             }
             uses link;
@@ -25,6 +36,8 @@ module bar {
 
     grouping link {
         list link {
+                       description "Link - Network topology is the arrangement of the various elements (links, nodes, etc.) of a computer network.[1][2] Essentially, it is the topological[3] structure of a network, and may be depicted physically or logically. Physical topology is the placement of the various components of a network, including device location and cable installation, while logical topology illustrates how data flows within a network, regardless of its physical design. Distances between nodes, physical interconnections, transmission rates, or signal types may differ between two networks, yet their topologies may be identical.";
+                       reference "RFC 6020 - http://tools.ietf.org/html/rfc6020";
             key "link-id";
             uses link-attributes;
         }
@@ -32,8 +45,37 @@ module bar {
 
     grouping link-attributes {
         leaf link-id {
+                       description "Link-attributes - Network topology is the arrangement of the various elements (links, nodes, etc.) of a computer network.[1][2] Essentially, it is the topological[3] structure of a network, and may be depicted physically or logically. Physical topology is the placement of the various components of a network, including device location and cable installation, while logical topology illustrates how data flows within a network, regardless of its physical design. Distances between nodes, physical interconnections, transmission rates, or signal types may differ between two networks, yet their topologies may be identical.";
+                       reference "RFC 6020 - http://tools.ietf.org/html/rfc6020";
             type int8;
         }
     }
+       
+       leaf inclusion-rulez {
+               description "Specified rulez description.";
+               reference "RFC 6020 http://technet.com";
+               
+               type string;
+       }
 
+       leaf inclusion-rule {
+        description "Specify how inheritance will work for this label";
+        default include;
+
+        type enumeration {
+            enum include {
+                description 
+                    "This label will be included normally in the 
+                     matching. This seems to be a little bit longer comment. I hear you very weel my darling.
+                                        Network topology is the arrangement of the various elements (links, nodes, etc.) of any other builder nodes types.";
+            }
+            enum exclude {
+                description 
+                    "This label will be excluded from the 
+                    matching.  This allows removing labels that
+                    would have otherwise been included because of
+                    inheritence rules.";
+            }
+        }
+    }
 }
index 99e66a155a4812774f689584a9b9e0871bacb957..4bdc209aa7b6f7afde77d393e203c67c4e740068 100644 (file)
@@ -19,6 +19,9 @@ module baz {
         prefix "br";
         revision-date 2013-10-08;
     }
+       
+       description "Baz - Network topology is the arrangement of the various elements (links, nodes, etc.) of a computer network.[1][2] Essentially, it is the topological[3] structure of a network, and may be depicted physically or logically. Physical topology is the placement of the various components of a network, including device location and cable installation, while logical topology illustrates how data flows within a network, regardless of its physical design. Distances between nodes, physical interconnections, transmission rates, or signal types may differ between two networks, yet their topologies may be identical.";
+       reference "RFC 6020 - http://tools.ietf.org/html/rfc6020";
 
     revision "2013-10-08" {
     }
@@ -31,7 +34,12 @@ module baz {
 
     grouping link-attributes {
         container ospf-link-attributes {
+                       description "Ospf-link-attributes - Network topology is the arrangement of the various elements (links, nodes, etc.) of a computer network.[1][2] Essentially, it is the topological[3] structure of a network, and may be depicted physically or logically. Physical topology is the placement of the various components of a network, including device location and cable installation, while logical topology illustrates how data flows within a network, regardless of its physical design. Distances between nodes, physical interconnections, transmission rates, or signal types may differ between two networks, yet their topologies may be identical.";
+                       reference "RFC 6020 - http://tools.ietf.org/html/rfc6020";
             leaf multi-topology-id {
+                               description "Multi-topology-id - Network topology is the arrangement of the various elements (links, nodes, etc.) of a computer network.[1][2] Essentially, it is the topological[3] structure of a network, and may be depicted physically or logically. Physical topology is the placement of the various components of a network, including device location and cable installation, while logical topology illustrates how data flows within a network, regardless of its physical design. Distances between nodes, physical interconnections, transmission rates, or signal types may differ between two networks, yet their topologies may be identical.";
+                               reference "RFC 6020 - http://tools.ietf.org/html/rfc6020";
+                               
                 type uint8 {
                     range "0..127";
                 }
index a20749d56dd13d41aea70e9cd9a6e5d23bec372d..5fa313eaec10986959da870b3f6c948d5c4b9660 100644 (file)
@@ -14,6 +14,9 @@ module foo {
         prefix "br";
         revision-date 2013-10-08;
     }
+       
+       description "Foo - Network topology is the arrangement of the various elements (links, nodes, etc.) of a computer network.[1][2] Essentially, it is the topological[3] structure of a network, and may be depicted physically or logically. Physical topology is the placement of the various components of a network, including device location and cable installation, while logical topology illustrates how data flows within a network, regardless of its physical design. Distances between nodes, physical interconnections, transmission rates, or signal types may differ between two networks, yet their topologies may be identical.";
+       reference "RFC 6020 - http://tools.ietf.org/html/rfc6020";
 
     revision "2013-10-08" {
     }
@@ -25,13 +28,22 @@ module foo {
 
     grouping igp-link-attributes {
         container igp-link-attributes {
+                       description "Igp-link-attributes - Network topology is the arrangement of the various elements (links, nodes, etc.) of a computer network.[1][2] Essentially, it is the topological[3] structure of a network, and may be depicted physically or logically. Physical topology is the placement of the various components of a network, including device location and cable installation, while logical topology illustrates how data flows within a network, regardless of its physical design. Distances between nodes, physical interconnections, transmission rates, or signal types may differ between two networks, yet their topologies may be identical.";
+                       reference "RFC 6020 - http://tools.ietf.org/html/rfc6020";
+               
             leaf name {
+                               description "Name - Network topology is the arrangement of the various elements (links, nodes, etc.) of a computer network.[1][2] Essentially, it is the topological[3] structure of a network, and may be depicted physically or logically. Physical topology is the placement of the various components of a network, including device location and cable installation, while logical topology illustrates how data flows within a network, regardless of its physical design. Distances between nodes, physical interconnections, transmission rates, or signal types may differ between two networks, yet their topologies may be identical.";
+                               reference "RFC 6020 - http://tools.ietf.org/html/rfc6020";
                 type string;
             }
             leaf-list flag {
+                               description "Flag - Network topology is the arrangement of the various elements (links, nodes, etc.) of a computer network.[1][2] Essentially, it is the topological[3] structure of a network, and may be depicted physically or logically. Physical topology is the placement of the various components of a network, including device location and cable installation, while logical topology illustrates how data flows within a network, regardless of its physical design. Distances between nodes, physical interconnections, transmission rates, or signal types may differ between two networks, yet their topologies may be identical.";
+                               reference "RFC 6020 - http://tools.ietf.org/html/rfc6020";
                 type string;
             }
             leaf metric {
+                               description "Metric - Network topology is the arrangement of the various elements (links, nodes, etc.) of a computer network.[1][2] Essentially, it is the topological[3] structure of a network, and may be depicted physically or logically. Physical topology is the placement of the various components of a network, including device location and cable installation, while logical topology illustrates how data flows within a network, regardless of its physical design. Distances between nodes, physical interconnections, transmission rates, or signal types may differ between two networks, yet their topologies may be identical.";
+                               reference "RFC 6020 - http://tools.ietf.org/html/rfc6020";
                 type uint32 {
                     range "0..16777215"  {
                     }
diff --git a/code-generator/binding-java-api-generator/src/test/resources/compilation/bug1097/foo.yang b/code-generator/binding-java-api-generator/src/test/resources/compilation/bug1097/foo.yang
new file mode 100644 (file)
index 0000000..fc0c4e2
--- /dev/null
@@ -0,0 +1,17 @@
+module foo {
+  namespace "urn:test:foo";
+  prefix foo;
+
+  revision 2014-07-17 {
+  }
+
+
+    container link {
+        list node {
+            leaf id {
+                type string;
+            }
+        }
+    }
+
+}
diff --git a/code-generator/binding-java-api-generator/src/test/resources/compilation/bug1276/foo.yang b/code-generator/binding-java-api-generator/src/test/resources/compilation/bug1276/foo.yang
new file mode 100644 (file)
index 0000000..9f77227
--- /dev/null
@@ -0,0 +1,62 @@
+ module foo {
+
+   namespace "test:yang:union";
+   prefix "foo";
+
+   revision 2014-07-15 {
+   }
+
+
+   typedef ip-address {
+     type union {
+       type ipv4-address;
+       type ipv6-address;
+     }
+   }
+
+   typedef ipv4-address {
+     type string {
+       pattern
+         '(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\.){3}'
+       +  '([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])'
+       + '(%[\p{N}\p{L}]+)?';
+     }
+   }
+
+   typedef ipv6-address {
+     type string {
+       pattern '((:|[0-9a-fA-F]{0,4}):)([0-9a-fA-F]{0,4}:){0,5}'
+             + '((([0-9a-fA-F]{0,4}:)?(:|[0-9a-fA-F]{0,4}))|'
+             + '(((25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9])\.){3}'
+             + '(25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9])))'
+             + '(%[\p{N}\p{L}]+)?';
+       pattern '(([^:]+:){6}(([^:]+:[^:]+)|(.*\..*)))|'
+             + '((([^:]+:)*[^:]+)?::(([^:]+:)*[^:]+)?)'
+             + '(%.+)?';
+     }
+   }
+
+   typedef domain-name {
+     type string {
+       pattern '((([a-zA-Z0-9_]([a-zA-Z0-9\-_]){0,61})?[a-zA-Z0-9]\.)*'
+            +  '([a-zA-Z0-9_]([a-zA-Z0-9\-_]){0,61})?[a-zA-Z0-9]\.?)'
+            +  '|\.';
+       length "1..253";
+     }
+   }
+
+   typedef host {
+     type union {
+       type ip-address;
+       type domain-name;
+     }
+   }
+
+    typedef int-type {
+        type union {
+            type binary;
+            type int8;
+        }
+    }
+
+ }
diff --git a/code-generator/binding-java-api-generator/src/test/resources/compilation/bug1377/foo.yang b/code-generator/binding-java-api-generator/src/test/resources/compilation/bug1377/foo.yang
new file mode 100644 (file)
index 0000000..b31a891
--- /dev/null
@@ -0,0 +1,21 @@
+module foo {
+  namespace "urn:test:foo";
+  prefix foo;
+
+  revision 2014-07-17 {
+  }
+
+
+    grouping action {
+        choice action {
+            case output-action-case {
+                container output-action {
+                    leaf id {
+                        type string;
+                    }
+                }
+            }
+        }
+    }
+
+}
diff --git a/code-generator/binding-model-api/src/main/java/org/opendaylight/yangtools/sal/binding/model/api/DocumentedType.java b/code-generator/binding-model-api/src/main/java/org/opendaylight/yangtools/sal/binding/model/api/DocumentedType.java
new file mode 100644 (file)
index 0000000..484d7d4
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * 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.yangtools.sal.binding.model.api;
+
+import org.opendaylight.yangtools.yang.common.QName;
+
+/**
+ * Implementing this interface allows an object to hold information which are
+ * essential for generating java doc from type definition.
+ */
+public interface DocumentedType {
+
+    /**
+     * Returns a string that contains a human-readable textual description of
+     * type definition.
+     *
+     * @return a human-readable textual description of type definition.
+     */
+    String getDescription();
+
+    /**
+     * Returns a string that is used to specify a textual cross-reference to an
+     * external document, either another module that defines related management
+     * information, or a document that provides additional information relevant
+     * to this definition.
+     *
+     * @return a textual cross-reference to an external document.
+     */
+    String getReference();
+
+    /**
+     * Returns a list of QNames which represent schema path in schema tree from
+     * actual concrete type to the root.
+     *
+     * @return a schema path in schema tree from actual concrete schema node
+     *         identifier to the root.
+     */
+    Iterable<QName> getSchemaPath();
+
+    /**
+     * Returns the name of the module, in which generated type was specified.
+     *
+     * @return the name of the module, in which generated type was specified.
+     */
+    String getModuleName();
+}
index 9599a7af22840b45425693cabb01edb95d9bd009..9709be32def1212aa5b66ce9024f02891c9e1279 100644 (file)
@@ -9,32 +9,36 @@ package org.opendaylight.yangtools.sal.binding.model.api;
 
 import java.util.List;
 
+import org.opendaylight.yangtools.yang.model.api.DocumentedNode;
+
 /**
  * Interface provide methods for reading data of enumeration class.
  */
 public interface Enumeration extends GeneratedType {
 
     /**
-     * 
+     *
      * Returns list of annotation definitions associated with enumeration type.
-     * 
+     *
      * @return list of annotation definitions associated with enumeration type.
-     * 
+     *
      */
+    @Override
     List<AnnotationType> getAnnotations();
 
+    @Override
     Type getParentType();
 
     /**
      * Returns list of the couples - name and value.
-     * 
+     *
      * @return list of the enumeration pairs.
      */
     List<Pair> getValues();
 
     /**
      * Formats enumeration according to rules of the programming language.
-     * 
+     *
      * @return string with source code in some programming language
      */
     String toFormattedString();
@@ -43,18 +47,18 @@ public interface Enumeration extends GeneratedType {
      * Interface is used for reading enumeration item. It means item's name and
      * its value.
      */
-    interface Pair {
+    interface Pair extends DocumentedNode {
 
         /**
          * Returns the name of the enumeration item.
-         * 
+         *
          * @return the name of the enumeration item.
          */
         String getName();
 
         /**
          * Returns value of the enumeration item.
-         * 
+         *
          * @return the value of the enumeration item.
          */
         Integer getValue();
index 4506daf98df4041732964bfabd43a47a3134d147..0e9b51ee741f42bb5952961421d046c7c52efa2a 100644 (file)
@@ -28,17 +28,17 @@ import java.util.List;
  * <li><code>method definitions</code> with specified input parameters (with
  * types) and return values</li>
  * </ul>
- * 
+ *
  * By the definition of the interface constant, enum, enclosed types and method
  * definitions MUST be public, so there is no need to specify the scope of
  * visibility.
  */
-public interface GeneratedType extends Type {
+public interface GeneratedType extends Type, DocumentedType {
 
     /**
      * Returns the parent type if Generated Type is defined as enclosing type,
      * otherwise returns <code>null</code>
-     * 
+     *
      * @return the parent type if Generated Type is defined as enclosing type,
      *         otherwise returns <code>null</code>
      */
@@ -46,35 +46,35 @@ public interface GeneratedType extends Type {
 
     /**
      * Returns comment string associated with Generated Type.
-     * 
+     *
      * @return comment string associated with Generated Type.
      */
     String getComment();
 
     /**
      * Returns List of annotation definitions associated with generated type.
-     * 
+     *
      * @return List of annotation definitions associated with generated type.
      */
     List<AnnotationType> getAnnotations();
 
     /**
      * Returns <code>true</code> if The Generated Type is defined as abstract.
-     * 
+     *
      * @return <code>true</code> if The Generated Type is defined as abstract.
      */
     boolean isAbstract();
 
     /**
      * Returns List of Types that Generated Type will implement.
-     * 
+     *
      * @return List of Types that Generated Type will implement.
      */
     List<Type> getImplements();
 
     /**
      * Returns List of enclosing Generated Types.
-     * 
+     *
      * @return List of enclosing Generated Types.
      */
     List<GeneratedType> getEnclosedTypes();
@@ -82,7 +82,7 @@ public interface GeneratedType extends Type {
     /**
      * Returns List of all Enumerator definitions associated with Generated
      * Type.
-     * 
+     *
      * @return List of all Enumerator definitions associated with Generated
      *         Type.
      */
@@ -90,16 +90,16 @@ public interface GeneratedType extends Type {
 
     /**
      * Returns List of Constant definitions associated with Generated Type.
-     * 
+     *
      * @return List of Constant definitions associated with Generated Type.
      */
     List<Constant> getConstantDefinitions();
 
     /**
      * Returns List of Method Definitions associated with Generated Type.
-     * 
+     *
      * List does not contains getters and setters for properties.
-     * 
+     *
      * @return List of Method Definitions associated with Generated Type.
      */
     List<MethodSignature> getMethodDefinitions();
@@ -107,7 +107,7 @@ public interface GeneratedType extends Type {
     /**
      * Returns List of Properties that are declared for Generated Transfer
      * Object.
-     * 
+     *
      * @return List of Properties that are declared for Generated Transfer
      *         Object.
      */
index 264b92c0da9ebf12259913a84694cbafe62cfded..a3339b9276fb701c07b50ff1538322909778f9fe 100644 (file)
@@ -14,7 +14,7 @@ import org.opendaylight.yangtools.yang.model.api.type.EnumTypeDefinition;
 /**
  * Enum Builder is interface that contains methods to build and instantiate
  * Enumeration definition.
- * 
+ *
  * @see Enumeration
  */
 public interface EnumBuilder extends Type {
@@ -25,7 +25,7 @@ public interface EnumBuilder extends Type {
      * Neither the package name or annotation name can contain <code>null</code>
      * references. In case that any of parameters contains <code>null</code> the
      * method SHOULD thrown {@link IllegalArgumentException}
-     * 
+     *
      * @param packageName
      *            Package Name of Annotation Type
      * @param name
@@ -35,14 +35,14 @@ public interface EnumBuilder extends Type {
     AnnotationTypeBuilder addAnnotation(final String packageName, final String name);
 
     /**
-     * 
+     *
      * @param name
      * @param value
      */
-    void addValue(final String name, final Integer value);
+    void addValue(final String name, final Integer value, final String description);
 
     /**
-     * 
+     *
      * @param definingType
      * @return
      */
@@ -51,11 +51,16 @@ public interface EnumBuilder extends Type {
     /**
      * Updates this builder with data from <code>enumTypeDef</code>.
      * Specifically this data represents list of value-name pairs.
-     * 
+     *
      * @param enumTypeDef
      *            enum type definition as source of enum data for
      *            <code>enumBuilder</code>
      */
     void updateEnumPairsFromEnumTypeDef(final EnumTypeDefinition enumTypeDef);
 
+    /**
+     * @param description
+     */
+    void setDescription(final String description);
+
 }
index 22dce2cd84e89c0690cc46017ede3c83f1f71ab2..628029f02869760998d3f33618832b2f70a428c2 100644 (file)
@@ -8,8 +8,10 @@
 package org.opendaylight.yangtools.sal.binding.model.api.type.builder;
 
 import java.util.List;
+
 import org.opendaylight.yangtools.sal.binding.model.api.Constant;
 import org.opendaylight.yangtools.sal.binding.model.api.Type;
+import org.opendaylight.yangtools.yang.common.QName;
 
 public interface GeneratedTypeBuilderBase<T extends GeneratedTypeBuilderBase<T>> extends Type {
 
@@ -179,4 +181,42 @@ public interface GeneratedTypeBuilderBase<T extends GeneratedTypeBuilderBase<T>>
      */
     boolean containsProperty(final String name);
 
+    /**
+     * Set a string that contains a human-readable textual description of type
+     * definition.
+     *
+     * @param description
+     *            a string that contains a human-readable textual description of
+     *            type definition.
+     */
+    public void setDescription(String description);
+
+    /**
+     * Set the name of the module, in which generated type was specified.
+     *
+     * @param moduleName
+     *            the name of the module
+     */
+    public void setModuleName(String moduleName);
+
+    /**
+     * Set a list of QNames which represent schema path in schema tree from
+     * actual concrete type to the root.
+     *
+     * @param schemaPath
+     *            a list of QNames which represent schema path in schema tree
+     */
+    public void setSchemaPath(Iterable<QName> schemaPath);
+
+    /**
+     * Set a string that is used to specify a textual cross-reference to an
+     * external document, either another module that defines related management
+     * information, or a document that provides additional information relevant
+     * to this definition.
+     *
+     * @param reference
+     *            a textual cross-reference to an external document.
+     */
+    public void setReference(String reference);
+
 }
index 7b1aa834f813b10b746907666a7db59cf65b95c7..cf23c844de29cfe5e5ea5d2ab36905f8a7dfb3ce 100644 (file)
@@ -14,9 +14,6 @@ import static org.opendaylight.yangtools.yang.model.util.SchemaContextUtil.findD
 import static org.opendaylight.yangtools.yang.model.util.SchemaContextUtil.findDataSchemaNodeForRelativeXPath;
 import static org.opendaylight.yangtools.yang.model.util.SchemaContextUtil.findParentModule;
 
-import com.google.common.base.Preconditions;
-import com.google.common.collect.Sets;
-import com.google.common.io.BaseEncoding;
 import java.io.Serializable;
 import java.math.BigDecimal;
 import java.math.BigInteger;
@@ -34,6 +31,7 @@ import java.util.Set;
 import java.util.TreeMap;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
+
 import org.apache.commons.lang3.StringEscapeUtils;
 import org.opendaylight.yangtools.binding.generator.util.BindingGeneratorUtil;
 import org.opendaylight.yangtools.binding.generator.util.TypeConstants;
@@ -92,6 +90,10 @@ import org.opendaylight.yangtools.yang.model.util.Uint64;
 import org.opendaylight.yangtools.yang.model.util.Uint8;
 import org.opendaylight.yangtools.yang.model.util.UnionType;
 
+import com.google.common.base.Preconditions;
+import com.google.common.collect.Sets;
+import com.google.common.io.BaseEncoding;
+
 public final class TypeProviderImpl implements TypeProvider {
     private static final Pattern NUMBERS_PATTERN = Pattern.compile("[0-9]+\\z");
 
@@ -195,8 +197,7 @@ public final class TypeProviderImpl implements TypeProvider {
         Preconditions.checkArgument(typeDefinition.getQName() != null,
                 "Type Definition cannot have non specified QName (QName cannot be NULL!)");
         String typedefName = typeDefinition.getQName().getLocalName();
-        Preconditions.checkArgument(typedefName != null,
-                "Type Definitions Local Name cannot be NULL!");
+        Preconditions.checkArgument(typedefName != null, "Type Definitions Local Name cannot be NULL!");
 
         if (typeDefinition instanceof ExtendedType) {
             returnType = javaTypeForExtendedType(typeDefinition);
@@ -549,7 +550,11 @@ public final class TypeProviderImpl implements TypeProvider {
         Module module = findParentModule(schemaContext, parentNode);
         final String basePackageName = moduleNamespaceToPackageName(module);
 
-        final EnumBuilder enumBuilder = new EnumerationBuilderImpl(basePackageName, enumerationName);
+        final EnumerationBuilderImpl enumBuilder = new EnumerationBuilderImpl(basePackageName, enumerationName);
+        enumBuilder.setDescription(enumTypeDef.getDescription());
+        enumBuilder.setReference(enumTypeDef.getReference());
+        enumBuilder.setModuleName(module.getName());
+        enumBuilder.setSchemaPath(enumTypeDef.getPath().getPathFromRoot());
         enumBuilder.updateEnumPairsFromEnumTypeDef(enumTypeDef);
         return enumBuilder.toInstance(null);
     }
@@ -590,6 +595,7 @@ public final class TypeProviderImpl implements TypeProvider {
         final String enumerationName = BindingMapping.getClassName(enumName);
 
         final EnumBuilder enumBuilder = typeBuilder.addEnumeration(enumerationName);
+        enumBuilder.setDescription(enumTypeDef.getDescription());
         enumBuilder.updateEnumPairsFromEnumTypeDef(enumTypeDef);
         return enumBuilder.toInstance(enumBuilder);
     }
@@ -637,7 +643,8 @@ public final class TypeProviderImpl implements TypeProvider {
         for (Module modul : modules) {
             modulesArray[i++] = modul;
         }
-        final List<Module> modulesSortedByDependency = org.opendaylight.yangtools.yang.parser.util.ModuleDependencySort.sort(modulesArray);
+        final List<Module> modulesSortedByDependency = org.opendaylight.yangtools.yang.parser.util.ModuleDependencySort
+                .sort(modulesArray);
 
         for (final Module module : modulesSortedByDependency) {
             Map<Date, Map<String, Type>> dateTypeMap = genTypeDefsContextMap.get(module.getName());
@@ -694,7 +701,8 @@ public final class TypeProviderImpl implements TypeProvider {
                 Type returnType = null;
                 if (innerTypeDefinition instanceof ExtendedType) {
                     ExtendedType innerExtendedType = (ExtendedType) innerTypeDefinition;
-                    returnType = provideGeneratedTOFromExtendedType(typedef, innerExtendedType, basePackageName);
+                    returnType = provideGeneratedTOFromExtendedType(typedef, innerExtendedType, basePackageName,
+                            module.getName());
                 } else if (innerTypeDefinition instanceof UnionTypeDefinition) {
                     final GeneratedTOBuilder genTOBuilder = provideGeneratedTOBuilderForUnionTypeDef(basePackageName,
                             (UnionTypeDefinition) innerTypeDefinition, typedefName, typedef);
@@ -727,7 +735,7 @@ public final class TypeProviderImpl implements TypeProvider {
                 } else if (innerTypeDefinition instanceof BitsTypeDefinition) {
                     final BitsTypeDefinition bitsTypeDefinition = (BitsTypeDefinition) innerTypeDefinition;
                     final GeneratedTOBuilder genTOBuilder = provideGeneratedTOBuilderForBitsTypeDefinition(
-                            basePackageName, bitsTypeDefinition, typedefName);
+                            basePackageName, bitsTypeDefinition, typedefName, module.getName());
                     genTOBuilder.setTypedef(true);
                     addUnitsToGenTO(genTOBuilder, typedef.getUnits());
                     makeSerializable((GeneratedTOBuilderImpl) genTOBuilder);
@@ -735,7 +743,7 @@ public final class TypeProviderImpl implements TypeProvider {
                 } else {
                     final Type javaType = BaseYangTypes.BASE_YANG_TYPES_PROVIDER.javaTypeForSchemaDefinitionType(
                             innerTypeDefinition, typedef);
-                    returnType = wrapJavaTypeIntoTO(basePackageName, typedef, javaType);
+                    returnType = wrapJavaTypeIntoTO(basePackageName, typedef, javaType, module.getName());
                 }
                 if (returnType != null) {
                     final Map<Date, Map<String, Type>> modulesByDate = genTypeDefsContextMap.get(moduleName);
@@ -762,11 +770,11 @@ public final class TypeProviderImpl implements TypeProvider {
      * @return generated transfer object which represent<code>javaType</code>
      */
     private GeneratedTransferObject wrapJavaTypeIntoTO(final String basePackageName, final TypeDefinition<?> typedef,
-            final Type javaType) {
+            final Type javaType, final String moduleName) {
         Preconditions.checkNotNull(javaType, "javaType cannot be null");
         final String propertyName = "value";
 
-        final GeneratedTOBuilder genTOBuilder = typedefToTransferObject(basePackageName, typedef);
+        final GeneratedTOBuilder genTOBuilder = typedefToTransferObject(basePackageName, typedef, moduleName);
         genTOBuilder.setRestrictions(BindingGeneratorUtil.getRestrictions(typedef));
         final GeneratedPropertyBuilder genPropBuilder = genTOBuilder.addProperty(propertyName);
         genPropBuilder.setReturnType(javaType);
@@ -846,13 +854,18 @@ public final class TypeProviderImpl implements TypeProvider {
 
         final List<GeneratedTOBuilder> generatedTOBuilders = new ArrayList<>();
         final List<TypeDefinition<?>> unionTypes = typedef.getTypes();
+        final Module module = findParentModule(schemaContext, parentNode);
 
-        final GeneratedTOBuilder unionGenTOBuilder;
+        final GeneratedTOBuilderImpl unionGenTOBuilder;
         if (typeDefName != null && !typeDefName.isEmpty()) {
             final String typeName = BindingMapping.getClassName(typeDefName);
             unionGenTOBuilder = new GeneratedTOBuilderImpl(basePackageName, typeName);
+            unionGenTOBuilder.setDescription(typedef.getDescription());
+            unionGenTOBuilder.setReference(typedef.getReference());
+            unionGenTOBuilder.setSchemaPath(typedef.getPath().getPathFromRoot());
+            unionGenTOBuilder.setModuleName(module.getName());
         } else {
-            unionGenTOBuilder = typedefToTransferObject(basePackageName, typedef);
+            unionGenTOBuilder = typedefToTransferObject(basePackageName, typedef, module.getName());
         }
 
         generatedTOBuilders.add(unionGenTOBuilder);
@@ -942,8 +955,7 @@ public final class TypeProviderImpl implements TypeProvider {
      *            list of strings with the regular expressions
      */
     private void resolveExtendedSubtypeAsUnion(final GeneratedTOBuilder parentUnionGenTOBuilder,
-            final ExtendedType unionSubtype, final List<String> regularExpressions,
-            final SchemaNode parentNode) {
+            final ExtendedType unionSubtype, final List<String> regularExpressions, final SchemaNode parentNode) {
         final String unionTypeName = unionSubtype.getQName().getLocalName();
         final Type genTO = findGenTO(unionTypeName, unionSubtype);
         if (genTO != null) {
@@ -995,7 +1007,8 @@ public final class TypeProviderImpl implements TypeProvider {
      *            generated TO builder which is converted to generated TO and
      *            stored
      */
-    private void storeGenTO(final TypeDefinition<?> newTypeDef, final GeneratedTOBuilder genTOBuilder, final SchemaNode parentNode) {
+    private void storeGenTO(final TypeDefinition<?> newTypeDef, final GeneratedTOBuilder genTOBuilder,
+            final SchemaNode parentNode) {
         if (!(newTypeDef instanceof UnionType)) {
 
             final Module parentModule = findParentModule(schemaContext, parentNode);
@@ -1043,15 +1056,21 @@ public final class TypeProviderImpl implements TypeProvider {
      * @return generated TO builder which contains data from
      *         <code>typedef</code> and <code>basePackageName</code>
      */
-    private GeneratedTOBuilder typedefToTransferObject(final String basePackageName, final TypeDefinition<?> typedef) {
+    private GeneratedTOBuilderImpl typedefToTransferObject(final String basePackageName,
+            final TypeDefinition<?> typedef, final String moduleName) {
 
         final String packageName = packageNameForGeneratedType(basePackageName, typedef.getPath());
         final String typeDefTOName = typedef.getQName().getLocalName();
 
         if ((packageName != null) && (typedef != null) && (typeDefTOName != null)) {
             final String genTOName = BindingMapping.getClassName(typeDefTOName);
-            final GeneratedTOBuilder newType = new GeneratedTOBuilderImpl(packageName, genTOName);
-            newType.addComment(typedef.getDescription());
+            final GeneratedTOBuilderImpl newType = new GeneratedTOBuilderImpl(packageName, genTOName);
+
+            newType.setDescription(typedef.getDescription());
+            newType.setReference(typedef.getReference());
+            newType.setSchemaPath(typedef.getPath().getPathFromRoot());
+            newType.setModuleName(moduleName);
+
             return newType;
         }
         return null;
@@ -1078,7 +1097,7 @@ public final class TypeProviderImpl implements TypeProvider {
      *             </ul>
      */
     public GeneratedTOBuilder provideGeneratedTOBuilderForBitsTypeDefinition(final String basePackageName,
-            final TypeDefinition<?> typeDef, final String typeDefName) {
+            final TypeDefinition<?> typeDef, final String typeDefName, final String moduleName) {
 
         Preconditions.checkArgument(typeDef != null, "typeDef cannot be NULL!");
         Preconditions.checkArgument(basePackageName != null, "Base Package Name cannot be NULL!");
@@ -1087,7 +1106,12 @@ public final class TypeProviderImpl implements TypeProvider {
             BitsTypeDefinition bitsTypeDefinition = (BitsTypeDefinition) typeDef;
 
             final String typeName = BindingMapping.getClassName(typeDefName);
-            final GeneratedTOBuilder genTOBuilder = new GeneratedTOBuilderImpl(basePackageName, typeName);
+            final GeneratedTOBuilderImpl genTOBuilder = new GeneratedTOBuilderImpl(basePackageName, typeName);
+
+            genTOBuilder.setDescription(typeDef.getDescription());
+            genTOBuilder.setReference(typeDef.getReference());
+            genTOBuilder.setSchemaPath(typeDef.getPath().getPathFromRoot());
+            genTOBuilder.setModuleName(moduleName);
 
             final List<Bit> bitList = bitsTypeDefinition.getBits();
             GeneratedPropertyBuilder genPropertyBuilder;
@@ -1192,7 +1216,7 @@ public final class TypeProviderImpl implements TypeProvider {
      *             </ul>
      */
     private GeneratedTransferObject provideGeneratedTOFromExtendedType(final TypeDefinition<?> typedef,
-            final ExtendedType innerExtendedType, final String basePackageName) {
+            final ExtendedType innerExtendedType, final String basePackageName, final String moduleName) {
         Preconditions.checkArgument(innerExtendedType != null, "Extended type cannot be NULL!");
         Preconditions.checkArgument(basePackageName != null, "String with base package name cannot be NULL!");
 
@@ -1200,6 +1224,11 @@ public final class TypeProviderImpl implements TypeProvider {
         final String classTypedefName = BindingMapping.getClassName(typedefName);
         final String innerTypeDef = innerExtendedType.getQName().getLocalName();
         final GeneratedTOBuilderImpl genTOBuilder = new GeneratedTOBuilderImpl(basePackageName, classTypedefName);
+
+        genTOBuilder.setDescription(typedef.getDescription());
+        genTOBuilder.setReference(typedef.getReference());
+        genTOBuilder.setSchemaPath(typedef.getPath().getPathFromRoot());
+        genTOBuilder.setModuleName(moduleName);
         genTOBuilder.setTypedef(true);
         Restrictions r = BindingGeneratorUtil.getRestrictions(typedef);
         genTOBuilder.setRestrictions(r);
@@ -1461,7 +1490,8 @@ public final class TypeProviderImpl implements TypeProvider {
         return sb.toString();
     }
 
-    private String bitsToDef(final BitsTypeDefinition type, final String className, final String defaultValue, final boolean isExt) {
+    private String bitsToDef(final BitsTypeDefinition type, final String className, final String defaultValue,
+            final boolean isExt) {
         List<Bit> bits = new ArrayList<>(type.getBits());
         Collections.sort(bits, new Comparator<Bit>() {
             @Override
index 9f8ac51670ef787187d4dccbf5c2f83e3441cd97..9f6f06ee639ff8810c22d986e5f00cbf1c296a3f 100644 (file)
@@ -89,9 +89,6 @@
                 <groupId>org.eclipse.xtend</groupId>
                 <artifactId>xtend-maven-plugin</artifactId>
             </plugin>
-            <plugin>
-                <artifactId>maven-clean-plugin</artifactId>
-            </plugin>
         </plugins>
     </build>
 
index e355f24a33c66c85e5119a0573cb6c1117d7ca17..bf2d1b7371c6d5c12137b864951cfc26c00ca521 100644 (file)
                     </dependency>
                 </dependencies>
             </plugin>
-            <plugin>
-                <groupId>org.codehaus.mojo</groupId>
-                <artifactId>build-helper-maven-plugin</artifactId>
-                <executions>
-                    <execution>
-                        <phase>generate-sources</phase>
-                        <goals>
-                            <goal>add-source</goal>
-                        </goals>
-                        <configuration>
-                            <sources>
-                                <source>target/generated-sources/sal</source>
-                            </sources>
-                        </configuration>
-                    </execution>
-                </executions>
-            </plugin>
         </plugins>
        </build>
     <dependencies>
index ab3bac3035472b5790dc8801f92c2482a8b350c7..f9ef1a7b0b67d757eaee2c5ac4b10464f8fe4693 100644 (file)
                     </dependency>
                 </dependencies>
             </plugin>
-            <plugin>
-                <groupId>org.codehaus.mojo</groupId>
-                <artifactId>build-helper-maven-plugin</artifactId>
-                <executions>
-                    <execution>
-                        <phase>generate-sources</phase>
-                        <goals>
-                            <goal>add-source</goal>
-                        </goals>
-                        <configuration>
-                            <sources>
-                                <source>target/generated-sources/sal</source>
-                            </sources>
-                        </configuration>
-                    </execution>
-                </executions>
-            </plugin>
         </plugins>
           </build>
     <dependencies>
index 6782698c32dd34aef65e8774ae9c0e0487ef557f..ee51ec6ef4ea9031f5c757b4b98aca739a977ee7 100644 (file)
@@ -15,6 +15,7 @@
         <feature version='${project.version}'>yangtools-common</feature>
         <feature version='${project.version}'>yangtools-concepts</feature>
         <feature version='${project.version}'>yangtools-binding-generator</feature>
+        <feature version='${project.version}'>yangtools-restconf</feature>
     </feature>
 
     <feature name='yangtools-models' version='${project.version}'>
         <bundle>mvn:org.opendaylight.yangtools/yang-model-util/${project.version}</bundle>
         <bundle>mvn:org.opendaylight.yangtools/yang-parser-api/${project.version}</bundle>
     </feature>
+    <feature name="yangtools-restconf" version='${project.version}'>
+        <bundle>mvn:org.opendaylight.yangtools/restconf-client-api/${project.version}</bundle>
+        <bundle>mvn:org.opendaylight.yangtools/restconf-client-impl/${project.version}</bundle>
+        <bundle>mvn:org.opendaylight.yangtools/restconf-common/${project.version}</bundle>
+     </feature>
+
 
 </features>
index 3f0675ba4d9fdf0dfbd16ae06c4792a0058b974b..84d4dfe9da7db6fc2d455dc6e66aeff0bdeb44d6 100644 (file)
                                         <execute />
                                     </action>
                                 </pluginExecution>
+                                <pluginExecution>
+                                    <pluginExecutionFilter>
+                                        <groupId>org.apache.maven.plugins</groupId>
+                                        <artifactId>maven-antrun-plugin</artifactId>
+                                        <versionRange>[1.0,)</versionRange>
+                                        <goals>
+                                            <goal>run</goal>
+                                        </goals>
+                                    </pluginExecutionFilter>
+                                    <action>
+                                        <execute/>
+                                    </action>
+                                </pluginExecution>
+                                <pluginExecution>
+                                    <pluginExecutionFilter>
+                                        <groupId>org.opendaylight.yangtools</groupId>
+                                        <artifactId>yang-maven-plugin</artifactId>
+                                        <versionRange>[0.5,)</versionRange>
+                                        <goals>
+                                            <goal>generate-sources</goal>
+                                        </goals>
+                                     </pluginExecutionFilter>
+                                     <action>
+                                         <ignore />
+                                     </action>
+                                 </pluginExecution>
+                                 <pluginExecution>
+                                    <pluginExecutionFilter>
+                                        <groupId>org.codehaus.mojo</groupId>
+                                        <artifactId>properties-maven-plugin</artifactId>
+                                        <versionRange>1.0-alpha-2</versionRange>
+                                        <goals>
+                                            <goal>write-project-properties</goal>
+                                        </goals>
+                                     </pluginExecutionFilter>
+                                     <action>
+                                         <ignore />
+                                     </action>
+                                 </pluginExecution>
+                                 <pluginExecution>
+                                    <pluginExecutionFilter>
+                                        <groupId>org.ops4j.pax.exam</groupId>
+                                        <artifactId>maven-paxexam-plugin</artifactId>
+                                        <versionRange>1.2.4</versionRange>
+                                        <goals>
+                                            <goal>generate-depends-file</goal>
+                                        </goals>
+                                     </pluginExecutionFilter>
+                                     <action>
+                                         <ignore />
+                                     </action>
+                                 </pluginExecution>
                             </pluginExecutions>
                         </lifecycleMappingMetadata>
                     </configuration>
                         </execution>
                     </executions>
                 </plugin>
+                <plugin>
+                    <groupId>org.codehaus.mojo</groupId>
+                    <artifactId>build-helper-maven-plugin</artifactId>
+                    <version>1.8</version>
+                    <executions>
+                        <execution>
+                            <phase>generate-sources</phase>
+                            <goals>
+                                <goal>add-source</goal>
+                            </goals>
+                            <configuration>
+                                <sources>
+                                    <source>target/generated-sources/parser</source>
+                                    <source>target/generated-sources/sal</source>
+                                    <source>${basedir}/src/main/xtend-gen</source>
+                                </sources>
+                            </configuration>
+                        </execution>
+                    </executions>
+                </plugin>
             </plugins>
         </pluginManagement>
 
                 <groupId>org.apache.maven.plugins</groupId>
                 <artifactId>maven-javadoc-plugin</artifactId>
             </plugin>
+            <plugin>
+                <groupId>org.codehaus.mojo</groupId>
+                <artifactId>build-helper-maven-plugin</artifactId>
+            </plugin>
         </plugins>
     </build>
 
index 2ef038b99f8cf19c0928ad61702831a5745cd31e..d1d8b75806d1d54fcc684230680872b5a147580a 100644 (file)
@@ -19,7 +19,7 @@ import com.google.common.base.Preconditions;
 import com.google.common.collect.Iterables;
 import com.romix.scala.collection.concurrent.TrieMap;
 
-/*
+/**
  * A simple layer on top of maps, which performs snapshot mediation and optimization of
  * what the underlying implementation is.
  */
index 3dd76b81ecaddd085208653fa56c7c06d59eee34..1167a64fa65e40636868f465ca50f99d11131646 100644 (file)
                     </dependency>
                 </dependencies>
             </plugin>
-            <plugin>
-                <groupId>org.codehaus.mojo</groupId>
-                <artifactId>build-helper-maven-plugin</artifactId>
-                <executions>
-                    <execution>
-                        <phase>generate-sources</phase>
-                        <goals>
-                            <goal>add-source</goal>
-                        </goals>
-                        <configuration>
-                            <sources>
-                                <source>target/generated-sources/sal</source>
-                            </sources>
-                        </configuration>
-                    </execution>
-                </executions>
-            </plugin>
         </plugins>
     </build>
 
index 32038f430e41c71f2bb0eb1f0673660b502cbe7f..8d4f608fb5da29020723188c4eb8f88a4a57ba38 100644 (file)
     <description>${project.artifactId}</description>
 
     <dependencies>
+        <dependency>
+            <groupId>com.google.guava</groupId>
+            <artifactId>guava</artifactId>
+        </dependency>
         <dependency>
             <groupId>org.slf4j</groupId>
             <artifactId>slf4j-api</artifactId>
index 7c35f6710393c04e87ffbc927b203ebb61e242de..0ac89ae8da2c1d634d134bc07977877e5a9c4484 100644 (file)
@@ -117,59 +117,6 @@ public final class QName implements Immutable, Serializable, Comparable<QName> {
         return localName;
     }
 
-    /**
-     * QName Constructor.
-     *
-     * @param namespace
-     *            the namespace assigned to the YANG module
-     * @param revision
-     *            the revision of the YANG module
-     * @param localName
-     *            YANG schema identifier
-     *
-     * @deprecated Use {@link #create(URI, Date, String)} instead.
-     */
-    @Deprecated
-    public QName(final URI namespace, final Date revision, final String localName) {
-        this(QNameModule.create(namespace, revision), null, localName);
-    }
-
-    /**
-     * Construct new QName which reuses namespace, revision and prefix from
-     * base.
-     *
-     * @param base
-     * @param localName
-     * @deprecated Use {@link #create(QName, String)} instead.
-     */
-    @Deprecated
-    public QName(final QName base, final String localName) {
-        this(base.getNamespace(), base.getRevision(), base.getPrefix(), localName);
-    }
-
-    /**
-     * @deprecated Use {@link #create(String)} instead. This implementation is
-     *             broken.
-     */
-    @Deprecated
-    public QName(final String input) throws ParseException {
-        final String nsAndRev = input.substring(input.indexOf("(") + 1, input.indexOf(")"));
-        final Date revision;
-        final URI namespace;
-        if (nsAndRev.contains("?")) {
-            String[] splitted = nsAndRev.split("\\?");
-            namespace = URI.create(splitted[0]);
-            revision = getRevisionFormat().parse(splitted[1]);
-        } else {
-            namespace = URI.create(nsAndRev);
-            revision = null;
-        }
-
-        this.localName = checkLocalName(input.substring(input.indexOf(")") + 1));
-        this.prefix = null;
-        this.module = QNameModule.create(namespace, revision);
-    }
-
     public static QName create(final String input) {
         Matcher matcher = QNAME_PATTERN_FULL.matcher(input);
         if (matcher.matches()) {
@@ -281,9 +228,20 @@ public final class QName implements Immutable, Serializable, Comparable<QName> {
     }
 
     public static QName create(final QName base, final String localName) {
-        return new QName(base, localName);
+        return new QName(base.getModule(), base.getPrefix(), localName);
     }
 
+    /**
+     * Creates new QName.
+     *
+     * @param qnameModule
+     *            Namespace and revision enclosed as a QNameModule
+     * @param prefix
+     *            Namespace prefix
+     * @param localName
+     *            Local name part of QName. MUST NOT BE null.
+     * @return Instance of QName
+     */
     public static QName create(final QNameModule module, final String prefix, final String localName) {
         if (module == null) {
             throw new NullPointerException("module may not be null");
index 809ea857220cd8e81448e002b57500257e2553b1..3645637b893af4ba9998922ff86e2f59186d5b4a 100644 (file)
@@ -52,25 +52,25 @@ public interface RpcError {
      * <p>
      * The following outlines suggested values as defined by netconf (<a href="https://tools.ietf.org/html/rfc6241#page-89">RFC 6241</a>):
      * <pre>
-     *    access_denied
-     *    bad_attribute
-     *    bad_element
-     *    data_exists
-     *    data_missing
-     *    in_use
-     *    invalid_value
-     *    lock_denied
-     *    malformed_message
-     *    missing_attribute
-     *    missing_element
-     *    operation_failed
-     *    operation_not_supported
-     *    resource_denied
-     *    rollback_failed
-     *    too_big
-     *    unknown_attribute
-     *    unknown_element
-     *    unknown_namespace
+     *    access-denied
+     *    bad-attribute
+     *    bad-element
+     *    data-exists
+     *    data-missing
+     *    in-use
+     *    invalid-value
+     *    lock-denied
+     *    malformed-message
+     *    missing-attribute
+     *    missing-element
+     *    operation-failed
+     *    operation-not-supported
+     *    resource-denied
+     *    rollback-failed
+     *    too-big
+     *    unknown-attribute
+     *    unknown-element
+     *    unknown-namespace
      * </pre>
      * @return a string if available or null otherwise.
      */
index 7b1b3dca1bf63059cb7242e2102d9afdade1504c..ab358d8c1a8653bd3c716e557ceebe16bb1354d5 100644 (file)
@@ -8,13 +8,14 @@
 
 package org.opendaylight.yangtools.yang.common;
 
-import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
 
 import org.opendaylight.yangtools.yang.common.RpcError.ErrorSeverity;
 import org.opendaylight.yangtools.yang.common.RpcError.ErrorType;
 
+import com.google.common.collect.ImmutableList;
+
 /**
  * A builder for creating RpcResult instances.
  *
@@ -22,7 +23,7 @@ import org.opendaylight.yangtools.yang.common.RpcError.ErrorType;
  *
  * @param <T> the result value type
  */
-public class RpcResultBuilder<T> {
+public final class RpcResultBuilder<T> {
 
     private static class RpcResultImpl<T> implements RpcResult<T> {
 
@@ -125,7 +126,7 @@ public class RpcResultBuilder<T> {
         }
     }
 
-    private Collection<RpcError> errors;
+    private ImmutableList.Builder<RpcError> errors;
     private T result;
     private final boolean successful;
 
@@ -157,6 +158,93 @@ public class RpcResultBuilder<T> {
         return new RpcResultBuilder<T>( false, null );
     }
 
+    /**
+     * Returns a builder based on the given status.
+     *
+     * @param success true if successful, false otherwise.
+     */
+    public static <T> RpcResultBuilder<T> status( boolean success ) {
+        return new RpcResultBuilder<T>( success, null );
+    }
+
+    /**
+     * Returns a builder from another RpcResult.
+     *
+     * @param other the other RpcResult.
+     */
+    public static <T> RpcResultBuilder<T> from( RpcResult<T> other ) {
+        return new RpcResultBuilder<T>( other.isSuccessful(), other.getResult() )
+                                                      .withRpcErrors( other.getErrors() );
+    }
+
+    /**
+     * Creates an RpcError with severity ERROR for reuse.
+     *
+     * @param errorType the conceptual layer at which the error occurred.
+     * @param tag a short string that identifies the general type of error condition. See
+     *        {@link RpcError#getTag} for a list of suggested values.
+     * @param message a string suitable for human display that describes the error condition.
+     *
+     * @return an RpcError
+     */
+    public static RpcError newError( ErrorType errorType, String tag, String message ) {
+        return new RpcErrorImpl( ErrorSeverity.ERROR, errorType, tag, message, null, null, null );
+    }
+
+    /**
+     * Creates an RpcError with severity ERROR for reuse.
+     *
+     * @param errorType the conceptual layer at which the error occurred.
+     * @param tag a short string that identifies the general type of error condition. See
+     *        {@link RpcError#getTag} for a list of suggested values.
+     * @param message a string suitable for human display that describes the error condition.
+     * * @param applicationTag a short string that identifies the specific type of error condition.
+     * @param info a string containing additional information to provide extended
+     *        and/or implementation-specific debugging information.
+     * @param cause the exception that triggered the error.
+     *
+     * @return an RpcError
+     */
+    public static RpcError newError(  ErrorType errorType, String tag, String message,
+            String applicationTag, String info, Throwable cause ) {
+        return new RpcErrorImpl( ErrorSeverity.ERROR, errorType, tag, message,
+                                 applicationTag, info, cause );
+    }
+
+    /**
+     * Creates an RpcError with severity WARNING for reuse.
+     *
+     * @param errorType the conceptual layer at which the warning occurred.
+     * @param tag a short string that identifies the general type of warning condition. See
+     *        {@link RpcError#getTag} for a list of suggested values.
+     * @param message a string suitable for human display that describes the warning condition.
+     *
+     * @return an RpcError
+     */
+    public static RpcError newWarning( ErrorType errorType, String tag, String message ) {
+        return new RpcErrorImpl( ErrorSeverity.WARNING, errorType, tag, message, null, null, null );
+    }
+
+    /**
+     * Creates an RpcError with severity WARNING for reuse.
+     *
+     * @param errorType the conceptual layer at which the warning occurred.
+     * @param tag a short string that identifies the general type of warning condition. See
+     *        {@link RpcError#getTag} for a list of suggested values.
+     * @param message a string suitable for human display that describes the warning condition.
+     * * @param applicationTag a short string that identifies the specific type of warning condition.
+     * @param info a string containing additional information to provide extended
+     *        and/or implementation-specific debugging information.
+     * @param cause the exception that triggered the warning.
+     *
+     * @return an RpcError
+     */
+    public static RpcError newWarning(  ErrorType errorType, String tag, String message,
+            String applicationTag, String info, Throwable cause ) {
+        return new RpcErrorImpl( ErrorSeverity.WARNING, errorType, tag, message,
+                                 applicationTag, info, cause );
+    }
+
     /**
      * Sets the value of the result.
      *
@@ -171,12 +259,18 @@ public class RpcResultBuilder<T> {
             String tag, String message, String applicationTag, String info,
             Throwable cause ) {
 
+        addError( new RpcErrorImpl( severity, errorType,
+                                    tag != null ? tag : "operation-failed", message,
+                                    applicationTag, info, cause ) );
+    }
+
+    private void addError( RpcError error ) {
+
         if( errors == null ) {
-            errors = new ArrayList<>();
+            errors = new ImmutableList.Builder<RpcError>();
         }
 
-        errors.add( new RpcErrorImpl( severity, errorType, tag, message,
-                                      applicationTag, info, cause ) );
+        errors.add( error );
     }
 
     /**
@@ -217,7 +311,7 @@ public class RpcResultBuilder<T> {
      * @param message a string suitable for human display that describes the error condition.
      */
     public RpcResultBuilder<T> withError( ErrorType errorType, String message ) {
-        addError( ErrorSeverity.ERROR, errorType, "operation-failed", message, null, null, null );
+        addError( ErrorSeverity.ERROR, errorType, null, message, null, null, null );
         return this;
     }
 
@@ -234,6 +328,19 @@ public class RpcResultBuilder<T> {
         return this;
     }
 
+    /**
+     * Adds an error to the result. The general error tag defaults to "operation-failed".
+     *
+     * @param errorType the conceptual layer at which the error occurred.
+     * @param message a string suitable for human display that describes the error condition.
+     * @param cause the exception that triggered the error.
+     */
+    public RpcResultBuilder<T> withError( ErrorType errorType, String message,
+                                          Throwable cause ) {
+        addError( ErrorSeverity.ERROR, errorType, null, message, null, null, cause );
+        return this;
+    }
+
     /**
      * Adds an error to the result.
      *
@@ -252,9 +359,33 @@ public class RpcResultBuilder<T> {
         return this;
     }
 
+    /**
+     * Adds an RpcError.
+     *
+     * @param error the RpcError
+     */
+    public RpcResultBuilder<T> withRpcError( RpcError error ) {
+        addError( error );
+        return this;
+    }
+
+    /**
+     * Adds RpcErrors.
+     *
+     * @param errors the list of RpcErrors
+     */
+    public RpcResultBuilder<T> withRpcErrors( Collection<RpcError> errors ) {
+        if( errors != null ) {
+            for( RpcError error: errors ) {
+                addError( error );
+            }
+        }
+        return this;
+    }
+
     public RpcResult<T> build() {
 
         return new RpcResultImpl<T>( successful, result,
-                errors != null ? errors : Collections.<RpcError>emptyList() );
+                errors != null ? errors.build() : Collections.<RpcError>emptyList() );
     }
 }
index 143773986cbcc2309bfb82b46edda384a5e3d470..6eee59a9183021da2440c7dbde55ddf5696611e0 100644 (file)
@@ -38,10 +38,12 @@ public class RpcResultBuilderTest {
     @Test
     public void testFailed() {
         Throwable cause = new Throwable( "mock cause" );
+        Throwable cause2 = new Throwable( "mock cause2" );
         RpcResult<String> result = RpcResultBuilder.<String>failed()
                   .withError( ErrorType.PROTOCOL, "error message 1" )
                   .withError( ErrorType.APPLICATION, "lock_denied", "error message 2" )
                   .withError( ErrorType.RPC, "in-use", "error message 3", "my-app-tag", "my-info", cause )
+                  .withError( ErrorType.TRANSPORT, "error message 4", cause2 )
                   .build();
         verifyRpcResult( result, false, null );
         verifyRpcError( result, 0, ErrorSeverity.ERROR, ErrorType.PROTOCOL, "operation-failed",
@@ -50,7 +52,9 @@ public class RpcResultBuilderTest {
                         "error message 2", null, null, null );
         verifyRpcError( result, 2, ErrorSeverity.ERROR, ErrorType.RPC, "in-use",
                         "error message 3", "my-app-tag", "my-info", cause );
-        assertEquals( "getErrors size", 3, result.getErrors().size() );
+        verifyRpcError( result, 3, ErrorSeverity.ERROR, ErrorType.TRANSPORT, "operation-failed",
+                        "error message 4", null, null, cause2 );
+        assertEquals( "getErrors size", 4, result.getErrors().size() );
     }
 
     @Test
@@ -68,6 +72,41 @@ public class RpcResultBuilderTest {
         assertEquals( "getErrors size", 2, result.getErrors().size() );
     }
 
+    @Test
+    public void testFrom() {
+        Throwable cause = new Throwable( "mock cause" );
+        RpcResult<String> result = RpcResultBuilder.<String>success()
+                .withResult( "foo" )
+                .withWarning( ErrorType.RPC, "in-use", "message", "my-app-tag", "my-info", cause )
+                .build();
+
+        RpcResult<String> copy = RpcResultBuilder.<String>from( result )
+                .withError( ErrorType.PROTOCOL, "error message" )
+                .build();
+        verifyRpcResult( copy, true, "foo" );
+        verifyRpcError( copy, 0, ErrorSeverity.WARNING, ErrorType.RPC, "in-use",
+                        "message", "my-app-tag", "my-info", cause );
+        verifyRpcError( copy, 1, ErrorSeverity.ERROR, ErrorType.PROTOCOL, "operation-failed",
+                        "error message", null, null, null );
+    }
+
+    @Test
+    public void testWithRpcErrors() {
+        Throwable cause = new Throwable( "mock cause" );
+        RpcResult<String> result = RpcResultBuilder.<String>failed()
+                .withWarning( ErrorType.RPC, "in-use", "message", "my-app-tag", "my-info", cause )
+                .withError( ErrorType.PROTOCOL, "error message" )
+                .build();
+
+        RpcResult<String> result2 = RpcResultBuilder.<String>failed()
+                .withRpcErrors( result.getErrors() )
+                .build();
+        verifyRpcError( result2, 0, ErrorSeverity.WARNING, ErrorType.RPC, "in-use",
+                        "message", "my-app-tag", "my-info", cause );
+        verifyRpcError( result2, 1, ErrorSeverity.ERROR, ErrorType.PROTOCOL, "operation-failed",
+                        "error message", null, null, null );
+    }
+
     void verifyRpcError( RpcResult<?> result, int errorIndex, ErrorSeverity expSeverity,
             ErrorType expErrorType, String expTag, String expMessage, String expAppTag,
             String expInfo, Throwable expCause ) {
index 4e3416fd1fb22b5b83243cd1e922cdf5d6ee8d86..36d4bdd228f55a20ede67e22457918eccf653edd 100644 (file)
@@ -10,7 +10,6 @@ package org.opendaylight.yangtools.yang.data.api.schema;
 import org.opendaylight.yangtools.concepts.Identifiable;
 import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
-import org.opendaylight.yangtools.yang.data.api.Node;
 
 /**
  *
@@ -23,31 +22,26 @@ import org.opendaylight.yangtools.yang.data.api.Node;
  * @param <K> Local identifier of node
  * @param <V> Value of node
  */
-public interface NormalizedNode<K extends InstanceIdentifier.PathArgument,V> extends
-    Identifiable<K>, //
-    Node<V> {
-
+public interface NormalizedNode<K extends InstanceIdentifier.PathArgument, V> extends Identifiable<K> {
     /**
-     *
      * QName of the node as defined in YANG schema.
      *
+     * @return QName of this node, non-null.
      */
-    @Override
     QName getNodeType();
 
     /**
+     * Locally unique identifier of the node.
      *
-     * Locally unique identifier of nodes
-     *
+     * @return Node identifier, non-null.
      */
     @Override
     K getIdentifier();
 
     /**
+     * Value of node.
      *
-     * Value of node
-     *
+     * @return Value of the node, may be null.
      */
-    @Override
     V getValue();
 }
index 82928944ec2c14e2fd0de6e0ed96bad40d83fd04..223157a223eee681231840c8b0d436dbe2ca0f83 100644 (file)
@@ -31,7 +31,7 @@ final class RandomPrefix {
                 do {
                     final StringBuilder sb = new StringBuilder();
                     for (int i = 0; i < 4; i++) {
-                        sb.append('a' + random.nextInt(25));
+                        sb.append((char)('a' + random.nextInt(25)));
                     }
 
                     prefix = sb.toString();
@@ -43,4 +43,4 @@ final class RandomPrefix {
 
         return prefix + ':' + qname.getLocalName();
     }
-}
\ No newline at end of file
+}
index e011d3ec83bb13b85434c3c2261f061490fe7b57..4b65eae332be2c6465be66d81f5605058a53e54d 100644 (file)
@@ -9,16 +9,10 @@ package org.opendaylight.yangtools.yang.data.impl.codec.xml;
 
 import static com.google.common.base.Preconditions.checkState;
 
-import com.google.common.base.Function;
-import com.google.common.base.Objects;
-import com.google.common.base.Optional;
-import com.google.common.base.Preconditions;
-import com.google.common.base.Strings;
-import com.google.common.collect.ImmutableList;
-
 import java.net.URI;
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Map;
 import java.util.Map.Entry;
 import java.util.Set;
 
@@ -26,6 +20,10 @@ import javax.activation.UnsupportedDataTypeException;
 import javax.xml.parsers.DocumentBuilder;
 import javax.xml.parsers.DocumentBuilderFactory;
 import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.stream.XMLOutputFactory;
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.XMLStreamWriter;
+import javax.xml.transform.dom.DOMResult;
 
 import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.data.api.AttributesContainer;
@@ -34,6 +32,7 @@ import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
 import org.opendaylight.yangtools.yang.data.api.ModifyAction;
 import org.opendaylight.yangtools.yang.data.api.Node;
 import org.opendaylight.yangtools.yang.data.api.SimpleNode;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
 import org.opendaylight.yangtools.yang.data.impl.ImmutableCompositeNode;
 import org.opendaylight.yangtools.yang.data.impl.SimpleNodeTOImpl;
 import org.opendaylight.yangtools.yang.data.impl.codec.TypeDefinitionAwareCodec;
@@ -59,8 +58,14 @@ import org.w3c.dom.Document;
 import org.w3c.dom.Element;
 import org.w3c.dom.NodeList;
 
-public class XmlDocumentUtils {
+import com.google.common.base.Function;
+import com.google.common.base.Objects;
+import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
+import com.google.common.base.Strings;
+import com.google.common.collect.ImmutableList;
 
+public class XmlDocumentUtils {
     private static class ElementWithSchemaContext {
         Element element;
         SchemaContext schemaContext;
@@ -79,16 +84,16 @@ public class XmlDocumentUtils {
         }
     }
 
+    public static final QName OPERATION_ATTRIBUTE_QNAME = QName.create(URI.create("urn:ietf:params:xml:ns:netconf:base:1.0"), null, "operation");
+    private static final Logger logger = LoggerFactory.getLogger(XmlDocumentUtils.class);
+    private static final XMLOutputFactory FACTORY = XMLOutputFactory.newFactory();
     private static final XmlCodecProvider DEFAULT_XML_VALUE_CODEC_PROVIDER = new XmlCodecProvider() {
-
         @Override
         public TypeDefinitionAwareCodec<Object, ? extends TypeDefinition<?>> codecFor(final TypeDefinition<?> baseType) {
             return TypeDefinitionAwareCodec.from(baseType);
         }
     };
 
-    private static final Logger logger = LoggerFactory.getLogger(XmlDocumentUtils.class);
-
     /**
      * Converts Data DOM structure to XML Document for specified XML Codec Provider and corresponding
      * Data Node Container schema. The CompositeNode data parameter enters as root of Data DOM tree and will
@@ -106,14 +111,20 @@ public class XmlDocumentUtils {
         Preconditions.checkNotNull(data);
         Preconditions.checkNotNull(schema);
 
-        Document doc = getDocument();
+        if (!(schema instanceof ContainerSchemaNode || schema instanceof ListSchemaNode)) {
+            throw new UnsupportedDataTypeException("Schema can be ContainerSchemaNode or ListSchemaNode. Other types are not supported yet.");
+        }
 
-        if (schema instanceof ContainerSchemaNode || schema instanceof ListSchemaNode) {
-            doc.appendChild(createXmlRootElement(doc, data, (SchemaNode) schema, codecProvider));
-            return doc;
-        } else {
-            throw new UnsupportedDataTypeException(
-                    "Schema can be ContainerSchemaNode or ListSchemaNode. Other types are not supported yet.");
+        final DOMResult result = new DOMResult();
+        result.setNode(getDocument());
+        try {
+            final XMLStreamWriter writer = FACTORY.createXMLStreamWriter(result);
+            XmlStreamUtils.create(codecProvider).writeDocument(writer, data, (SchemaNode)schema);
+            writer.close();
+            return (Document)result.getNode();
+        } catch (XMLStreamException e) {
+            logger.error("Failed to serialize data {}", data, e);
+            return null;
         }
     }
 
@@ -139,75 +150,47 @@ public class XmlDocumentUtils {
      * @return new instance of XML Document
      * @throws UnsupportedDataTypeException
      */
-    public static Document toDocument(final CompositeNode data, final XmlCodecProvider codecProvider)
-            throws UnsupportedDataTypeException {
-        Preconditions.checkNotNull(data);
-
-        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
-        dbf.setNamespaceAware(true);
-        Document doc = null;
+    public static Document toDocument(final CompositeNode data, final XmlCodecProvider codecProvider) {
+        final DOMResult result = new DOMResult();
         try {
-            DocumentBuilder bob = dbf.newDocumentBuilder();
-            doc = bob.newDocument();
-        } catch (ParserConfigurationException e) {
+            final XMLStreamWriter writer = FACTORY.createXMLStreamWriter(result);
+            XmlStreamUtils.create(codecProvider).writeDocument(writer, data);
+            writer.close();
+            return (Document)result.getNode();
+        } catch (XMLStreamException e) {
+            logger.error("Failed to serialize data {}", data, e);
             return null;
         }
-
-        doc.appendChild(createXmlRootElement(doc, data, null, codecProvider));
-        return doc;
     }
 
-    private static Element createXmlRootElement(final Document doc, final Node<?> data, final SchemaNode schema,
-            final XmlCodecProvider codecProvider) throws UnsupportedDataTypeException {
-        Element itemEl = createElementFor(doc, data);
-        if (data instanceof SimpleNode<?>) {
-            if (schema instanceof LeafListSchemaNode) {
-                writeValueByType(itemEl, (SimpleNode<?>) data, ((LeafListSchemaNode) schema).getType(),
-                        (DataSchemaNode) schema, codecProvider);
-            } else if (schema instanceof LeafSchemaNode) {
-                writeValueByType(itemEl, (SimpleNode<?>) data, ((LeafSchemaNode) schema).getType(),
-                        (DataSchemaNode) schema, codecProvider);
-            } else {
-                Object value = data.getValue();
-                if (value != null) {
-                    itemEl.setTextContent(String.valueOf(value));
-                }
-            }
-        } else { // CompositeNode
-            for (Node<?> child : ((CompositeNode) data).getValue()) {
-                DataSchemaNode childSchema = null;
-                if (schema instanceof DataNodeContainer) {
-                    childSchema = findFirstSchema(child.getNodeType(), ((DataNodeContainer) schema).getChildNodes()).orNull();
-                    if (logger.isDebugEnabled()) {
-                        if (childSchema == null) {
-                            logger.debug("Probably the data node \""
-                                    + ((child == null) ? "" : child.getNodeType().getLocalName())
-                                    + "\" is not conform to schema");
-                        }
-                    }
+    private static final Element createElementFor(final Document doc, final QName qname, final Object obj) {
+        final Element ret;
+        if (qname.getNamespace() != null) {
+            ret = doc.createElementNS(qname.getNamespace().toString(), qname.getLocalName());
+        } else {
+            ret = doc.createElementNS(null, qname.getLocalName());
+        }
+
+        if (obj instanceof AttributesContainer) {
+            final Map<QName, String> attrs = ((AttributesContainer)obj).getAttributes();
+
+            if (attrs != null) {
+                for (Entry<QName, String> attribute : attrs.entrySet()) {
+                    ret.setAttributeNS(attribute.getKey().getNamespace().toString(), attribute.getKey().getLocalName(),
+                            attribute.getValue());
                 }
-                itemEl.appendChild(createXmlRootElement(doc, child, childSchema, codecProvider));
             }
         }
-        return itemEl;
+
+        return ret;
     }
 
     public static Element createElementFor(final Document doc, final Node<?> data) {
-        QName dataType = data.getNodeType();
-        Element ret;
-        if (dataType.getNamespace() != null) {
-            ret = doc.createElementNS(dataType.getNamespace().toString(), dataType.getLocalName());
-        } else {
-            ret = doc.createElementNS(null, dataType.getLocalName());
-        }
-        if (data instanceof AttributesContainer && ((AttributesContainer) data).getAttributes() != null) {
-            for (Entry<QName, String> attribute : ((AttributesContainer) data).getAttributes().entrySet()) {
-                ret.setAttributeNS(attribute.getKey().getNamespace().toString(), attribute.getKey().getLocalName(),
-                        attribute.getValue());
-            }
+        return createElementFor(doc, data.getNodeType(), data);
+    }
 
-        }
-        return ret;
+    public static Element createElementFor(final Document doc, final NormalizedNode<?, ?> data) {
+        return createElementFor(doc, data.getNodeType(), data);
     }
 
     public static void writeValueByType(final Element element, final SimpleNode<?> node, final TypeDefinition<?> type,
@@ -362,13 +345,11 @@ public class XmlDocumentUtils {
         return ImmutableCompositeNode.create(qName, values, modifyAction.orNull());
     }
 
-    public static final QName OPERATION_ATTRIBUTE_QNAME = QName.create(URI.create("urn:ietf:params:xml:ns:netconf:base:1.0"), null, "operation");
-
     public static Optional<ModifyAction> getModifyOperationFromAttributes(final Element xmlElement) {
         Attr attributeNodeNS = xmlElement.getAttributeNodeNS(OPERATION_ATTRIBUTE_QNAME.getNamespace().toString(), OPERATION_ATTRIBUTE_QNAME.getLocalName());
         if(attributeNodeNS == null) {
-                       return Optional.absent();
-               }
+            return Optional.absent();
+        }
 
         ModifyAction action = ModifyAction.fromXmlValue(attributeNodeNS.getValue());
         Preconditions.checkArgument(action.isOnElementPermitted(), "Unexpected operation %s on %s", action, xmlElement);
index 64913914de515ad53f3d347c93ffc9b5def38149..1d319a5acec49db92d0fb909e266ebc85b313508 100644 (file)
@@ -1,10 +1,13 @@
 package org.opendaylight.yangtools.yang.data.impl.codec.xml;
 
+import com.google.common.annotations.Beta;
 import com.google.common.base.Preconditions;
 
 import java.net.URI;
 import java.util.Map.Entry;
 
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
 import javax.xml.stream.XMLStreamException;
 import javax.xml.stream.XMLStreamWriter;
 
@@ -27,24 +30,61 @@ import org.opendaylight.yangtools.yang.model.api.type.InstanceIdentifierTypeDefi
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+/**
+ * Utility class for bridging JAXP Stream and YANG Data APIs. Note that the definition of this class
+ * by no means final and subject to change as more functionality is centralized here.
+ */
+@Beta
 public class XmlStreamUtils {
     private static final Logger LOG = LoggerFactory.getLogger(XmlStreamUtils.class);
+    private final XmlCodecProvider codecProvider;
 
-    public static void writeDataDocument(final XMLStreamWriter writer, final CompositeNode data, final SchemaNode schema, final XmlCodecProvider codecProvider) throws XMLStreamException {
-        //        final Boolean repairing = (Boolean) writer.getProperty(XMLOutputFactory.IS_REPAIRING_NAMESPACES);
-        //        Preconditions.checkArgument(repairing == true, "XML Stream Writer has to be repairing namespaces");
+    protected XmlStreamUtils(final XmlCodecProvider codecProvider) {
+        this.codecProvider = Preconditions.checkNotNull(codecProvider);
+    }
 
-        writer.writeStartDocument();
-        writeData(writer, data, schema, codecProvider);
-        writer.writeEndDocument();
-        writer.flush();
+    /**
+     * Create a new instance encapsulating a particular codec provider.
+     *
+     * @param codecProvider XML codec provider
+     * @return A new instance
+     */
+    public static XmlStreamUtils create(final XmlCodecProvider codecProvider) {
+        return new XmlStreamUtils(codecProvider);
     }
 
-    public static void writeDataDocument(final XMLStreamWriter writer, final CompositeNode data, final XmlCodecProvider codecProvider) throws XMLStreamException {
-        writeDataDocument(writer, data, null, codecProvider);
+    /**
+     * Check if a particular data element can be emitted as an empty element, bypassing value encoding. This
+     * functionality is optional, as valid XML stream is produced even if start/end element is produced unconditionally.
+     *
+     * @param data Data node
+     * @return True if the data node will result in empty element body.
+     */
+    public static boolean isEmptyElement(final Node<?> data) {
+        if (data == null) {
+            return true;
+        }
+
+        if (data instanceof CompositeNode) {
+            return ((CompositeNode) data).getValue().isEmpty();
+        }
+        if (data instanceof SimpleNode) {
+            return data.getValue() == null;
+        }
+
+        // Safe default
+        return false;
     }
 
-    public static void write(final XMLStreamWriter writer, final InstanceIdentifier id) throws XMLStreamException {
+    /**
+     * Write an InstanceIdentifier into the output stream. Calling corresponding {@link XMLStreamWriter#writeStartElement(String)}
+     * and {@link XMLStreamWriter#writeEndElement()} is the responsibility of the caller.
+     *
+     * @param writer XML Stream writer
+     * @param id InstanceIdentifier
+     * @throws XMLStreamException
+     */
+    public static void write(final @Nonnull XMLStreamWriter writer, final @Nonnull InstanceIdentifier id) throws XMLStreamException {
         Preconditions.checkNotNull(writer, "Writer may not be null");
         Preconditions.checkNotNull(id, "Variable should contain instance of instance identifier and can't be null");
 
@@ -57,14 +97,54 @@ public class XmlStreamUtils {
         writer.writeCharacters(str);
     }
 
-    public static void writeData(final XMLStreamWriter writer, final Node<?> data, final SchemaNode schema, final XmlCodecProvider codecProvider) throws XMLStreamException {
+    /**
+     * Write a full XML document corresponding to a CompositeNode into an XML stream writer.
+     *
+     * @param writer XML Stream writer
+     * @param data data node
+     * @param schema corresponding schema node, may be null
+     * @throws XMLStreamException if an encoding problem occurs
+     */
+    public void writeDocument(final @Nonnull XMLStreamWriter writer, final @Nonnull CompositeNode data, final @Nullable SchemaNode schema) throws XMLStreamException {
+        // final Boolean repairing = (Boolean) writer.getProperty(XMLOutputFactory.IS_REPAIRING_NAMESPACES);
+        // Preconditions.checkArgument(repairing == true, "XML Stream Writer has to be repairing namespaces");
+
+        writer.writeStartDocument();
+        writeElement(writer, data, schema);
+        writer.writeEndDocument();
+        writer.flush();
+    }
+
+    /**
+     * Short-hand for {@link #writeDataDocument(XMLStreamWriter, CompositeNode, SchemaNode, XmlCodecProvider)} with
+     * null SchemaNode.
+     *
+     * @param writer XML Stream writer
+     * @param data data node
+     * @param schema corresponding schema node, may be null
+     * @throws XMLStreamException if an encoding problem occurs
+     */
+    public void writeDocument(final XMLStreamWriter writer, final CompositeNode data) throws XMLStreamException {
+        writeDocument(writer, data, null);
+    }
+
+    /**
+     * Write an element into a XML stream writer. This includes the element start/end tags and
+     * the value of the element.
+     *
+     * @param writer XML Stream writer
+     * @param data data node
+     * @param schema Schema node
+     * @throws XMLStreamException if an encoding problem occurs
+     */
+    public void writeElement(final XMLStreamWriter writer, final @Nonnull Node<?> data, final SchemaNode schema) throws XMLStreamException {
         final QName qname = data.getNodeType();
         final String pfx = qname.getPrefix() != null ? qname.getPrefix() : "";
-        final String ns;
-        if (qname.getNamespace() != null) {
-            ns = qname.getNamespace().toString();
-        } else {
-            ns = "";
+        final String ns = qname.getNamespace() != null ? qname.getNamespace().toString() : "";
+
+        if (isEmptyElement(data)) {
+            writer.writeEmptyElement(pfx, qname.getLocalName(), ns);
+            return;
         }
 
         writer.writeStartElement(pfx, qname.getLocalName(), ns);
@@ -77,9 +157,9 @@ public class XmlStreamUtils {
         if (data instanceof SimpleNode<?>) {
             // Simple node
             if (schema instanceof LeafListSchemaNode) {
-                writeValue(writer, ((LeafListSchemaNode) schema).getType(), codecProvider, data.getValue());
+                writeValue(writer, ((LeafListSchemaNode) schema).getType(), data.getValue());
             } else if (schema instanceof LeafSchemaNode) {
-                writeValue(writer, ((LeafSchemaNode) schema).getType(), codecProvider, data.getValue());
+                writeValue(writer, ((LeafSchemaNode) schema).getType(), data.getValue());
             } else {
                 Object value = data.getValue();
                 if (value != null) {
@@ -99,62 +179,75 @@ public class XmlStreamUtils {
                     }
                 }
 
-                writeData(writer, child, childSchema, codecProvider);
+                writeElement(writer, child, childSchema);
             }
         }
 
         writer.writeEndElement();
     }
 
-    public static void writeValue(final XMLStreamWriter writer, final TypeDefinition<?> type, final XmlCodecProvider codecProvider, final Object nodeValue) throws XMLStreamException {
-        TypeDefinition<?> baseType = XmlUtils.resolveBaseTypeFrom(type);
+    /**
+     * Write a value into a XML stream writer. This method assumes the start and end of element is
+     * emitted by the caller.
+     *
+     * @param writer XML Stream writer
+     * @param data data node
+     * @param schema Schema node
+     * @throws XMLStreamException if an encoding problem occurs
+     */
+    public void writeValue(final @Nonnull XMLStreamWriter writer, final @Nonnull TypeDefinition<?> type, final Object value) throws XMLStreamException {
+        if (value == null) {
+            LOG.debug("Value of {}:{} is null, not encoding it", type.getQName().getNamespace(), type.getQName().getLocalName());
+            return;
+        }
+
+        final TypeDefinition<?> baseType = XmlUtils.resolveBaseTypeFrom(type);
         if (baseType instanceof IdentityrefTypeDefinition) {
-            if (nodeValue instanceof QName) {
-                QName value = (QName) nodeValue;
-                String prefix = "x";
-                if (value.getPrefix() != null && !value.getPrefix().isEmpty()) {
-                    prefix = value.getPrefix();
+            write(writer, (IdentityrefTypeDefinition) baseType, value);
+        } else if (baseType instanceof InstanceIdentifierTypeDefinition) {
+            write(writer, (InstanceIdentifierTypeDefinition) baseType, value);
+        } else {
+            final TypeDefinitionAwareCodec<Object, ?> codec = codecProvider.codecFor(baseType);
+            String text;
+            if (codec != null) {
+                try {
+                    text = codec.serialize(value);
+                } catch (ClassCastException e) {
+                    LOG.error("Provided node value {} did not have type {} required by mapping. Using stream instead.", value, baseType, e);
+                    text = String.valueOf(value);
                 }
-
-                writer.writeNamespace(prefix, value.getNamespace().toString());
-                writer.writeCharacters(prefix + ':' + value.getLocalName());
             } else {
-                Object value = nodeValue;
-                LOG.debug("Value of {}:{} is not instance of QName but is {}", baseType.getQName().getNamespace(),
-                        baseType.getQName().getLocalName(), value != null ? value.getClass() : "null");
-                if (value != null) {
-                    writer.writeCharacters(String.valueOf(value));
-                }
+                LOG.error("Failed to find codec for {}, falling back to using stream", baseType);
+                text = String.valueOf(value);
             }
-        } else if (baseType instanceof InstanceIdentifierTypeDefinition) {
-            if (nodeValue instanceof InstanceIdentifier) {
-                write(writer, (InstanceIdentifier)nodeValue);
+            writer.writeCharacters(text);
+        }
+    }
+
+    private static void write(final @Nonnull XMLStreamWriter writer, final @Nonnull IdentityrefTypeDefinition type, final @Nonnull Object value) throws XMLStreamException {
+        if (value instanceof QName) {
+            final QName qname = (QName) value;
+            final String prefix;
+            if (qname.getPrefix() != null && !qname.getPrefix().isEmpty()) {
+                prefix = qname.getPrefix();
             } else {
-                Object value = nodeValue;
-                LOG.debug("Value of {}:{} is not instance of InstanceIdentifier but is {}", baseType.getQName()
-                        .getNamespace(), //
-                        baseType.getQName().getLocalName(), value != null ? value.getClass() : "null");
-                if (value != null) {
-                    writer.writeCharacters(String.valueOf(value));
-                }
+                prefix = "x";
             }
+
+            writer.writeNamespace(prefix, qname.getNamespace().toString());
+            writer.writeCharacters(prefix + ':' + qname.getLocalName());
         } else {
-            if (nodeValue != null) {
-                final TypeDefinitionAwareCodec<Object, ?> codec = codecProvider.codecFor(baseType);
-                String text;
-                if (codec != null) {
-                    try {
-                        text = codec.serialize(nodeValue);
-                    } catch (ClassCastException e) {
-                        LOG.error("Provided node value {} did not have type {} required by mapping. Using stream instead.", nodeValue, baseType, e);
-                        text = String.valueOf(nodeValue);
-                    }
-                } else {
-                    LOG.error("Failed to find codec for {}, falling back to using stream", baseType);
-                    text = String.valueOf(nodeValue);
-                }
-                writer.writeCharacters(text);
-            }
+            LOG.debug("Value of {}:{} is not a QName but {}", type.getQName().getNamespace(), type.getQName().getLocalName(), value.getClass());
+            writer.writeCharacters(String.valueOf(value));
+        }
+    }
+
+    private static void write(final @Nonnull XMLStreamWriter writer, final @Nonnull InstanceIdentifierTypeDefinition type, final @Nonnull Object value) throws XMLStreamException {
+        if (value instanceof InstanceIdentifier) {
+            write(writer, (InstanceIdentifier)value);
+        } else {
+            LOG.debug("Value of {}:{} is not an InstanceIdentifier but {}", type.getQName().getNamespace(), type.getQName().getLocalName(), value.getClass());
+            writer.writeCharacters(String.valueOf(value));
         }
     }
 }
index dbdb6ff1b72909c4485bebdc11d1079f2d390ac7..052c250099ebae4a69857d70eb6c174aaf6ee472 100644 (file)
@@ -9,6 +9,8 @@ package org.opendaylight.yangtools.yang.data.impl.codec.xml;
 
 import java.util.Map;
 
+import javax.annotation.Nonnull;
+
 import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
 import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeIdentifierWithPredicates;
@@ -26,7 +28,7 @@ final class XmlUtils {
 
     }
 
-    public static TypeDefinition<?> resolveBaseTypeFrom(final TypeDefinition<?> type) {
+    public static TypeDefinition<?> resolveBaseTypeFrom(final @Nonnull TypeDefinition<?> type) {
         TypeDefinition<?> superType = type;
         while (superType.getBaseType() != null) {
             superType = superType.getBaseType();
index 14b0f419297352315c71d5b2517395fee7e7cfb8..d5a6a2b501bab86229f012f66824ebe543ef5983 100644 (file)
@@ -7,19 +7,16 @@
  */
 package org.opendaylight.yangtools.yang.data.impl.schema.nodes;
 
-import org.opendaylight.yangtools.concepts.Immutable;
-import org.opendaylight.yangtools.yang.common.QName;
-import org.opendaylight.yangtools.yang.data.api.CompositeNode;
-import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
-import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
-
 import com.google.common.base.Objects;
 import com.google.common.base.Objects.ToStringHelper;
 import com.google.common.base.Preconditions;
 
-public abstract class AbstractImmutableNormalizedNode<K extends InstanceIdentifier.PathArgument,V>
-        implements NormalizedNode<K, V>, Immutable {
+import org.opendaylight.yangtools.concepts.Immutable;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
 
+public abstract class AbstractImmutableNormalizedNode<K extends InstanceIdentifier.PathArgument,V> implements NormalizedNode<K, V>, Immutable {
     private final K nodeIdentifier;
 
     protected AbstractImmutableNormalizedNode(final K nodeIdentifier) {
@@ -36,21 +33,6 @@ public abstract class AbstractImmutableNormalizedNode<K extends InstanceIdentifi
         return nodeIdentifier;
     }
 
-    @Override
-    public final CompositeNode getParent() {
-        throw new UnsupportedOperationException("Deprecated");
-    }
-
-    @Override
-    public final QName getKey() {
-        return getNodeType();
-    }
-
-    @Override
-    public final V setValue(final V value) {
-        throw new UnsupportedOperationException("Immutable");
-    }
-
     @Override
     public final String toString() {
         return addToStringAttributes(Objects.toStringHelper(this)).toString();
index 7013e55ad1fccdafcb4eb0c9e1550bfa9a4352df..668f7512c33f05e5a60749cbc540470b33465c0d 100644 (file)
@@ -50,7 +50,8 @@ final class InMemoryDataTree implements DataTree {
     public synchronized void setSchemaContext(final SchemaContext newSchemaContext) {
         Preconditions.checkNotNull(newSchemaContext);
 
-        LOG.info("Attempting to install schema context {}", newSchemaContext);
+        LOG.info("Attempting to install schema contexts");
+        LOG.debug("Following schema contexts will be attempted {}",newSchemaContext);
 
         /*
          * FIXME: we should walk the schema contexts, both current and new and see
diff --git a/yang/yang-data-impl/src/test/java/org/opendaylight/yangtools/yang/data/impl/codec/xml/RandomPrefixTest.java b/yang/yang-data-impl/src/test/java/org/opendaylight/yangtools/yang/data/impl/codec/xml/RandomPrefixTest.java
new file mode 100644 (file)
index 0000000..eb32e4d
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.data.impl.codec.xml;
+
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.impl.codec.xml.RandomPrefix;
+
+/**
+ * @author tkubas
+ */
+public class RandomPrefixTest {
+    private RandomPrefix randomPrefix;
+
+    /**
+     * setup {@link #randomPrefix} instance
+     */
+    @Before
+    public void setUp() {
+        randomPrefix = new RandomPrefix();
+    }
+    /**
+     * Test method for {@link org.opendaylight.yangtools.yang.data.impl.codec.xml.RandomPrefix#encodeQName(QName)}.
+     */
+    @Test
+    public void testEncodeQName() {
+        QName node = QName.create("","2013-06-07","node");
+        String encodedQName = randomPrefix.encodeQName(node);
+        Assert.assertNotNull(encodedQName);
+        Assert.assertTrue("prefix is expected to contain 4 small letters as prefix but result is: "+encodedQName,
+                encodedQName.matches("[a-z]{4}:node"));
+    }
+
+}
diff --git a/yang/yang-data-impl/src/test/java/org/opendaylight/yangtools/yang/data/impl/schema/tree/TreeNodeUtilsTest.java b/yang/yang-data-impl/src/test/java/org/opendaylight/yangtools/yang/data/impl/schema/tree/TreeNodeUtilsTest.java
new file mode 100644 (file)
index 0000000..9098e32
--- /dev/null
@@ -0,0 +1,187 @@
+package org.opendaylight.yangtools.yang.data.impl.schema.tree;
+
+import com.google.common.base.Optional;
+import junit.framework.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
+import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.spi.TreeNode;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.spi.TreeNodeFactory;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.spi.Version;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableContainerNodeBuilder;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.Map;
+
+import static org.junit.Assert.*;
+import static org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes.*;
+
+
+public class TreeNodeUtilsTest {
+    private static final Logger LOG = LoggerFactory.getLogger(TreeNodeUtilsTest.class);
+
+    private static final Short ONE_ID = 1;
+    private static final Short TWO_ID = 2;
+    private static final String TWO_ONE_NAME = "one";
+    private static final String TWO_TWO_NAME = "two";
+
+    private static final InstanceIdentifier OUTER_LIST_1_PATH = InstanceIdentifier.builder(TestModel.OUTER_LIST_PATH)
+            .nodeWithKey(TestModel.OUTER_LIST_QNAME, TestModel.ID_QNAME, ONE_ID) //
+            .build();
+
+    private static final InstanceIdentifier OUTER_LIST_2_PATH = InstanceIdentifier.builder(TestModel.OUTER_LIST_PATH)
+            .nodeWithKey(TestModel.OUTER_LIST_QNAME, TestModel.ID_QNAME, TWO_ID) //
+            .build();
+
+    private static final InstanceIdentifier TWO_TWO_PATH = InstanceIdentifier.builder(OUTER_LIST_2_PATH)
+            .node(TestModel.INNER_LIST_QNAME) //
+            .nodeWithKey(TestModel.INNER_LIST_QNAME, TestModel.NAME_QNAME, TWO_TWO_NAME) //
+            .build();
+
+    private static final MapEntryNode BAR_NODE = mapEntryBuilder(TestModel.OUTER_LIST_QNAME, TestModel.ID_QNAME, TWO_ID) //
+            .withChild(mapNodeBuilder(TestModel.INNER_LIST_QNAME) //
+                    .withChild(mapEntry(TestModel.INNER_LIST_QNAME, TestModel.NAME_QNAME, TWO_ONE_NAME)) //
+                    .withChild(mapEntry(TestModel.INNER_LIST_QNAME, TestModel.NAME_QNAME, TWO_TWO_NAME)) //
+                    .build()) //
+            .build();
+
+    private SchemaContext schemaContext;
+    private RootModificationApplyOperation rootOper;
+
+    @Before
+    public void prepare() {
+        schemaContext = TestModel.createTestContext();
+        assertNotNull("Schema context must not be null.", schemaContext);
+        rootOper = RootModificationApplyOperation.from(SchemaAwareApplyOperation.from(schemaContext));
+    }
+
+    public NormalizedNode<?, ?> createDocumentOne() {
+        return ImmutableContainerNodeBuilder
+                .create()
+                .withNodeIdentifier(new InstanceIdentifier.NodeIdentifier(schemaContext.getQName()))
+                .withChild(createTestContainer()).build();
+
+    }
+
+    private ContainerNode createTestContainer() {
+        return ImmutableContainerNodeBuilder
+                .create()
+                .withNodeIdentifier(new InstanceIdentifier.NodeIdentifier(TestModel.TEST_QNAME))
+                .withChild(
+                        mapNodeBuilder(TestModel.OUTER_LIST_QNAME)
+                                .withChild(mapEntry(TestModel.OUTER_LIST_QNAME, TestModel.ID_QNAME, ONE_ID))
+                                .withChild(BAR_NODE).build()).build();
+    }
+
+    private static <T> T assertPresentAndType(final Optional<?> potential, final Class<T> type) {
+        assertNotNull(potential);
+        assertTrue(potential.isPresent());
+        assertTrue(type.isInstance(potential.get()));
+        return type.cast(potential.get());
+    }
+
+    @Test
+    public void findNodeTestNodeFound() {
+        InMemoryDataTreeSnapshot inMemoryDataTreeSnapshot = new InMemoryDataTreeSnapshot(schemaContext,
+                TreeNodeFactory.createTreeNode(createDocumentOne(), Version.initial()), rootOper);
+        TreeNode rootNode = inMemoryDataTreeSnapshot.getRootNode();
+        Optional<TreeNode> node = TreeNodeUtils.findNode(rootNode, OUTER_LIST_1_PATH);
+        assertPresentAndType(node, TreeNode.class);
+    }
+
+    @Test
+    public void findNodeTestNodeNotFound() {
+        InMemoryDataTreeSnapshot inMemoryDataTreeSnapshot = new InMemoryDataTreeSnapshot(schemaContext,
+                TreeNodeFactory.createTreeNode(createDocumentOne(), Version.initial()), rootOper);
+        TreeNode rootNode = inMemoryDataTreeSnapshot.getRootNode();
+        final InstanceIdentifier outerList1InvalidPath = InstanceIdentifier.builder(TestModel.OUTER_LIST_PATH)
+                .nodeWithKey(TestModel.OUTER_LIST_QNAME, TestModel.ID_QNAME, 3) //
+                .build();
+        Optional<TreeNode> node = TreeNodeUtils.findNode(rootNode, outerList1InvalidPath);
+        Assert.assertFalse(node.isPresent());
+    }
+
+    @Test
+    public void findNodeCheckedTestNodeFound() {
+        InMemoryDataTreeSnapshot inMemoryDataTreeSnapshot = new InMemoryDataTreeSnapshot(schemaContext,
+                TreeNodeFactory.createTreeNode(createDocumentOne(), Version.initial()), rootOper);
+        TreeNode rootNode = inMemoryDataTreeSnapshot.getRootNode();
+        TreeNode foundNode = null;
+        try {
+            foundNode = TreeNodeUtils.findNodeChecked(rootNode, OUTER_LIST_1_PATH);
+        } catch (IllegalArgumentException e) {
+            fail("Illegal argument exception was thrown and should not have been" + e.getMessage());
+        }
+        Assert.assertNotNull(foundNode);
+    }
+
+    @Test
+    public void findNodeCheckedTestNodeNotFound() {
+        InMemoryDataTreeSnapshot inMemoryDataTreeSnapshot = new InMemoryDataTreeSnapshot(schemaContext,
+                TreeNodeFactory.createTreeNode(createDocumentOne(), Version.initial()), rootOper);
+        TreeNode rootNode = inMemoryDataTreeSnapshot.getRootNode();
+        final InstanceIdentifier outerList1InvalidPath = InstanceIdentifier.builder(TestModel.OUTER_LIST_PATH)
+                .nodeWithKey(TestModel.OUTER_LIST_QNAME, TestModel.ID_QNAME, 3) //
+                .build();
+        try {
+            TreeNodeUtils.findNodeChecked(rootNode, outerList1InvalidPath);
+            fail("Illegal argument exception should have been thrown");
+        } catch (IllegalArgumentException e) {
+            LOG.debug("Illegal argument exception was thrown as expected: '{}' - '{}'", e.getClass(), e.getMessage());
+        }
+    }
+
+    @Test
+    public void findClosestOrFirstMatchTestNodeExists() {
+        InMemoryDataTreeSnapshot inMemoryDataTreeSnapshot = new InMemoryDataTreeSnapshot(schemaContext,
+                TreeNodeFactory.createTreeNode(createDocumentOne(), Version.initial()), rootOper);
+        TreeNode rootNode = inMemoryDataTreeSnapshot.getRootNode();
+        Optional<TreeNode> expectedNode = TreeNodeUtils.findNode(rootNode, TWO_TWO_PATH);
+        assertPresentAndType(expectedNode, TreeNode.class);
+        Map.Entry<InstanceIdentifier, TreeNode> actualNode = TreeNodeUtils.findClosest(rootNode, TWO_TWO_PATH);
+        Assert.assertEquals("Expected node and actual node are not the same", expectedNode.get(), actualNode.getValue());
+    }
+
+    @Test
+    public void findClosestOrFirstMatchTestNodeDoesNotExist() {
+        InMemoryDataTreeSnapshot inMemoryDataTreeSnapshot = new InMemoryDataTreeSnapshot(schemaContext,
+                TreeNodeFactory.createTreeNode(createDocumentOne(), Version.initial()), rootOper);
+        TreeNode rootNode = inMemoryDataTreeSnapshot.getRootNode();
+        final InstanceIdentifier outerListInnerListPath = InstanceIdentifier.builder(OUTER_LIST_2_PATH)
+                .node(TestModel.INNER_LIST_QNAME)
+                .build();
+        final InstanceIdentifier twoTwoInvalidPath = InstanceIdentifier.builder(OUTER_LIST_2_PATH)
+                .node(TestModel.INNER_LIST_QNAME) //
+                .nodeWithKey(TestModel.INNER_LIST_QNAME, TestModel.NAME_QNAME, "three") //
+                .build();
+        Optional<TreeNode> expectedNode = TreeNodeUtils.findNode(rootNode, outerListInnerListPath);
+        assertPresentAndType(expectedNode, TreeNode.class);
+        Map.Entry<InstanceIdentifier, TreeNode> actualNode = TreeNodeUtils.findClosest(rootNode, twoTwoInvalidPath);
+        Assert.assertEquals("Expected node and actual node are not the same", expectedNode.get(), actualNode.getValue());
+    }
+
+    @Test
+    public void getChildTestChildFound() {
+        InMemoryDataTreeSnapshot inMemoryDataTreeSnapshot = new InMemoryDataTreeSnapshot(schemaContext,
+                TreeNodeFactory.createTreeNode(createDocumentOne(), Version.initial()), rootOper);
+        TreeNode rootNode = inMemoryDataTreeSnapshot.getRootNode();
+        Optional<TreeNode> node = TreeNodeUtils.getChild(Optional.fromNullable(rootNode),
+                TestModel.TEST_PATH.getLastPathArgument());
+        assertPresentAndType(node, TreeNode.class);
+    }
+
+    @Test
+    public void getChildTestChildNotFound() {
+        InMemoryDataTreeSnapshot inMemoryDataTreeSnapshot = new InMemoryDataTreeSnapshot(schemaContext,
+                TreeNodeFactory.createTreeNode(createDocumentOne(), Version.initial()), rootOper);
+        TreeNode rootNode = inMemoryDataTreeSnapshot.getRootNode();
+        Optional<TreeNode> node = TreeNodeUtils.getChild(Optional.fromNullable(rootNode),
+                TestModel.OUTER_LIST_PATH.getLastPathArgument());
+        Assert.assertFalse(node.isPresent());
+    }
+}
index d1e1f7c8fbd2f4a7285588644dd02d5b2185276a..bfbe329c7d40236e177ffad6bcd22d7c6ec53ca2 100644 (file)
@@ -7,6 +7,8 @@
  */
 package org.opendaylight.yangtools.yang.data.operations;
 
+import com.google.common.base.Optional;
+
 import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.data.api.Node;
 import org.opendaylight.yangtools.yang.data.api.schema.ChoiceNode;
@@ -16,8 +18,6 @@ import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
 import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
 
-import com.google.common.base.Optional;
-
 public class DataModificationException extends Exception {
     // TODO replace QName as identifier for node with schema or NodeIdentifier,
     // Augmentation does not have a QName
@@ -45,6 +45,10 @@ public class DataModificationException extends Exception {
             super(String.format("Data missing for node: %s, %s", nodeType, modificationNode), nodeType);
         }
 
+        public DataMissingException(final QName nodeType, final NormalizedNode<?, ?> modificationNode) {
+            super(String.format("Data missing for node: %s, %s", nodeType, modificationNode), nodeType);
+        }
+
         static void check(final QName nodeQName, final Optional<? extends NormalizedNode<?, ?>> actualNode) throws DataMissingException {
             if (!actualNode.isPresent()) {
                 throw new DataMissingException(nodeQName);
index 6cfa27e6d3096df806fbf056f1529cac63d28993..06fbdb629ab41ad9cb5eb5742016de88636de582 100644 (file)
@@ -7,6 +7,8 @@
  */
 package org.opendaylight.yangtools.yang.model.util;
 
+import com.google.common.base.Optional;
+
 import java.util.Collections;
 import java.util.List;
 
@@ -17,8 +19,6 @@ import org.opendaylight.yangtools.yang.model.api.UnknownSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.type.IntegerTypeDefinition;
 import org.opendaylight.yangtools.yang.model.api.type.RangeConstraint;
 
-import com.google.common.base.Optional;
-
 /**
  * The Abstract Integer class defines implementation of IntegerTypeDefinition
  * interface which represents SIGNED Integer values defined in Yang language. <br>
@@ -49,13 +49,13 @@ abstract class AbstractSignedInteger implements IntegerTypeDefinition {
      * @param name Name of type
      * @param description Description of type
      * @param minRange Minimal range
-     * @param maxRange Maxium range
+     * @param maxRange Maximum range
      * @param units Units
      */
     protected AbstractSignedInteger(final QName name, final String description, final Number minRange,
             final Number maxRange, final String units) {
         this.name = name;
-        this.path = SchemaPath.create(Collections.singletonList(name), true);
+        this.path = SchemaPath.create(true, name);
         this.description = description;
         this.units = units;
         final String rangeDescription = "Integer values between " + minRange + " and " + maxRange + ", inclusively.";
index b33392a7a0fcf1632694da9dee3510c7c4310d90..d5c904fd72fe854c4a2d7f99287b14077e3472aa 100644 (file)
@@ -7,6 +7,8 @@
  */
 package org.opendaylight.yangtools.yang.model.util;
 
+import com.google.common.base.Optional;
+
 import java.util.Collections;
 import java.util.List;
 
@@ -17,8 +19,6 @@ import org.opendaylight.yangtools.yang.model.api.UnknownSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.type.RangeConstraint;
 import org.opendaylight.yangtools.yang.model.api.type.UnsignedIntegerTypeDefinition;
 
-import com.google.common.base.Optional;
-
 /**
  * The Abstract Integer class defines implementation of IntegerTypeDefinition
  * interface which represents UNSIGNED Integer values defined in Yang language. <br>
@@ -54,7 +54,7 @@ abstract class AbstractUnsignedInteger implements UnsignedIntegerTypeDefinition
      */
     public AbstractUnsignedInteger(final QName name, final String description, final Number maxRange, final String units) {
         this.name = name;
-        this.path = SchemaPath.create(Collections.singletonList(name), true);
+        this.path = SchemaPath.create(true, name);
         this.description = description;
         this.units = units;
         final String rangeDescription = "Integer values between " + MIN_VALUE + " and " + maxRange + ", inclusively.";
index 53dc55b58555f473eb4c838a39336dfd56a82ec5..002746fa571d8b9616e4ca78ddfd406bcfd005ef 100644 (file)
@@ -7,21 +7,21 @@
  */
 package org.opendaylight.yangtools.yang.model.util;
 
+import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableSet;
+
 import java.net.URI;
 import java.util.ArrayList;
-import java.util.Collections;
 import java.util.Date;
 import java.util.List;
 import java.util.Set;
 
 import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.common.QNameModule;
 import org.opendaylight.yangtools.yang.model.api.SchemaPath;
 import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
 
-import com.google.common.base.Optional;
-import com.google.common.base.Preconditions;
-import com.google.common.collect.ImmutableSet;
-
 /**
  * Utility methods and constants to work with built-in YANG types
  *
@@ -33,6 +33,7 @@ public final class BaseTypes {
     }
 
     public static final URI BASE_TYPES_NAMESPACE = URI.create("urn:ietf:params:xml:ns:yang:1");
+    public static final QNameModule BASE_TYPES_MODULE = QNameModule.create(BASE_TYPES_NAMESPACE, null);
 
     public static final QName BINARY_QNAME = constructQName("binary");
     public static final QName BITS_QNAME = constructQName("bits");
@@ -84,7 +85,7 @@ public final class BaseTypes {
      * @return built-in base yang type QName.
      */
     public static QName constructQName(final String typeName) {
-        return new QName(BASE_TYPES_NAMESPACE, typeName);
+        return QName.create(BASE_TYPES_MODULE, "", typeName);
     }
 
     /**
@@ -97,7 +98,7 @@ public final class BaseTypes {
      */
     @Deprecated
     public static SchemaPath schemaPath(final QName typeName) {
-        return SchemaPath.create(Collections.singletonList(typeName), true);
+        return SchemaPath.create(true, typeName);
     }
 
     /**
@@ -122,7 +123,7 @@ public final class BaseTypes {
         }
         final List<QName> pathList = new ArrayList<QName>();
         for (final String path : actualPath) {
-            final QName qname = new QName(namespace, revision, path);
+            final QName qname = QName.create(namespace, revision, path);
             if (qname != null) {
                 pathList.add(qname);
             }
index ad3a0ef6d29410beb12b3e5aaa30595058a7caf2..20ec00cce25147bc2a8627902e97966734ae6077 100644 (file)
@@ -23,7 +23,7 @@ import org.opendaylight.yangtools.yang.model.api.type.BooleanTypeDefinition;
  */
 public final class BooleanType implements BooleanTypeDefinition {
     private static final BooleanType INSTANCE = new BooleanType();
-    private static final SchemaPath PATH = SchemaPath.create(Collections.singletonList(BaseTypes.BOOLEAN_QNAME), true);
+    private static final SchemaPath PATH = SchemaPath.create(true, BaseTypes.BOOLEAN_QNAME);
     private static final String DESCRIPTION = "The boolean built-in type represents a boolean value.";
     private static final String REFERENCE = "https://tools.ietf.org/html/rfc6020#section-9.5";
     private static final String UNITS = "";
index 3000c78e9fc98befdcf1b033cda1c3dbf09ea00f..c4a7ffe3edab286c9396defec69cdb2edebc057b 100644 (file)
@@ -7,6 +7,9 @@
  */
 package org.opendaylight.yangtools.yang.model.util;
 
+import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
+
 import java.net.URI;
 import java.util.Collections;
 import java.util.Date;
@@ -20,9 +23,6 @@ import org.opendaylight.yangtools.yang.model.api.UnknownSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.type.LengthConstraint;
 import org.opendaylight.yangtools.yang.model.api.type.PatternConstraint;
 import org.opendaylight.yangtools.yang.model.api.type.RangeConstraint;
-
-import com.google.common.base.Optional;
-import com.google.common.base.Preconditions;
 /**
  * Extended Type represents YANG type derived from other type.
  *
@@ -52,15 +52,15 @@ public class ExtendedType implements TypeDefinition<TypeDefinition<?>> {
     private final boolean addedByUses;
 
     /**
-    *
-    * Creates Builder for extended / derived type.
-    *
-    * @param typeName QName of derived type
-    * @param baseType Base type of derived type
-    * @param description Description of type
-    * @param reference Reference of Type
-    * @param path Schema path to type definition.
-    */
+     *
+     * Creates Builder for extended / derived type.
+     *
+     * @param typeName QName of derived type
+     * @param baseType Base type of derived type
+     * @param description Description of type
+     * @param reference Reference of Type
+     * @param path Schema path to type definition.
+     */
     public static final Builder builder(final QName typeName,final TypeDefinition<?> baseType,final Optional<String> description,final Optional<String> reference,final SchemaPath path) {
         return new Builder(typeName, baseType, description.or(""), reference.or(""), path);
     }
@@ -150,7 +150,11 @@ public class ExtendedType implements TypeDefinition<TypeDefinition<?>> {
 
         public Builder unknownSchemaNodes(
                 final List<UnknownSchemaNode> unknownSchemaNodes) {
-            this.unknownSchemaNodes = unknownSchemaNodes;
+            if (unknownSchemaNodes.isEmpty()) {
+                this.unknownSchemaNodes = Collections.emptyList();
+            } else {
+                this.unknownSchemaNodes = unknownSchemaNodes;
+            }
             return this;
         }
 
@@ -265,8 +269,9 @@ public class ExtendedType implements TypeDefinition<TypeDefinition<?>> {
         if (path != null ? !path.equals(that.path) : that.path != null) {
             return false;
         }
-        if (typeName != null ? !typeName.equals(that.typeName) : that.typeName != null)
+        if (typeName != null ? !typeName.equals(that.typeName) : that.typeName != null) {
             return false;
+        }
 
         return true;
     }
index b2d5887a7e6cbef4be618d392a2b2f8bfc9ef3b8..138b6a50a9b3e045f39b3c2c9a22e3e637a62d8a 100644 (file)
@@ -32,7 +32,7 @@ import org.opendaylight.yangtools.yang.model.api.type.InstanceIdentifierTypeDefi
 public final class InstanceIdentifier implements InstanceIdentifierTypeDefinition, Immutable {
 
     private static final QName NAME = BaseTypes.INSTANCE_IDENTIFIER_QNAME;
-    private static final SchemaPath PATH = SchemaPath.create(Collections.singletonList(NAME), true);
+    private static final SchemaPath PATH = SchemaPath.create(true, NAME);
     private static final String DESCRIPTION = "The instance-identifier built-in type is used to "
             + "uniquely identify a particular instance node in the data tree.";
     private static final String REFERENCE = "https://tools.ietf.org/html/rfc6020#section-9.13";
index 65fd92458f72564de1f9fd084490854fc4c50498..5a14d3097b7c2eb8fdf9c780e18fc3fb0582bf2e 100644 (file)
@@ -7,9 +7,9 @@
  */
 package org.opendaylight.yangtools.yang.model.util;
 
+import com.google.common.base.Preconditions;
 import java.util.Collections;
 import java.util.List;
-
 import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.model.api.RevisionAwareXPath;
 import org.opendaylight.yangtools.yang.model.api.SchemaPath;
@@ -17,8 +17,6 @@ import org.opendaylight.yangtools.yang.model.api.Status;
 import org.opendaylight.yangtools.yang.model.api.UnknownSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.type.LeafrefTypeDefinition;
 
-import com.google.common.base.Preconditions;
-
 /**
  * The <code>default</code> implementation of Instance Leafref Type Definition
  * interface.
@@ -27,7 +25,7 @@ import com.google.common.base.Preconditions;
  */
 public final class Leafref implements LeafrefTypeDefinition {
     private static final QName NAME = BaseTypes.constructQName("leafref");
-    private static final SchemaPath PATH = BaseTypes.schemaPath(NAME);
+    private static final SchemaPath PATH = SchemaPath.create(true, NAME);
     private static final String DESCRIPTION = "The leafref type is used to reference a particular leaf instance in the data tree.";
     private static final String REF = "https://tools.ietf.org/html/rfc6020#section-9.9";
 
index fbf4c4389b05f140dbc3452c367a18627f707109..57ed8fdd1da3ebdd47b89f690b6e1571114ef06b 100644 (file)
@@ -11,22 +11,14 @@ import com.google.common.base.Function;
 import com.google.common.base.Preconditions;
 import com.google.common.base.Splitter;
 import com.google.common.collect.Iterables;
-import java.net.URI;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Date;
 import java.util.Iterator;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Set;
 import org.opendaylight.yangtools.yang.common.QName;
-import org.opendaylight.yangtools.yang.model.api.AugmentationSchema;
-import org.opendaylight.yangtools.yang.model.api.AugmentationTarget;
 import org.opendaylight.yangtools.yang.model.api.ChoiceCaseNode;
 import org.opendaylight.yangtools.yang.model.api.ChoiceNode;
 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;
@@ -38,7 +30,6 @@ 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.UsesNode;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -240,33 +231,6 @@ public final class SchemaContextUtil {
         return findNodeInModule(module, path);
     }
 
-    public static GroupingDefinition findGrouping(final SchemaContext context, final Module module, final Iterable<QName> path) {
-        Iterator<QName> iterator = path.iterator();
-        QName first = iterator.next();
-        Module m = context.findModuleByNamespace(first.getNamespace()).iterator().next();
-        DataNodeContainer currentParent = m;
-        for (QName qname : path) {
-            boolean found = false;
-            DataNodeContainer node = (DataNodeContainer) currentParent.getDataChildByName(qname.getLocalName());
-            if (node == null) {
-                Set<GroupingDefinition> groupings = currentParent.getGroupings();
-                for (GroupingDefinition gr : groupings) {
-                    if (gr.getQName().getLocalName().equals(qname.getLocalName())) {
-                        currentParent = gr;
-                        found = true;
-                    }
-                }
-            } else {
-                found = true;
-                currentParent = node;
-            }
-
-            Preconditions.checkArgument(found, "Failed to find referenced grouping: %s(%s)", path, qname.getLocalName());
-        }
-
-        return (GroupingDefinition) currentParent;
-    }
-
     private static SchemaNode findNodeInModule(final Module module, final Iterable<QName> path) {
         final QName current = path.iterator().next();
 
@@ -428,7 +392,7 @@ public final class SchemaContextUtil {
         return node;
     }
 
-    public static SchemaNode findNodeInCase(final ChoiceCaseNode parent, final Iterable<QName> path) {
+    private static SchemaNode findNodeInCase(final ChoiceCaseNode parent, final Iterable<QName> path) {
         final QName current = Iterables.getFirst(path, null);
         if (current == null) {
             return parent;
@@ -442,7 +406,7 @@ public final class SchemaContextUtil {
         return findNode(node, nextLevel(path));
     }
 
-    public static RpcDefinition getRpcByName(final Module module, final QName name) {
+    private static RpcDefinition getRpcByName(final Module module, final QName name) {
         for (RpcDefinition rpc : module.getRpcs()) {
             if (rpc.getQName().equals(name)) {
                 return rpc;
@@ -455,7 +419,7 @@ public final class SchemaContextUtil {
         return Iterables.skip(path, 1);
     }
 
-    public static NotificationDefinition getNotificationByName(final Module module, final QName name) {
+    private static NotificationDefinition getNotificationByName(final Module module, final QName name) {
         for (NotificationDefinition notification : module.getNotifications()) {
             if (notification.getQName().equals(name)) {
                 return notification;
@@ -464,7 +428,7 @@ public final class SchemaContextUtil {
         return null;
     }
 
-    public static GroupingDefinition getGroupingByName(final Module module, final QName name) {
+    private static GroupingDefinition getGroupingByName(final Module module, final QName name) {
         for (GroupingDefinition grouping : module.getGroupings()) {
             if (grouping.getQName().equals(name)) {
                 return grouping;
@@ -473,257 +437,6 @@ public final class SchemaContextUtil {
         return null;
     }
 
-    /**
-     * Utility method which search for original node defined in grouping.
-     *
-     * @param node
-     * @return
-     */
-    public static DataSchemaNode findOriginal(final DataSchemaNode node, final SchemaContext ctx) {
-        DataSchemaNode result = findCorrectTargetFromGrouping(node, ctx);
-        if (result == null) {
-            result = findCorrectTargetFromAugment(node, ctx);
-            if (result != null) {
-                if (result.isAddedByUses()) {
-                    result = findOriginal(result, ctx);
-                }
-            }
-        }
-        return result;
-    }
-
-    private static DataSchemaNode findCorrectImmediateTargetFromGrouping(final DataSchemaNode node, final SchemaContext ctx) {
-        // uses is under module statement
-        final Module m = findParentModule(ctx, node);
-        Preconditions.checkArgument(m != null, "Failed to find module for node {} in context {}", node, ctx);
-
-        for (final UsesNode u : m.getUses()) {
-            final SchemaNode targetGrouping = findNodeInSchemaContext(ctx, u.getGroupingPath().getPathFromRoot());
-            Preconditions.checkArgument(targetGrouping instanceof GroupingDefinition,
-                    "Failed to generate code for augment in %s", u);
-
-            LOG.trace("Checking grouping {} for node {}", targetGrouping, node);
-            final GroupingDefinition gr = (GroupingDefinition) targetGrouping;
-            final DataSchemaNode result = gr.getDataChildByName(node.getQName().getLocalName());
-            if (result != null) {
-                return result;
-            }
-
-            LOG.debug("Skipped grouping {}, no matching node found", gr);
-        }
-
-        throw new IllegalArgumentException(
-                String.format("Failed to find uses node matching {} in context {}", node, ctx));
-    }
-
-    private static DataSchemaNode findCorrectTargetFromGrouping(final DataSchemaNode node, final SchemaContext ctx) {
-        if (Iterables.size(node.getPath().getPathTowardsRoot()) != 1) {
-            QName currentName = node.getQName();
-            // tmpPath is used to track level of nesting
-            List<QName> tmpPath = new ArrayList<>();
-            Object parent = null;
-
-            // create schema path of parent node
-            SchemaPath sp = node.getPath().getParent();
-            parent = findDataSchemaNode(ctx, sp);
-
-            do {
-                tmpPath.add(currentName);
-
-                DataSchemaNode result = null;
-                // search parent node's used groupings for presence of wanted
-                // node
-                if (parent instanceof DataNodeContainer) {
-                    DataNodeContainer dataNodeParent = (DataNodeContainer) parent;
-                    for (UsesNode u : dataNodeParent.getUses()) {
-                        result = getResultFromUses(u, currentName.getLocalName(), ctx);
-                        if (result != null) {
-                            break;
-                        }
-                    }
-                }
-
-                // if node is not found in any of current parent's used
-                // groupings => parent is added by grouping too, so repeat same
-                // process for parent
-                if (result == null) {
-                    final SchemaNode sn = (SchemaNode) parent;
-
-                    // set current name to name of parent node
-                    currentName = sn.getQName();
-                    Preconditions.checkArgument(parent instanceof SchemaNode,
-                            "Failed to generate code for augmend node {} at parent {}", node, parent);
-
-                    // create schema path for parent of current parent
-                    final SchemaPath parentSp = sn.getPath().getParent();
-                    parent = parentSp.getPathFromRoot().iterator().hasNext() ? findDataSchemaNode(ctx, parentSp)
-                            : getParentModule(sn, ctx);
-                } else {
-                    // if wanted node was found in grouping, traverse this node
-                    // based on level of nesting
-                    return getTargetNode(tmpPath, result, ctx);
-                }
-            } while (!(parent instanceof Module));
-
-            return null;
-        } else {
-            return findCorrectImmediateTargetFromGrouping(node, ctx);
-        }
-    }
-
-    private static DataSchemaNode findCorrectTargetFromAugment(final DataSchemaNode node, final SchemaContext ctx) {
-        if (!node.isAugmenting()) {
-            return null;
-        }
-
-        QName currentName = node.getQName();
-        Object currentNode = node;
-        Object parent = node;
-        List<QName> tmpPath = new ArrayList<QName>();
-        List<SchemaNode> tmpTree = new ArrayList<SchemaNode>();
-
-        AugmentationSchema augment = null;
-        do {
-            SchemaPath sp = ((SchemaNode) parent).getPath();
-            parent = findDataSchemaNode(ctx, sp.getParent());
-            if (parent instanceof AugmentationTarget) {
-                tmpPath.add(currentName);
-                tmpTree.add((SchemaNode) currentNode);
-                augment = findNodeInAugment(((AugmentationTarget) parent).getAvailableAugmentations(), currentName);
-                if (augment == null) {
-                    currentName = ((DataSchemaNode) parent).getQName();
-                    currentNode = parent;
-                }
-            }
-        } while (((DataSchemaNode) parent).isAugmenting() && augment == null);
-
-        if (augment == null) {
-            return null;
-        } else {
-            Collections.reverse(tmpPath);
-            Collections.reverse(tmpTree);
-            Object actualParent = augment;
-            DataSchemaNode result = null;
-            for (QName name : tmpPath) {
-                if (actualParent instanceof DataNodeContainer) {
-                    result = ((DataNodeContainer) actualParent).getDataChildByName(name.getLocalName());
-                    actualParent = ((DataNodeContainer) actualParent).getDataChildByName(name.getLocalName());
-                } else {
-                    if (actualParent instanceof ChoiceNode) {
-                        result = ((ChoiceNode) actualParent).getCaseNodeByName(name.getLocalName());
-                        actualParent = ((ChoiceNode) actualParent).getCaseNodeByName(name.getLocalName());
-                    }
-                }
-            }
-
-            if (result.isAddedByUses()) {
-                result = findCorrectTargetFromAugmentGrouping(result, augment, tmpTree, ctx);
-            }
-
-            return result;
-        }
-    }
-
-    private static DataSchemaNode getResultFromUses(final UsesNode u, final String currentName, final SchemaContext ctx) {
-        SchemaNode targetGrouping = SchemaContextUtil.findNodeInSchemaContext(ctx, u.getGroupingPath()
-                .getPathFromRoot());
-        if (!(targetGrouping instanceof GroupingDefinition)) {
-            targetGrouping = findGrouping(ctx, getParentModule(targetGrouping, ctx), u.getGroupingPath()
-                    .getPathFromRoot());
-        }
-        Preconditions.checkArgument(targetGrouping instanceof GroupingDefinition,
-                "Failed to generate code for augment in %s", u);
-        GroupingDefinition gr = (GroupingDefinition) targetGrouping;
-        return gr.getDataChildByName(currentName);
-    }
-
-    private static Module getParentModule(final SchemaNode node, final SchemaContext ctx) {
-        QName qname = node.getPath().getPathFromRoot().iterator().next();
-        URI namespace = qname.getNamespace();
-        Date revision = qname.getRevision();
-        return ctx.findModuleByNamespaceAndRevision(namespace, revision);
-    }
-
-    private static DataSchemaNode getTargetNode(final List<QName> tmpPath, final DataSchemaNode node, final SchemaContext ctx) {
-        DataSchemaNode result = node;
-        if (tmpPath.size() == 1) {
-            if (result != null && result.isAddedByUses()) {
-                result = findOriginal(result, ctx);
-            }
-            return result;
-        } else {
-            DataSchemaNode newParent = result;
-            Collections.reverse(tmpPath);
-
-            tmpPath.remove(0);
-            for (QName name : tmpPath) {
-                // searching by local name is must, because node has different
-                // namespace in its original location
-                if (newParent == null) {
-                    break;
-                }
-                if (newParent instanceof DataNodeContainer) {
-                    newParent = ((DataNodeContainer) newParent).getDataChildByName(name.getLocalName());
-                } else {
-                    newParent = ((ChoiceNode) newParent).getCaseNodeByName(name.getLocalName());
-                }
-            }
-            if (newParent != null && newParent.isAddedByUses()) {
-                newParent = findOriginal(newParent, ctx);
-            }
-            return newParent;
-        }
-    }
-
-    private static AugmentationSchema findNodeInAugment(final Collection<AugmentationSchema> augments, final QName name) {
-        for (AugmentationSchema augment : augments) {
-            DataSchemaNode node = augment.getDataChildByName(name);
-            if (node != null) {
-                return augment;
-            }
-        }
-        return null;
-    }
-
-    private static DataSchemaNode findCorrectTargetFromAugmentGrouping(final DataSchemaNode node,
-            final AugmentationSchema parentNode, final List<SchemaNode> dataTree, final SchemaContext ctx) {
-
-        DataSchemaNode result = null;
-        QName currentName = node.getQName();
-        List<QName> tmpPath = new ArrayList<>();
-        tmpPath.add(currentName);
-        int i = 1;
-        Object parent = null;
-
-        do {
-            if (dataTree.size() < 2 || dataTree.size() == i) {
-                parent = parentNode;
-            } else {
-                parent = dataTree.get(dataTree.size() - (i + 1));
-                tmpPath.add(((SchemaNode) parent).getQName());
-            }
-
-            if (parent instanceof DataNodeContainer) {
-                DataNodeContainer dataNodeParent = (DataNodeContainer) parent;
-                for (UsesNode u : dataNodeParent.getUses()) {
-                    if (result == null) {
-                        result = getResultFromUses(u, currentName.getLocalName(), ctx);
-                    }
-                }
-            }
-
-            if (result == null) {
-                i = i + 1;
-                currentName = ((SchemaNode) parent).getQName();
-            }
-        } while (result == null);
-
-        if (result != null) {
-            result = getTargetNode(tmpPath, result, ctx);
-        }
-        return result;
-    }
-
     /**
      * Transforms string representation of XPath to Queue of QNames. The XPath
      * is split by "/" and for each part of XPath is assigned correct module in
index 857e6a4d030037e89bc8dc7b01607149542a463c..984580adc6f98403581c7eb5a4a160ef3bd1027b 100644 (file)
@@ -7,6 +7,8 @@
  */
 package org.opendaylight.yangtools.yang.model.util;
 
+import com.google.common.base.Optional;
+
 import java.util.Collections;
 import java.util.List;
 
@@ -19,8 +21,6 @@ import org.opendaylight.yangtools.yang.model.api.type.LengthConstraint;
 import org.opendaylight.yangtools.yang.model.api.type.PatternConstraint;
 import org.opendaylight.yangtools.yang.model.api.type.StringTypeDefinition;
 
-import com.google.common.base.Optional;
-
 /**
  * The <code>default</code> implementation of String Type Definition interface.
  *
@@ -28,7 +28,7 @@ import com.google.common.base.Optional;
  */
 public final class StringType implements StringTypeDefinition, Immutable {
     private static final QName NAME = BaseTypes.STRING_QNAME;
-    private static final SchemaPath PATH = SchemaPath.create(Collections.singletonList(NAME), true);
+    private static final SchemaPath PATH = SchemaPath.create(true, NAME);
     private static final String DEFAULT_VALUE = "";
     private static final String DESCRIPTION = "";
     private static final String REFERENCE = "";
index 3386bb720f5e238d8760f6b1cc7bc765070d3e7e..41e91351aff53d514fa943b1db15b1c163683c69 100644 (file)
@@ -7,6 +7,9 @@
  */
 package org.opendaylight.yangtools.yang.model.util;
 
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableList;
+
 import java.util.Collections;
 import java.util.List;
 
@@ -17,11 +20,8 @@ import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
 import org.opendaylight.yangtools.yang.model.api.UnknownSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.type.UnionTypeDefinition;
 
-import com.google.common.base.Preconditions;
-import com.google.common.collect.ImmutableList;
-
 public final class UnionType implements UnionTypeDefinition {
-    private final SchemaPath path = SchemaPath.create(Collections.singletonList(BaseTypes.UNION_QNAME),true);
+    private static final SchemaPath PATH = SchemaPath.create(true, BaseTypes.UNION_QNAME);
     private static final String DESCRIPTION = "The union built-in type represents a value that corresponds to one of its member types.";
     private static final String REFERENCE = "https://tools.ietf.org/html/rfc6020#section-9.12";
     private final List<TypeDefinition<?>> types;
@@ -58,7 +58,7 @@ public final class UnionType implements UnionTypeDefinition {
 
     @Override
     public SchemaPath getPath() {
-        return path;
+        return PATH;
     }
 
     @Override
index 2e23b81db600af9e5db25af9b484a543aee50527..f32c16f8bf9b7433d001d0c6c1b84ff0ac49cb7b 100644 (file)
@@ -25,9 +25,7 @@ import org.opendaylight.yangtools.yang.model.api.type.UnknownTypeDefinition;
  * Unknown type definition is derived type, for
  * which base built-in type is not yet known. This types
  * are possible during parsing and resolving of YANG model
- * without all requisites allready processed.
- *
- *
+ * without all requisites already processed.
  */
 public final class UnknownType implements UnknownTypeDefinition {
 
@@ -66,14 +64,14 @@ public final class UnknownType implements UnknownTypeDefinition {
 
         public Builder(final QName name, final String description, final String reference) {
             this.name = name;
-            this.path = BaseTypes.schemaPath(name);
+            this.path = SchemaPath.create(true, name);
             this.description = description;
             this.reference = reference;
         }
 
         public Builder(final QName name) {
             this.name = name;
-            this.path = BaseTypes.schemaPath(name);
+            this.path = SchemaPath.create(true, name);
         }
 
         public Builder description(final String description) {
index 2662bbb001fece80f80909260f6c669db3ee0e54..0c812a8c42163e2109b6717f334b198952711a6b 100644 (file)
                     <listener>true</listener>
                 </configuration>
             </plugin>
-            <plugin>
-                <groupId>org.codehaus.mojo</groupId>
-                <artifactId>build-helper-maven-plugin</artifactId>
-                <executions>
-                    <execution>
-                        <phase>generate-sources</phase>
-                        <goals>
-                            <goal>add-source</goal>
-                        </goals>
-                        <configuration>
-                            <sources>
-                                <source>target/generated-sources/parser</source>
-                            </sources>
-                        </configuration>
-                    </execution>
-                </executions>
-            </plugin>
             <plugin>
                 <groupId>org.apache.maven.plugins</groupId>
                 <artifactId>maven-javadoc-plugin</artifactId>
index 232f4578bde81e5ca7558cb5b02d9599d57e2294..18497d7f5d86f2431029957b0316358942cf544b 100644 (file)
@@ -11,13 +11,14 @@ import static com.google.common.base.Preconditions.checkNotNull;
 
 import com.google.common.base.Optional;
 import com.google.common.collect.ImmutableList;
+
 import java.net.URI;
 import java.util.ArrayList;
 import java.util.Date;
 import java.util.Iterator;
 import java.util.List;
+
 import org.opendaylight.yangtools.yang.common.QName;
-import org.opendaylight.yangtools.yang.common.QNameModule;
 import org.opendaylight.yangtools.yang.model.api.AugmentationSchema;
 import org.opendaylight.yangtools.yang.model.api.NamespaceRevisionAware;
 import org.opendaylight.yangtools.yang.model.api.RevisionAwareXPath;
@@ -31,8 +32,7 @@ import org.opendaylight.yangtools.yang.parser.builder.api.UsesNodeBuilder;
 import org.opendaylight.yangtools.yang.parser.builder.util.AbstractDocumentedDataNodeContainer;
 import org.opendaylight.yangtools.yang.parser.builder.util.AbstractDocumentedDataNodeContainerBuilder;
 
-public final class AugmentationSchemaBuilderImpl extends AbstractDocumentedDataNodeContainerBuilder implements
-        AugmentationSchemaBuilder {
+public final class AugmentationSchemaBuilderImpl extends AbstractDocumentedDataNodeContainerBuilder implements AugmentationSchemaBuilder {
     private final int order;
     private AugmentationSchemaImpl instance;
     private String whenCondition;
@@ -79,11 +79,10 @@ public final class AugmentationSchemaBuilderImpl extends AbstractDocumentedDataN
 
         if (parent instanceof UsesNodeBuilder) {
             final ModuleBuilder mb = BuilderUtils.getParentModule(this);
-            final QNameModule qm = QNameModule.create(mb.getNamespace(), mb.getRevision());
 
             List<QName> newPath = new ArrayList<>();
             for (QName name : targetPath.getPathFromRoot()) {
-                newPath.add(QName.create(qm, name.getPrefix(), name.getLocalName()));
+                newPath.add(QName.create(mb.getQNameModule(), name.getPrefix(), name.getLocalName()));
             }
             instance.targetPath = SchemaPath.create(newPath, false);
         } else {
@@ -207,8 +206,7 @@ public final class AugmentationSchemaBuilderImpl extends AbstractDocumentedDataN
         copyOf = old;
     }
 
-    private static final class AugmentationSchemaImpl extends AbstractDocumentedDataNodeContainer implements AugmentationSchema, NamespaceRevisionAware,
-            Comparable<AugmentationSchemaImpl> {
+    private static final class AugmentationSchemaImpl extends AbstractDocumentedDataNodeContainer implements AugmentationSchema, NamespaceRevisionAware, Comparable<AugmentationSchemaImpl> {
         private final int order;
         private SchemaPath targetPath;
         private RevisionAwareXPath whenCondition;
index 70eb185ca25b3063538a62c2285526d1a96d08ef..0eae6cace889bc54c718d9169f041f35d084bcdd 100644 (file)
@@ -13,6 +13,7 @@ import com.google.common.base.Preconditions;
 import com.google.common.base.Splitter;
 import com.google.common.collect.Collections2;
 import com.google.common.io.ByteSource;
+
 import java.io.ByteArrayOutputStream;
 import java.io.File;
 import java.io.FileNotFoundException;
@@ -30,6 +31,7 @@ import java.util.TreeMap;
 
 import org.apache.commons.io.IOUtils;
 import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.common.QNameModule;
 import org.opendaylight.yangtools.yang.model.api.AnyXmlSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.ChoiceCaseNode;
 import org.opendaylight.yangtools.yang.model.api.ChoiceNode;
@@ -233,9 +235,9 @@ public final class BuilderUtils {
 
             final QName name;
             if (it.hasNext()) {
-                name = new QName(null, null, s, it.next());
+                name = QName.create(QNameModule.create(null, null), s, it.next());
             } else {
-                name = new QName(null, null, null, s);
+                name = QName.create(QNameModule.create(null, null), s);
             }
             path.add(name);
         }
@@ -745,7 +747,7 @@ public final class BuilderUtils {
         }
     }
 
-    public static ModuleBuilder getModuleByPrefix(ModuleBuilder module, String prefix) {
+    public static ModuleBuilder getModuleByPrefix(final ModuleBuilder module, final String prefix) {
         if (prefix == null || prefix.isEmpty() || prefix.equals(module.getPrefix())) {
             return module;
         } else {
index 5cb69724010dc9766623936a8bbf7c54064719a9..365c34379eba8e05df5292463ab68b71614cd97e 100644 (file)
@@ -455,7 +455,7 @@ public final class CopyUtils {
         if (newParent instanceof ModuleBuilder) {
             ModuleBuilder parent = (ModuleBuilder) newParent;
             if (updateQName) {
-                newQName = new QName(parent.getNamespace(), parent.getRevision(), parent.getPrefix(), old.getQName()
+                newQName = QName.create(parent.getQNameModule(), parent.getPrefix(), old.getQName()
                         .getLocalName());
             } else {
                 newQName = old.getQName();
@@ -465,7 +465,7 @@ public final class CopyUtils {
             AugmentationSchemaBuilder augment = (AugmentationSchemaBuilder) newParent;
             ModuleBuilder parent = BuilderUtils.getParentModule(newParent);
             if (updateQName) {
-                newQName = new QName(parent.getNamespace(), parent.getRevision(), parent.getPrefix(), old.getQName()
+                newQName = QName.create(parent.getQNameModule(), parent.getPrefix(), old.getQName()
                         .getLocalName());
             } else {
                 newQName = old.getQName();
index ba7f4aaf004d58d0d7db67334535298fa1501ea5..994a979b20f1bf2a8822a0b58d9aeb840cf504d2 100644 (file)
@@ -7,13 +7,17 @@
  */
 package org.opendaylight.yangtools.yang.parser.builder.impl;
 
+import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Set;
-
 import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.model.api.AugmentationSchema;
 import org.opendaylight.yangtools.yang.model.api.ConstraintDefinition;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.DerivableSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.SchemaPath;
@@ -26,14 +30,10 @@ import org.opendaylight.yangtools.yang.parser.builder.api.SchemaNodeBuilder;
 import org.opendaylight.yangtools.yang.parser.builder.api.UnknownSchemaNodeBuilder;
 import org.opendaylight.yangtools.yang.parser.builder.util.AbstractDocumentedDataNodeContainer;
 import org.opendaylight.yangtools.yang.parser.builder.util.AbstractDocumentedDataNodeContainerBuilder;
+import org.opendaylight.yangtools.yang.parser.util.YangParseException;
 
-import com.google.common.base.Optional;
-import com.google.common.base.Preconditions;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableSet;
-
-public final class ListSchemaNodeBuilder extends AbstractDocumentedDataNodeContainerBuilder implements DataSchemaNodeBuilder,
-AugmentationTargetBuilder {
+public final class ListSchemaNodeBuilder extends AbstractDocumentedDataNodeContainerBuilder implements
+        DataSchemaNodeBuilder, AugmentationTargetBuilder {
     private ListSchemaNodeImpl instance;
     private boolean userOrdered;
     private List<String> keys;
@@ -59,7 +59,7 @@ AugmentationTargetBuilder {
 
     public ListSchemaNodeBuilder(final String moduleName, final int line, final QName qname, final SchemaPath path,
             final ListSchemaNode base) {
-        super(moduleName, line, qname,path,base);
+        super(moduleName, line, qname, path, base);
         this.schemaPath = Preconditions.checkNotNull(path, "Schema Path must not be null");
         constraints = new ConstraintsBuilderImpl(moduleName, line, base.getConstraints());
 
@@ -82,7 +82,7 @@ AugmentationTargetBuilder {
             return instance;
         }
         buildChildren();
-        instance = new ListSchemaNodeImpl(qname, schemaPath,this);
+        instance = new ListSchemaNodeImpl(qname, schemaPath, this);
 
         instance.augmenting = augmenting;
         instance.addedByUses = addedByUses;
@@ -96,7 +96,12 @@ AugmentationTargetBuilder {
         } else {
             keyDefinition = new ArrayList<>();
             for (String key : keys) {
-                keyDefinition.add(instance.getDataChildByName(key).getQName());
+                DataSchemaNode keyPart = instance.getDataChildByName(key);
+                if (keyPart == null) {
+                    throw new YangParseException(getModuleName(), getLine(), "Failed to resolve list key for name "
+                            + key);
+                }
+                keyDefinition.add(keyPart.getQName());
             }
             instance.keyDefinition = ImmutableList.copyOf(keyDefinition);
         }
@@ -250,7 +255,8 @@ AugmentationTargetBuilder {
         return "list " + qname.getLocalName();
     }
 
-    private static final class ListSchemaNodeImpl extends AbstractDocumentedDataNodeContainer implements ListSchemaNode, DerivableSchemaNode {
+    private static final class ListSchemaNodeImpl extends AbstractDocumentedDataNodeContainer implements
+            ListSchemaNode, DerivableSchemaNode {
         private final QName qname;
         private final SchemaPath path;
         private ImmutableList<QName> keyDefinition;
index d762af57bf7f382c4e722f6253a40a8954f40784..db1babd6dc08ef8242c4aa37c81232224ebbc8e8 100644 (file)
@@ -129,7 +129,7 @@ public class ModuleBuilder extends AbstractDocumentedDataNodeContainerBuilder im
     }
 
     public ModuleBuilder(final Module base) {
-        super(base.getName(), 0, new QName(base.getNamespace(), base.getRevision(), base.getPrefix(), base.getName()),
+        super(base.getName(), 0, QName.create(base.getQNameModule(), base.getPrefix(), base.getName()),
                 SCHEMA_PATH, base);
         this.name = base.getName();
         this.sourcePath = base.getModuleSourcePath();
index 61b47f2cf5032585b10ce7533692857cd043e282..d59b0215a68cd9e1736b054802ff8a79e9e8dadb 100644 (file)
@@ -7,6 +7,8 @@
  */
 package org.opendaylight.yangtools.yang.parser.builder.impl;
 
+import static org.opendaylight.yangtools.yang.parser.builder.impl.BuilderUtils.findBaseIdentity;
+
 import java.util.ArrayList;
 import java.util.Date;
 import java.util.List;
@@ -86,6 +88,18 @@ public final class TypeUtils {
                 toRemove.add(unionType);
             }
         }
+        // special handling for identityref types under union
+        for (TypeDefinitionBuilder unionType : union.getTypedefs()) {
+            if (unionType instanceof IdentityrefTypeBuilder) {
+                IdentityrefTypeBuilder idref = (IdentityrefTypeBuilder) unionType;
+                IdentitySchemaNodeBuilder identity = findBaseIdentity(modules, module, idref.getBaseString(),
+                        idref.getLine());
+                if (identity == null) {
+                    throw new YangParseException(module.getName(), idref.getLine(), "Failed to find base identity");
+                }
+                idref.setBaseIdentity(identity);
+            }
+        }
         unionTypes.removeAll(toRemove);
     }
 
@@ -93,6 +107,10 @@ public final class TypeUtils {
             final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder module) {
         final QName utQName = ut.getQName();
         final ModuleBuilder dependentModuleBuilder = BuilderUtils.getModuleByPrefix(module, utQName.getPrefix());
+        if (dependentModuleBuilder == null) {
+            throw new YangParseException(module.getName(), union.getLine(), "No module found with prefix "
+                    + utQName.getPrefix());
+        }
         final TypeDefinitionBuilder resolvedType = findTypeDefinitionBuilder(union, dependentModuleBuilder,
                 utQName.getLocalName(), module.getName(), union.getLine());
         union.setTypedef(resolvedType);
index 1facf78f3d4c3386db29c74c46aabb4cf88a5d07..9d68c53fb0a18cc2a8fa9d07264ab0e182e3c1e7 100644 (file)
@@ -10,6 +10,7 @@ package org.opendaylight.yangtools.yang.parser.builder.impl;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
+
 import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.model.api.SchemaPath;
 import org.opendaylight.yangtools.yang.model.api.Status;
@@ -31,8 +32,8 @@ import org.opendaylight.yangtools.yang.parser.util.YangParseException;
  * types.
  */
 public final class UnionTypeBuilder extends AbstractTypeAwareBuilder implements TypeDefinitionBuilder {
+    private static final SchemaPath SCHEMA_PATH = SchemaPath.create(true, BaseTypes.UNION_QNAME);
     private static final String NAME = "union";
-    private static final QName QNAME = BaseTypes.constructQName(NAME);
 
     private final List<TypeDefinition<?>> types;
     private final List<TypeDefinitionBuilder> typedefs;
@@ -40,7 +41,7 @@ public final class UnionTypeBuilder extends AbstractTypeAwareBuilder implements
     private boolean isBuilt;
 
     public UnionTypeBuilder(final String moduleName, final int line) {
-        super(moduleName, line, BaseTypes.constructQName(NAME));
+        super(moduleName, line, BaseTypes.UNION_QNAME);
         types = new ArrayList<>();
         typedefs = new ArrayList<>();
     }
@@ -122,7 +123,7 @@ public final class UnionTypeBuilder extends AbstractTypeAwareBuilder implements
 
     @Override
     public SchemaPath getPath() {
-        return SchemaPath.create(true,  QNAME);
+        return SCHEMA_PATH;
     }
 
     @Override
index 0f3c4dd2f8bbb2f9519556c6e63d595c6e376d8b..25ace683009ac9f49d72e74458b353f1679450f9 100644 (file)
@@ -27,6 +27,7 @@ import com.google.common.base.Preconditions;
 import com.google.common.base.Splitter;
 import com.google.common.collect.HashBiMap;
 import com.google.common.io.ByteSource;
+
 import java.io.File;
 import java.io.IOException;
 import java.io.InputStream;
@@ -36,14 +37,15 @@ import java.util.Collections;
 import java.util.Date;
 import java.util.HashMap;
 import java.util.HashSet;
-import java.util.Iterator;
 import java.util.LinkedHashMap;
 import java.util.LinkedHashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
 import java.util.TreeMap;
+
 import javax.annotation.concurrent.Immutable;
+
 import org.antlr.v4.runtime.ANTLRInputStream;
 import org.antlr.v4.runtime.CommonTokenStream;
 import org.antlr.v4.runtime.tree.ParseTree;
@@ -117,7 +119,7 @@ public final class YangParserImpl implements YangContextParser {
 
     @Override
     public SchemaContext parseFile(final File yangFile, final File directory) throws IOException,
-            YangSyntaxErrorException {
+    YangSyntaxErrorException {
         Preconditions.checkState(yangFile.exists(), yangFile + " does not exists");
         Preconditions.checkState(directory.exists(), directory + " does not exists");
         Preconditions.checkState(directory.isDirectory(), directory + " is not a directory");
@@ -182,7 +184,7 @@ public final class YangParserImpl implements YangContextParser {
 
     @Override
     public SchemaContext parseFiles(final Collection<File> yangFiles, final SchemaContext context) throws IOException,
-            YangSyntaxErrorException {
+    YangSyntaxErrorException {
         if (yangFiles == null) {
             return resolveSchemaContext(Collections.<Module> emptySet());
         }
@@ -204,7 +206,7 @@ public final class YangParserImpl implements YangContextParser {
 
     @Override
     public SchemaContext parseSources(final Collection<ByteSource> sources) throws IOException,
-            YangSyntaxErrorException {
+    YangSyntaxErrorException {
         Collection<Module> unsorted = parseYangModelSources(sources).values();
         Set<Module> sorted = new LinkedHashSet<>(
                 ModuleDependencySort.sort(unsorted.toArray(new Module[unsorted.size()])));
@@ -245,8 +247,8 @@ public final class YangParserImpl implements YangContextParser {
         return resolveSchemaContext(result);
     }
 
-    private LinkedHashMap<String, TreeMap<Date, ModuleBuilder>> resolveModulesWithImports(List<ModuleBuilder> sorted,
-            SchemaContext context) {
+    private LinkedHashMap<String, TreeMap<Date, ModuleBuilder>> resolveModulesWithImports(final List<ModuleBuilder> sorted,
+            final SchemaContext context) {
         final LinkedHashMap<String, TreeMap<Date, ModuleBuilder>> modules = orderModules(sorted);
         for (ModuleBuilder module : sorted) {
             if (module != null) {
@@ -345,7 +347,7 @@ public final class YangParserImpl implements YangContextParser {
     }
 
     private Map<ByteSource, Module> parseYangModelSources(final Collection<ByteSource> sources) throws IOException,
-            YangSyntaxErrorException {
+    YangSyntaxErrorException {
         if (sources == null || sources.isEmpty()) {
             return Collections.emptyMap();
         }
@@ -378,7 +380,7 @@ public final class YangParserImpl implements YangContextParser {
      */
     // TODO: remove ByteSource result after removing YangModelParser
     private Map<ByteSource, ModuleBuilder> resolveSources(final Collection<ByteSource> streams) throws IOException,
-            YangSyntaxErrorException {
+    YangSyntaxErrorException {
         Map<ByteSource, ModuleBuilder> builders = parseSourcesToBuilders(streams);
         return resolveSubmodules(builders);
     }
@@ -593,7 +595,7 @@ public final class YangParserImpl implements YangContextParser {
     }
 
     private Map<ByteSource, ParseTree> parseYangSources(final Collection<ByteSource> sources) throws IOException,
-            YangSyntaxErrorException {
+    YangSyntaxErrorException {
         final Map<ByteSource, ParseTree> trees = new HashMap<>();
         for (ByteSource source : sources) {
             trees.put(source, parseYangSource(source));
@@ -764,13 +766,11 @@ public final class YangParserImpl implements YangContextParser {
     private void setCorrectAugmentTargetPath(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
             final AugmentationSchemaBuilder augment) {
         ModuleBuilder module = BuilderUtils.getParentModule(augment);
-        Iterable<QName> oldPath = augment.getTargetPath().getPathFromRoot();
-        List<QName> newPath = new ArrayList<>();
+        final SchemaPath newSchemaPath;
 
         Builder parent = augment.getParent();
         if (parent instanceof UsesNodeBuilder) {
             DataNodeContainerBuilder usesParent = ((UsesNodeBuilder) parent).getParent();
-            newPath.addAll(usesParent.getPath().getPath());
 
             QName baseQName = usesParent.getQName();
             final QNameModule qnm;
@@ -784,11 +784,16 @@ public final class YangParserImpl implements YangContextParser {
                 prefix = baseQName.getPrefix();
             }
 
-            for (QName qn : oldPath) {
-                newPath.add(QName.create(qnm, prefix, qn.getLocalName()));
+            SchemaPath s = usesParent.getPath();
+            for (QName qn : augment.getTargetPath().getPathFromRoot()) {
+                s = s.createChild(QName.create(qnm, prefix, qn.getLocalName()));
             }
+
+            newSchemaPath = s;
         } else {
-            for (QName qn : oldPath) {
+            final List<QName> newPath = new ArrayList<>();
+
+            for (QName qn : augment.getTargetPath().getPathFromRoot()) {
                 QNameModule qnm = module.getQNameModule();
                 String localPrefix = qn.getPrefix();
                 if (localPrefix != null && !localPrefix.isEmpty()) {
@@ -799,10 +804,18 @@ public final class YangParserImpl implements YangContextParser {
                     }
                     qnm = currentModule.getQNameModule();
                 }
-                newPath.add(new QName(qnm.getNamespace(), qnm.getRevision(), localPrefix, qn.getLocalName()));
+                newPath.add(QName.create(qnm, localPrefix, qn.getLocalName()));
             }
+
+            /*
+             * FIXME: this method of SchemaPath construction is highly ineffective.
+             *        It would be great if we could actually dive into the context,
+             *        find the actual target node and reuse its SchemaPath. Can we
+             *        do that?
+             */
+            newSchemaPath = SchemaPath.create(newPath, true);
         }
-        augment.setTargetNodeSchemaPath(SchemaPath.create(newPath, true));
+        augment.setTargetNodeSchemaPath(newSchemaPath);
 
         for (DataSchemaNodeBuilder childNode : augment.getChildNodeBuilders()) {
             correctPathForAugmentNodes(childNode, augment.getTargetNodeSchemaPath());
@@ -996,7 +1009,7 @@ public final class YangParserImpl implements YangContextParser {
         }
     }
 
-    private void resolveIdentity(final Map<String, TreeMap<Date, ModuleBuilder>> modules, ModuleBuilder module,
+    private void resolveIdentity(final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder module,
             final IdentitySchemaNodeBuilder identity) {
         final String baseIdentityName = identity.getBaseIdentityName();
         if (baseIdentityName != null) {
@@ -1203,7 +1216,7 @@ public final class YangParserImpl implements YangContextParser {
                     usnb.setExtensionDefinition(extDef);
                 }
             } else {
-                usnb.setNodeType(new QName(extBuilder.getQName().getNamespace(), extBuilder.getQName().getRevision(),
+                usnb.setNodeType(QName.create(extBuilder.getQName().getModule(),
                         nodeType.getPrefix(), extBuilder.getQName().getLocalName()));
                 usnb.setExtensionBuilder(extBuilder);
             }
index b51c638717daf50153ef0328e94abe0f6f0bd4ab..a536c1cbf85a2abaf518006afb048bd21107f314 100644 (file)
@@ -69,6 +69,7 @@ import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.When_stmtContext;
 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Yang_version_stmtContext;
 import org.opendaylight.yangtools.antlrv4.code.gen.YangParserBaseListener;
 import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.common.QNameModule;
 import org.opendaylight.yangtools.yang.model.api.SchemaPath;
 import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
 import org.opendaylight.yangtools.yang.model.util.BaseTypes;
@@ -199,7 +200,7 @@ public final class YangParserListenerImpl extends YangParserBaseListener {
                 setLog("namespace", namespaceStr);
             } else if (treeNode instanceof Prefix_stmtContext) {
                 final String yangModelPrefix = stringFromNode(treeNode);
-                this.moduleQName = new QName(moduleQName.getNamespace(), moduleQName.getRevision(), yangModelPrefix, moduleQName.getLocalName());
+                this.moduleQName = QName.create(moduleQName.getModule(), yangModelPrefix, moduleQName.getLocalName());
                 moduleBuilder.setPrefix(yangModelPrefix);
                 setLog("prefix", yangModelPrefix);
             } else if (treeNode instanceof Yang_version_stmtContext) {
@@ -471,7 +472,7 @@ public final class YangParserListenerImpl extends YangParserBaseListener {
             if (prefix.equals(moduleQName.getPrefix())) {
                 typeQName = QName.create(moduleQName, name);
             } else {
-                typeQName = new QName(null, null, prefix, name);
+                typeQName = QName.create(QNameModule.create(null, null), prefix, name);
             }
         } else {
             typeQName = QName.create(moduleQName, typeName);
@@ -1027,7 +1028,7 @@ public final class YangParserListenerImpl extends YangParserBaseListener {
         final String e0 = splittedElement.next();
         final QName nodeType;
         if (splittedElement.hasNext()) {
-            nodeType = new QName(moduleQName.getNamespace(), moduleQName.getRevision(), e0, splittedElement.next());
+            nodeType = QName.create(moduleQName.getModule(), e0, splittedElement.next());
         } else {
             nodeType = QName.create(moduleQName, e0);
         }
@@ -1039,7 +1040,7 @@ public final class YangParserListenerImpl extends YangParserBaseListener {
                 final Iterator<String> it = splittedName.iterator();
 
                 if (Iterables.size(splittedName) == 2) {
-                    qname = new QName(null, null, it.next(), it.next());
+                    qname = QName.create(QNameModule.create(null, null), it.next(), it.next());
                 } else {
                     qname = QName.create(moduleQName, it.next());
                 }
index 4d31c1a2e080d89a9fbe5e296f55b242dfe23dac..5e29a76719b045fdbf60f6620dbb5610b1b9b2ad 100644 (file)
@@ -12,21 +12,13 @@ import static org.junit.Assert.assertEquals;
 import java.util.Set;
 import org.junit.Test;
 import org.opendaylight.yangtools.yang.model.api.Module;
-import org.opendaylight.yangtools.yang.model.api.SchemaContext;
-import org.opendaylight.yangtools.yang.model.parser.api.YangModelParser;
 
 public class TwoRevisionsTest {
 
     @Test
     public void testTwoRevisions() throws Exception {
-        YangModelParser parser = new YangParserImpl();
-
         Set<Module> modules = TestUtils.loadModules(getClass().getResource("/ietf").toURI());
         assertEquals(2, TestUtils.findModules(modules, "network-topology").size());
-
-        SchemaContext schemaContext = parser.resolveSchemaContext(modules);
-        assertEquals(2, TestUtils.findModules(schemaContext.getModules(), "network-topology").size());
-
     }
 
 }
index ac7099085e740c9417a273a7968c583b22983b1f..41d76c39972cd6792379edbdcc114ef909ade167 100644 (file)
@@ -163,7 +163,7 @@ public class YangParserNegativeTest {
             }
         } catch (YangParseException e) {
             String expected = "Error in module 'typedef' at line 10: typedef with same name 'int-ext' already declared at line 6.";
-            assertTrue(e.getMessage().contains("'typedef' at line 10: typedef with same name 'int-ext' already declared at line 6."));
+            assertEquals(expected, e.getMessage());
         }
     }
 
@@ -241,4 +241,18 @@ public class YangParserNegativeTest {
         }
     }
 
+    @Test
+    public void testInvalidListKeyDefinition() throws Exception {
+        File yang1 = new File(getClass().getResource("/negative-scenario/invalid-list-key-def.yang").toURI());
+        try {
+            try (InputStream stream1 = new FileInputStream(yang1)) {
+                TestUtils.loadModule(stream1);
+                fail("YangParseException should by thrown");
+            }
+        } catch (YangParseException e) {
+            String expected = "Error in module 'invalid-list-key-def' at line 6: Failed to resolve list key for name rib-id";
+            assertEquals(expected, e.getMessage());
+        }
+    }
+
 }
index ee2d7facbee4ceb61460ed723633f3849ce2aceb..ea33db06c1f95fe97c67fb3bfa0801ecdcd89653 100644 (file)
@@ -12,6 +12,7 @@ import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
 
+import com.google.common.base.Optional;
 import java.net.URI;
 import java.net.URISyntaxException;
 import java.util.ArrayList;
@@ -130,13 +131,17 @@ public class RefineHolderTest {
     @Test
     public void testMustEqualsBranch() {
         assertEquals("rh should equal to rh1", rh, rh1);
-        rh1.setMust(new MustDefinitionImpl("mustStr1", "description1", "reference1", "errorAppTag1", "errorMessage1"));
+        rh1.setMust(MustDefinitionImpl.create("mustStr1", Optional.of("description1"), Optional.of("reference1"),
+                Optional.of("errorAppTag1"), Optional.of("errorMessage1")));
         assertFalse("rh shouldn't equal to rh1", rh.equals(rh1));
-        rh.setMust(new MustDefinitionImpl("mustStr1", "description1", "reference1", "errorAppTag1", "errorMessage1"));
+        rh.setMust(MustDefinitionImpl.create("mustStr1", Optional.of("description1"), Optional.of("reference1"),
+                Optional.of("errorAppTag1"), Optional.of("errorMessage1")));
         assertEquals("rh should equal to rh1", rh, rh1);
-        rh.setMust(new MustDefinitionImpl("mustStr", "description", "reference", "errorAppTag", "errorMessage"));
+        rh.setMust(MustDefinitionImpl.create("mustStr", Optional.of("description"), Optional.of("reference"),
+                Optional.of("errorAppTag"), Optional.of("errorMessage")));
         assertFalse("rh shouldn't equal to rh1", rh.equals(rh1));
-        rh1.setMust(new MustDefinitionImpl("mustStr", "description", "reference", "errorAppTag", "errorMessage"));
+        rh1.setMust(MustDefinitionImpl.create("mustStr", Optional.of("description"), Optional.of("reference"),
+                Optional.of("errorAppTag"), Optional.of("errorMessage")));
     }
 
     @Test
diff --git a/yang/yang-parser-impl/src/test/resources/negative-scenario/invalid-list-key-def.yang b/yang/yang-parser-impl/src/test/resources/negative-scenario/invalid-list-key-def.yang
new file mode 100644 (file)
index 0000000..6fb0a66
--- /dev/null
@@ -0,0 +1,14 @@
+module invalid-list-key-def {
+    yang-version 1;
+    namespace "invalid:list:key:def";
+    prefix "p";
+
+    list application-map {
+        key "rib-id";
+
+        leaf bgp-id {
+            type string;
+        }
+    }
+
+}