Merge "While the controller is starting up, we see the following info messages which...
authorTony Tkacik <ttkacik@cisco.com>
Mon, 21 Jul 2014 07:19:17 +0000 (07:19 +0000)
committerGerrit Code Review <gerrit@opendaylight.org>
Mon, 21 Jul 2014 07:19:17 +0000 (07:19 +0000)
81 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/LazyGeneratedCodecRegistry.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-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/test/java/org/opendaylight/yangtools/sal/java/api/generator/test/TypedefCompilationTest.java
code-generator/binding-java-api-generator/src/test/resources/compilation/typedef/foo.yang
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-binding/src/main/java/org/opendaylight/yangtools/yang/binding/BindingMapping.java
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/RpcResult.java
yang/yang-common/src/main/java/org/opendaylight/yangtools/yang/common/RpcResultBuilder.java [new file with mode: 0644]
yang/yang-common/src/test/java/org/opendaylight/yangtools/yang/common/RpcResultBuilderTest.java [new file with mode: 0644]
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/InstanceIdentifierForXmlCodec.java
yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/codec/xml/RandomPrefix.java [new file with mode: 0644]
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 [new file with mode: 0644]
yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/codec/xml/XmlUtils.java [new file with mode: 0644]
yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/SchemaUtils.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/main/java/org/opendaylight/yangtools/yang/data/impl/schema/tree/InMemoryDataTreeModification.java
yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/tree/InMemoryDataTreeSnapshot.java
yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/tree/RootModificationApplyOperation.java [new file with mode: 0644]
yang/yang-data-impl/src/test/java/org/opendaylight/yangtools/yang/data/impl/NodeUtilsTest.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/ModificationMetadataTreeTest.java
yang/yang-data-operations/src/main/java/org/opendaylight/yangtools/yang/data/operations/DataModificationException.java
yang/yang-model-api/src/main/java/org/opendaylight/yangtools/yang/model/api/DerivableSchemaNode.java [new file with mode: 0644]
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/SchemaContextUtil.java
yang/yang-model-util/src/main/java/org/opendaylight/yangtools/yang/model/util/SchemaNodeUtils.java [new file with mode: 0644]
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/api/DataSchemaNodeBuilder.java
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/builder/impl/AnyXmlBuilder.java
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/ChoiceBuilder.java
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/builder/impl/ChoiceCaseBuilder.java
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/builder/impl/ContainerSchemaNodeBuilder.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/GroupingBuilderImpl.java
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/builder/impl/LeafListSchemaNodeBuilder.java
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/builder/impl/LeafSchemaNodeBuilder.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/UnionTypeBuilder.java
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/builder/util/AbstractDocumentedDataNodeContainerBuilder.java
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/impl/SchemaContextImpl.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/GroupingTest.java
yang/yang-parser-impl/src/test/java/org/opendaylight/yangtools/yang/parser/impl/YangParserNegativeTest.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 b4837dc185efe2e1e0841149a6f4c5055f998b19..0e6a8e473cb217764e6d4ef7a712e69cbbc390ee 100644 (file)
@@ -11,7 +11,6 @@ import static com.google.common.base.Preconditions.checkArgument;
 import static com.google.common.base.Preconditions.checkNotNull;
 import static com.google.common.base.Preconditions.checkState;
 import static org.opendaylight.yangtools.binding.generator.util.BindingGeneratorUtil.computeDefaultSUID;
-import static org.opendaylight.yangtools.binding.generator.util.BindingGeneratorUtil.moduleNamespaceToPackageName;
 import static org.opendaylight.yangtools.binding.generator.util.BindingGeneratorUtil.packageNameForGeneratedType;
 import static org.opendaylight.yangtools.binding.generator.util.BindingGeneratorUtil.parseToValidParamName;
 import static org.opendaylight.yangtools.binding.generator.util.BindingTypes.DATA_OBJECT;
@@ -240,7 +239,7 @@ public class BindingGeneratorImpl implements BindingGenerator {
         if (!m.getChildNodes().isEmpty()) {
             final GeneratedTypeBuilder moduleType = moduleToDataType(m);
             genCtx.get(m).addModuleNode(moduleType);
-            final String basePackageName = moduleNamespaceToPackageName(m);
+            final String basePackageName = BindingMapping.getRootPackageName(m.getQNameModule());
             resolveDataSchemaNodes(m, basePackageName, moduleType, moduleType, m.getChildNodes());
         }
     }
@@ -336,7 +335,7 @@ public class BindingGeneratorImpl implements BindingGenerator {
     }
 
     private void processUsesAugments(final DataNodeContainer node, final Module module) {
-        final String basePackageName = moduleNamespaceToPackageName(module);
+        final String basePackageName = BindingMapping.getRootPackageName(module.getQNameModule());
         for (UsesNode usesNode : node.getUses()) {
             for (AugmentationSchema augment : usesNode.getAugmentations()) {
                 usesAugmentationToGenTypes(basePackageName, augment, module, usesNode, node);
@@ -365,7 +364,7 @@ public class BindingGeneratorImpl implements BindingGenerator {
         checkArgument(module.getName() != null, "Module name cannot be NULL.");
         checkState(module.getAugmentations() != null, "Augmentations Set cannot be NULL.");
 
-        final String basePackageName = moduleNamespaceToPackageName(module);
+        final String basePackageName = BindingMapping.getRootPackageName(module.getQNameModule());
         final List<AugmentationSchema> augmentations = resolveAugmentations(module);
         for (AugmentationSchema augment : augmentations) {
             augmentationToGenTypes(basePackageName, augment, module);
@@ -442,7 +441,7 @@ public class BindingGeneratorImpl implements BindingGenerator {
             return;
         }
 
-        final String basePackageName = moduleNamespaceToPackageName(module);
+        final String basePackageName = BindingMapping.getRootPackageName(module.getQNameModule());
         final GeneratedTypeBuilder interfaceBuilder = moduleTypeBuilder(module, "Service");
         interfaceBuilder.addImplementsType(Types.typeForClass(RpcService.class));
         for (RpcDefinition rpc : rpcDefinitions) {
@@ -512,7 +511,7 @@ public class BindingGeneratorImpl implements BindingGenerator {
 
         final GeneratedTypeBuilder listenerInterface = moduleTypeBuilder(module, "Listener");
         listenerInterface.addImplementsType(BindingTypes.NOTIFICATION_LISTENER);
-        final String basePackageName = moduleNamespaceToPackageName(module);
+        final String basePackageName = BindingMapping.getRootPackageName(module.getQNameModule());
 
         for (NotificationDefinition notification : notifications) {
             if (notification != null) {
@@ -550,7 +549,7 @@ public class BindingGeneratorImpl implements BindingGenerator {
      */
     private void allIdentitiesToGenTypes(final Module module, final SchemaContext context) {
         final Set<IdentitySchemaNode> schemaIdentities = module.getIdentities();
-        final String basePackageName = moduleNamespaceToPackageName(module);
+        final String basePackageName = BindingMapping.getRootPackageName(module.getQNameModule());
 
         if (schemaIdentities != null && !schemaIdentities.isEmpty()) {
             for (IdentitySchemaNode identity : schemaIdentities) {
@@ -593,7 +592,7 @@ public class BindingGeneratorImpl implements BindingGenerator {
             newType.setExtendsType(gto.toInstance());
         } else {
             final Module baseIdentityParentModule = SchemaContextUtil.findParentModule(context, baseIdentity);
-            final String returnTypePkgName = moduleNamespaceToPackageName(baseIdentityParentModule);
+            final String returnTypePkgName = BindingMapping.getRootPackageName(baseIdentityParentModule.getQNameModule());
             final String returnTypeName = BindingMapping.getClassName(baseIdentity.getQName());
             final GeneratedTransferObject gto = new GeneratedTOBuilderImpl(returnTypePkgName, returnTypeName)
                     .toInstance();
@@ -635,7 +634,7 @@ public class BindingGeneratorImpl implements BindingGenerator {
      *
      */
     private void groupingsToGenTypes(final Module module, final Collection<GroupingDefinition> groupings) {
-        final String basePackageName = moduleNamespaceToPackageName(module);
+        final String basePackageName = BindingMapping.getRootPackageName(module.getQNameModule());
         final List<GroupingDefinition> groupingsSortedByDependencies = new GroupingDefinitionDependencySort()
                 .sort(groupings);
         for (GroupingDefinition grouping : groupingsSortedByDependencies) {
@@ -711,7 +710,7 @@ public class BindingGeneratorImpl implements BindingGenerator {
      */
     private GeneratedTypeBuilder moduleTypeBuilder(final Module module, final String postfix) {
         checkArgument(module != null, "Module reference cannot be NULL.");
-        final String packageName = moduleNamespaceToPackageName(module);
+        final String packageName = BindingMapping.getRootPackageName(module.getQNameModule());
         final String moduleName = BindingMapping.getClassName(module.getName()) + postfix;
         return new GeneratedTypeBuilderImpl(packageName, moduleName);
     }
@@ -1333,7 +1332,7 @@ public class BindingGeneratorImpl implements BindingGenerator {
                 final int length = Iterables.size(splittedElement);
                 if (length == 1) {
                     identity = findIdentityByName(module.getIdentities(), iterator.next());
-                    basePackageName = moduleNamespaceToPackageName(module);
+                    basePackageName = BindingMapping.getRootPackageName(module.getQNameModule());
                 } else if (length == 2) {
                     String prefix = iterator.next();
                     final Module dependentModule = findModuleFromImports(module.getImports(), prefix);
@@ -1342,7 +1341,7 @@ public class BindingGeneratorImpl implements BindingGenerator {
                                 + prefix);
                     }
                     identity = findIdentityByName(dependentModule.getIdentities(), iterator.next());
-                    basePackageName = moduleNamespaceToPackageName(dependentModule);
+                    basePackageName = BindingMapping.getRootPackageName(dependentModule.getQNameModule());
                 } else {
                     throw new IllegalArgumentException("Failed to process context-reference: unknown identity "
                             + nodeParam);
index 68685792593181f5beeb6d61e7dd91ec37b3f392..c890252a3fb00808dec50e1b54cd6018bea1e603 100644 (file)
@@ -37,6 +37,7 @@ import org.opendaylight.yangtools.yang.binding.Augmentable;
 import org.opendaylight.yangtools.yang.binding.Augmentation;
 import org.opendaylight.yangtools.yang.binding.BaseIdentity;
 import org.opendaylight.yangtools.yang.binding.BindingCodec;
+import org.opendaylight.yangtools.yang.binding.BindingMapping;
 import org.opendaylight.yangtools.yang.binding.DataContainer;
 import org.opendaylight.yangtools.yang.binding.DataObject;
 import org.opendaylight.yangtools.yang.binding.Identifier;
@@ -1292,9 +1293,14 @@ class LazyGeneratedCodecRegistry implements //
 
         @Override
         public Class<?> deserialize(final QName input) {
+            if(input == null) {
+                return null;
+            }
             Type type = qnamesToIdentityMap.get(input);
             if (type == null) {
-                throw new IllegalArgumentException( "Invalid value \"" + input + "\"." );
+                String packageName = BindingMapping.getRootPackageName(input);
+                String className = BindingMapping.getClassName(input);
+                type = new ReferencedTypeImpl(packageName, className);
             }
             ReferencedTypeImpl typeref = new ReferencedTypeImpl(type.getPackageName(), type.getName());
             WeakReference<Class> softref = typeToClass.get(typeref);
@@ -1348,8 +1354,7 @@ class LazyGeneratedCodecRegistry implements //
             if (qname != null) {
                 return qname;
             }
-            ConcreteType typeref = Types.typeForClass(input);
-            qname = typeToQname.get(typeref);
+            qname = BindingReflections.findQName(input);
             if (qname != null) {
                 identityQNames.put(input, qname);
             }
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 d5ec8b202ffe4abd7ed5d4de8ad4c0146fdb4687..0b7e071fa8452696d8262416dc7f3f1136bb1b47 100644 (file)
@@ -8,21 +8,20 @@
 package org.opendaylight.yangtools.binding.generator.util;
 
 import com.google.common.base.CharMatcher;
-import com.google.common.base.Splitter;
 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.text.SimpleDateFormat;
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.Collections;
 import java.util.Comparator;
 import java.util.Iterator;
 import java.util.List;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
+
 import org.opendaylight.yangtools.sal.binding.model.api.AccessModifier;
 import org.opendaylight.yangtools.sal.binding.model.api.Restrictions;
 import org.opendaylight.yangtools.sal.binding.model.api.Type;
@@ -32,6 +31,7 @@ import org.opendaylight.yangtools.sal.binding.model.api.type.builder.MethodSigna
 import org.opendaylight.yangtools.sal.binding.model.api.type.builder.TypeMemberBuilder;
 import org.opendaylight.yangtools.yang.binding.BindingMapping;
 import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.common.QNameModule;
 import org.opendaylight.yangtools.yang.model.api.Module;
 import org.opendaylight.yangtools.yang.model.api.SchemaPath;
 import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
@@ -51,19 +51,6 @@ import org.opendaylight.yangtools.yang.model.util.ExtendedType;
  */
 public final class BindingGeneratorUtil {
 
-    private static final ThreadLocal<SimpleDateFormat> DATE_FORMAT = new ThreadLocal<SimpleDateFormat>() {
-
-        @Override
-        protected SimpleDateFormat initialValue() {
-            return new SimpleDateFormat("yyMMdd");
-        }
-
-        @Override
-        public void set(final SimpleDateFormat value) {
-            throw new UnsupportedOperationException();
-        }
-    };
-
     /**
      * Impossible to instantiate this class. All of the methods or attributes
      * are static.
@@ -74,45 +61,44 @@ public final class BindingGeneratorUtil {
     /**
      * Pre-compiled replacement pattern.
      */
-    private static final Pattern COLON_SLASH_SLASH = Pattern.compile("://", Pattern.LITERAL);
-    private static final String QUOTED_DOT = Matcher.quoteReplacement(".");
-    private static final Splitter DOT_SPLITTER = Splitter.on('.');
     private static final CharMatcher DOT_MATCHER = CharMatcher.is('.');
     private static final CharMatcher DASH_COLON_MATCHER = CharMatcher.anyOf("-:");
 
-    /**
-     * Converts string <code>packageName</code> to valid JAVA package name.
-     *
-     * If some words of package name are digits of JAVA reserved words they are
-     * prefixed with underscore character.
-     *
-     * @param packageName
-     *            string which contains words separated by point.
-     * @return package name which contains words separated by point.
-     */
-    private static String validateJavaPackage(final String packageName) {
-        if (packageName == null) {
-            return null;
+    private static final Restrictions EMPTY_RESTRICTIONS = new Restrictions() {
+        @Override
+        public List<LengthConstraint> getLengthConstraints() {
+            return Collections.emptyList();
         }
 
-        final StringBuilder builder = new StringBuilder();
-        boolean first = true;
+        @Override
+        public List<PatternConstraint> getPatternConstraints() {
+            return Collections.emptyList();
+        }
 
-        for (String p : DOT_SPLITTER.split(packageName.toLowerCase())) {
-            if (first) {
-                first = false;
-            } else {
-                builder.append('.');
-            }
+        @Override
+        public List<RangeConstraint> getRangeConstraints() {
+            return Collections.emptyList();
+        }
 
-            if (Character.isDigit(p.charAt(0)) || BindingMapping.JAVA_RESERVED_WORDS.contains(p)) {
-                builder.append('_');
-            }
-            builder.append(p);
+        @Override
+        public boolean isEmpty() {
+            return true;
         }
+    };
 
-        return builder.toString();
-    }
+    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.
@@ -149,43 +135,11 @@ public final class BindingGeneratorUtil {
      * @throws IllegalArgumentException
      *             if the revision date of the <code>module</code> equals
      *             <code>null</code>
+     * @deprecated USe {@link BindingMapping#getRootPackageName(QNameModule)} with {@link Module#getQNameModule()}.
      */
+    @Deprecated
     public static String moduleNamespaceToPackageName(final Module module) {
-        final StringBuilder packageNameBuilder = new StringBuilder();
-
-        if (module.getRevision() == null) {
-            throw new IllegalArgumentException("Module " + module.getName() + " does not specify revision date!");
-        }
-        packageNameBuilder.append(BindingMapping.PACKAGE_PREFIX);
-        packageNameBuilder.append('.');
-
-        String namespace = module.getNamespace().toString();
-        namespace = COLON_SLASH_SLASH.matcher(namespace).replaceAll(QUOTED_DOT);
-
-        final char[] chars = namespace.toCharArray();
-        for (int i = 0; i < chars.length; ++i) {
-            switch (chars[i]) {
-            case '/':
-            case ':':
-            case '-':
-            case '@':
-            case '$':
-            case '#':
-            case '\'':
-            case '*':
-            case '+':
-            case ',':
-            case ';':
-            case '=':
-                chars[i] = '.';
-            }
-        }
-
-        packageNameBuilder.append(chars);
-        packageNameBuilder.append(".rev");
-        packageNameBuilder.append(DATE_FORMAT.get().format(module.getRevision()));
-
-        return validateJavaPackage(packageNameBuilder.toString());
+        return BindingMapping.getRootPackageName(module.getQNameModule());
     }
 
     public static String packageNameForGeneratedType(final String basePackageName, final SchemaPath schemaPath) {
@@ -230,10 +184,10 @@ public final class BindingGeneratorUtil {
         for (int i = 0; i < traversalSteps; ++i) {
             builder.append('.');
             String nodeLocalName = iterator.next().getLocalName();
-
+            // FIXME: Collon ":" is invalid in node local name as per RFC6020, identifier statement.
             builder.append(DASH_COLON_MATCHER.replaceFrom(nodeLocalName, '.'));
         }
-        return validateJavaPackage(builder.toString());
+        return BindingMapping.normalizePackageName(builder.toString());
     }
 
     /**
@@ -262,7 +216,7 @@ public final class BindingGeneratorUtil {
 
         final StringBuilder builder = new StringBuilder();
         builder.append(basePackageName);
-        return validateJavaPackage(builder.toString());
+        return BindingMapping.normalizePackageName(builder.toString());
     }
 
     /**
@@ -374,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();
@@ -382,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());
@@ -417,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() {
@@ -468,7 +424,7 @@ public final class BindingGeneratorUtil {
             }
             @Override
             public boolean isEmpty() {
-                return range.isEmpty() && pattern.isEmpty() && length.isEmpty();
+                return false;
             }
         };
     }
index 5b16fa7eec7432b8ce85b6a1a2fab4869d09ec45..215523672e66c2a8e14c4573f1059c53a49933dd 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>
index 672d4b648e94eea593dbd1d04a8d6415bcefa751..c1b1074d5d45b06e0db40be6181d250030ed27e0 100644 (file)
@@ -178,7 +178,7 @@ abstract class BaseTemplate {
                 Â«generateLengthRestriction(returnType, restrictions, paramName, isNestedType)»
             Â«ENDIF»
             Â«IF !restrictions.rangeConstraints.empty»
-                Â«generateRangeRestriction(returnType, restrictions, paramName, isNestedType)»
+                Â«generateRangeRestriction(returnType, paramName, isNestedType)»
             Â«ENDIF»
         Â«ENDIF»
     '''
@@ -199,12 +199,11 @@ abstract class BaseTemplate {
         }
     '''
 
-    def private generateRangeRestriction(Type returnType, Restrictions restrictions, String paramName, boolean isNestedType) '''
-        Â«val clazz = restrictions.rangeConstraints.iterator.next.min.class»
+    def private generateRangeRestriction(Type returnType, String paramName, boolean isNestedType) '''
         if («paramName» != null) {
-            Â«printRangeConstraint(returnType, clazz, paramName, isNestedType)»
+            Â«printRangeConstraint(returnType, paramName, isNestedType)»
             boolean isValidRange = false;
-            for («Range.importedName»<«clazz.importedNumber»> r : Â«IF isNestedType»«returnType.importedName».«ENDIF»range()) {
+            for («Range.importedName»<«returnType.importedNumber»> r : Â«IF isNestedType»«returnType.importedName».«ENDIF»range()) {
                 if (r.contains(_constraint)) {
                     isValidRange = true;
                 }
@@ -223,22 +222,22 @@ abstract class BaseTemplate {
         Â«clazz.importedNumber» _constraint = Â«clazz.importedNumber».valueOf(«paramName»«IF isNestedType».getValue()«ENDIF».length«IF !isArray»()«ENDIF»);
     '''
 
-    def printRangeConstraint(Type returnType, Class<? extends Number> clazz, String paramName, boolean isNestedType) '''
-        Â«IF clazz.canonicalName.equals(BigDecimal.canonicalName)»
-            Â«clazz.importedNumber» _constraint = new Â«clazz.importedNumber»(«paramName»«IF isNestedType».getValue()«ENDIF».toString());
+    def printRangeConstraint(Type returnType, String paramName, boolean isNestedType) '''
+        Â«IF BigDecimal.canonicalName.equals(returnType.fullyQualifiedName)»
+            Â«BigDecimal.importedName» _constraint = new Â«BigDecimal.importedName»(«paramName»«IF isNestedType».getValue()«ENDIF».toString());
         Â«ELSE»
             Â«IF isNestedType»
                 Â«val propReturnType = findProperty(returnType as GeneratedTransferObject, "value").returnType»
                 Â«IF propReturnType.fullyQualifiedName.equals(BigInteger.canonicalName)»
-                    Â«clazz.importedNumber» _constraint = Â«paramName».getValue();
+                    Â«BigInteger.importedName» _constraint = Â«paramName».getValue();
                 Â«ELSE»
-                    Â«clazz.importedNumber» _constraint = Â«clazz.importedNumber».valueOf(«paramName».getValue());
+                    Â«BigInteger.importedName» _constraint = Â«BigInteger.importedName».valueOf(«paramName».getValue());
                 Â«ENDIF»
             Â«ELSE»
                 Â«IF returnType.fullyQualifiedName.equals(BigInteger.canonicalName)»
-                    Â«clazz.importedNumber» _constraint = Â«paramName»;
+                    Â«BigInteger.importedName» _constraint = Â«paramName»;
                 Â«ELSE»
-                    Â«clazz.importedNumber» _constraint = Â«clazz.importedNumber».valueOf(«paramName»);
+                    Â«BigInteger.importedName» _constraint = Â«BigInteger.importedName».valueOf(«paramName»);
                 Â«ENDIF»
             Â«ENDIF»
         Â«ENDIF»
@@ -271,15 +270,6 @@ abstract class BaseTemplate {
         Â«ENDIF»
     '''
 
-    def GeneratedProperty getPropByName(GeneratedType gt, String name) {
-        for (GeneratedProperty prop : gt.properties) {
-            if (prop.name.equals(name)) {
-                return prop;
-            }
-        }
-        return null;
-    }
-
     def getRestrictions(Type type) {
         var Restrictions restrictions = null
         if (type instanceof ConcreteType) {
@@ -347,15 +337,27 @@ abstract class BaseTemplate {
         return Â«varName»;
     '''
 
-    def protected generateRangeMethod(String methodName, Type type, String className, String varName) '''
-        Â«val Restrictions restrictions = type.restrictions»
+    def protected generateRangeMethod(String methodName, Restrictions restrictions, Type returnType, String className, String varName) '''
         Â«IF restrictions != null && !(restrictions.rangeConstraints.empty)»
-            Â«val numberClass = restrictions.rangeConstraints.iterator.next.min.class»
-            public static Â«List.importedName»<«Range.importedName»<«numberClass.importedNumber»>> Â«methodName»() {
-                Â«IF numberClass.equals(typeof(BigDecimal))»
-                    Â«rangeMethodBody(restrictions, numberClass, className, varName)»
+            Â«val number = returnType.importedNumber»
+            public static Â«List.importedName»<«Range.importedName»<«number»>> Â«methodName»() {
+                Â«IF returnType.fullyQualifiedName.equals(BigDecimal.canonicalName)»
+                    Â«rangeMethodBody(restrictions, BigDecimal, className, varName)»
+                Â«ELSE»
+                    Â«rangeMethodBody(restrictions, BigInteger, className, varName)»
+                Â«ENDIF»
+            }
+        Â«ENDIF»
+    '''
+
+    def protected generateRangeMethod(String methodName, Restrictions restrictions, String className, String varName, Iterable<GeneratedProperty> properties) '''
+        Â«IF restrictions != null && !(restrictions.rangeConstraints.empty)»
+            Â«val returnType = properties.iterator.next.returnType»
+            public static Â«List.importedName»<«Range.importedName»<«returnType.importedNumber»>> Â«methodName»() {
+                Â«IF returnType.fullyQualifiedName.equals(BigDecimal.canonicalName)»
+                    Â«rangeMethodBody(restrictions, BigDecimal, className, varName)»
                 Â«ELSE»
-                    Â«rangeMethodBody(restrictions, typeof(BigInteger), className, varName)»
+                    Â«rangeMethodBody(restrictions, BigInteger, className, varName)»
                 Â«ENDIF»
             }
         Â«ENDIF»
@@ -383,6 +385,13 @@ abstract class BaseTemplate {
         return BigInteger.importedName
     }
 
+    def protected String importedNumber(Type clazz) {
+        if (clazz.fullyQualifiedName.equals(BigDecimal.canonicalName)) {
+            return BigDecimal.importedName
+        }
+        return BigInteger.importedName
+    }
+
     def private String numericValue(Class<? extends Number> clazz, Object numberValue) {
         val number = clazz.importedName;
         val value = numberValue.toString
index fbd198054a40310ecd6300ec79aa6e4c8af7f258..c97838ed02125b073a37d61ec53d00e2b72d5546 100644 (file)
@@ -405,12 +405,10 @@ class BuilderTemplate extends BaseTemplate {
                 Â«val restrictions = f.returnType.restrictions»
                 Â«IF !_final && restrictions != null»
                     Â«IF !(restrictions.lengthConstraints.empty)»
-                        Â«val clazz = restrictions.lengthConstraints.iterator.next.min.class»
-                        private static Â«List.importedName»<«Range.importedName»<«clazz.importedNumber»>> Â«f.fieldName»_length;
+                        private static Â«List.importedName»<«Range.importedName»<«f.returnType.importedNumber»>> Â«f.fieldName»_length;
                     Â«ENDIF»
                     Â«IF !(restrictions.rangeConstraints.empty)»
-                        Â«val clazz = restrictions.rangeConstraints.iterator.next.min.class»
-                        private static Â«List.importedName»<«Range.importedName»<«clazz.importedNumber»>> Â«f.fieldName»_range;
+                        private static Â«List.importedName»<«Range.importedName»<«f.returnType.importedNumber»>> Â«f.fieldName»_range;
                     Â«ENDIF»
                 Â«ENDIF»
             Â«ENDFOR»
@@ -438,7 +436,7 @@ class BuilderTemplate extends BaseTemplate {
                 return this;
             }
             Â«generateLengthMethod(length, field.returnType, type.name+BUILDER, length)»
-            Â«generateRangeMethod(range, field.returnType, type.name+BUILDER, range)»
+            Â«generateRangeMethod(range, field.returnType.restrictions, field.returnType, type.name+BUILDER, range)»
         Â«ENDFOR»
         Â«IF augmentField != null»
 
@@ -466,7 +464,7 @@ class BuilderTemplate extends BaseTemplate {
                 Â«generateLengthRestriction(type, paramName, lengthGetter, isNestedType, isArray)»
             Â«ENDIF»
             Â«IF !restrictions.rangeConstraints.empty»
-                Â«generateRangeRestriction(type, paramName, rangeGetter, isNestedType, isArray)»
+                Â«generateRangeRestriction(type, paramName, rangeGetter, isNestedType)»
             Â«ENDIF»
         Â«ENDIF»
     '''
@@ -488,13 +486,11 @@ class BuilderTemplate extends BaseTemplate {
         }
     '''
 
-    def private generateRangeRestriction(Type type, String paramName, String getterName, boolean isNestedType, boolean isArray) '''
-        Â«val restrictions = type.getRestrictions»
+    def private generateRangeRestriction(Type type, String paramName, String getterName, boolean isNestedType) '''
         if («paramName» != null) {
-            Â«val clazz = restrictions.rangeConstraints.iterator.next.min.class»
-            Â«printRangeConstraint(type, clazz, paramName, isNestedType)»
+            Â«printRangeConstraint(type, paramName, isNestedType)»
             boolean isValidRange = false;
-            for («Range.importedName»<«clazz.importedNumber»> r : Â«getterName»()) {
+            for («Range.importedName»<«type.importedNumber»> r : Â«getterName»()) {
                 if (r.contains(_constraint)) {
                     isValidRange = true;
                 }
index 85b2df5d6243ad2f765ffae0943d1e91a8203f9e..eb5b94c5da742df982350567d99606116e351d2a 100644 (file)
@@ -127,7 +127,7 @@ class ClassTemplate extends BaseTemplate {
 
             Â«generateLengthMethod("length", genTO, genTO.importedName, "_length")»
 
-            Â«generateRangeMethod("range", genTO, genTO.importedName, "_range")»
+            Â«generateRangeMethod("range", genTO.restrictions, genTO.importedName, "_range", allProperties)»
 
         }
     '''
@@ -366,13 +366,14 @@ class ClassTemplate extends BaseTemplate {
      */
     def protected generateFields() '''
         Â«IF restrictions != null»
-            Â«IF !(restrictions.lengthConstraints.empty)»
-                Â«val numberClass = restrictions.lengthConstraints.iterator.next.min.class»
-                private static Â«List.importedName»<«Range.importedName»<«numberClass.importedNumber»>> _length;
-            Â«ENDIF»
-            Â«IF !(restrictions.rangeConstraints.empty)»
-                Â«val numberClass = restrictions.rangeConstraints.iterator.next.min.class»
-                private static Â«List.importedName»<«Range.importedName»<«numberClass.importedNumber»>> _range;
+            Â«val prop = getPropByName("value")»
+            Â«IF prop != null»
+                Â«IF !(restrictions.lengthConstraints.empty)»
+                    private static Â«List.importedName»<«Range.importedName»<«prop.returnType.importedNumber»>> _length;
+                Â«ENDIF»
+                Â«IF !(restrictions.rangeConstraints.empty)»
+                    private static Â«List.importedName»<«Range.importedName»<«prop.returnType.importedNumber»>> _range;
+                Â«ENDIF»
             Â«ENDIF»
         Â«ENDIF»
         Â«IF !properties.empty»
@@ -382,7 +383,6 @@ class ClassTemplate extends BaseTemplate {
         Â«ENDIF»
     '''
 
-
     /**
      * Template method which generates the method <code>hashCode()</code>.
      *
@@ -444,4 +444,13 @@ class ClassTemplate extends BaseTemplate {
         Â«ENDIF»
     '''
 
+    def GeneratedProperty getPropByName(String name) {
+        for (GeneratedProperty prop : allProperties) {
+            if (prop.name.equals(name)) {
+                return prop;
+            }
+        }
+        return null;
+    }
+
 }
index f8b2eda1a662f0831e56393b2011b7cc9cd14e35..a80133d17368b05540179809d2bdab182248e729 100644 (file)
@@ -91,7 +91,7 @@ public class TypedefCompilationTest extends BaseCompilationTest {
         assertTrue(unionExt2.exists());
         assertTrue(unionExt3.exists());
         assertTrue(unionExt4.exists());
-        assertFilesCount(parent, 30);
+        assertFilesCount(parent, 31);
 
         // Test if sources are compilable
         testCompilation(sourcesOutputDir, compiledOutputDir);
@@ -102,6 +102,7 @@ public class TypedefCompilationTest extends BaseCompilationTest {
         Class<?> int32Ext1Class = Class.forName(pkg + ".Int32Ext1", true, loader);
         Class<?> int32Ext2Class = Class.forName(pkg + ".Int32Ext2", true, loader);
         Class<?> myDecimalTypeClass = Class.forName(pkg + ".MyDecimalType", true, loader);
+        Class<?> myDecimalType2Class = Class.forName(pkg + ".MyDecimalType2", true, loader);
         Class<?> stringExt1Class = Class.forName(pkg + ".StringExt1", true, loader);
         Class<?> stringExt2Class = Class.forName(pkg + ".StringExt2", true, loader);
         Class<?> stringExt3Class = Class.forName(pkg + ".StringExt3", true, loader);
@@ -264,6 +265,30 @@ public class TypedefCompilationTest extends BaseCompilationTest {
         obj = expectedConstructor.newInstance(new BigDecimal("3.14"));
         assertEquals(obj, defInst.invoke(null, "3.14"));
 
+        // typedef my-decimal-type2
+        assertFalse(myDecimalType2Class.isInterface());
+        assertContainsField(myDecimalType2Class, VAL, BigDecimal.class);
+        assertContainsField(myDecimalType2Class, RANGE, List.class);
+        assertContainsFieldWithValue(myDecimalType2Class, "serialVersionUID", Long.TYPE, -672265764962082714L, BigDecimal.class);
+        assertEquals(3, myDecimalType2Class.getDeclaredFields().length);
+        assertContainsMethod(myDecimalType2Class, BigDecimal.class, "getValue");
+        expectedConstructor = assertContainsConstructor(myDecimalType2Class, BigDecimal.class);
+        assertContainsConstructor(myDecimalType2Class, myDecimalType2Class);
+        assertEquals(2, myDecimalType2Class.getDeclaredConstructors().length);
+        assertContainsMethod(myDecimalType2Class, BigDecimal.class, GET_VAL);
+        assertContainsDefaultMethods(myDecimalType2Class);
+        defInst = assertContainsMethod(myDecimalType2Class, myDecimalType2Class, "getDefaultInstance", String.class);
+        assertContainsGetLengthOrRange(myDecimalType2Class, false);
+        assertEquals(6, myDecimalType2Class.getDeclaredMethods().length);
+
+        List<Range<BigDecimal>> decimal2RangeConstraints = new ArrayList<>();
+        decimal2RangeConstraints.add(Range.closed(new BigDecimal("0"), new BigDecimal("1")));
+        arg = new BigDecimal("1.4");
+        expectedMsg = String.format("Invalid range: %s, expected: %s.", arg, decimal2RangeConstraints);
+        assertContainsRestrictionCheck(expectedConstructor, expectedMsg, arg);
+        obj = expectedConstructor.newInstance(new BigDecimal("0.14"));
+        assertEquals(obj, defInst.invoke(null, "0.14"));
+
         // typedef union-ext1
         assertFalse(unionExt1Class.isInterface());
         assertContainsField(unionExt1Class, "_int16", Short.class);
index 19d2eb1d5ee807111e24e2f392d02358f1b76340..911096606efee2258902f48d7947ec4b56677297 100644 (file)
@@ -95,6 +95,13 @@ module foo {
         }
     }
 
+    typedef my-decimal-type2 {
+        type decimal64 {
+            fraction-digits 18;
+            range "0..1";
+        }
+    }
+
     typedef union-ext1 {
         type union {
             type int16 {
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 968990aaa916dfb49232d522e8fbb80fce5e8e09..ee51ec6ef4ea9031f5c757b4b98aca739a977ee7 100644 (file)
 
     <feature name='yangtools-all' version='${project.version}'>
         <feature version='${project.version}'>yangtools-models</feature>
-        <feature version='${project.version}'>yangtools-binding</feature>
+        <feature version='${project.version}'>yangtools-data-binding</feature>
         <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.model/ietf-topology/${ietf.topology.version}</bundle>
        </feature>
 
-    <feature name='yangtools-binding' version='${project.version}'>
+    <feature name='yangtools-data-binding' version='${project.version}'>
         <feature version='${project.version}'>yangtools-concepts</feature>
+        <feature version='${project.version}'>yangtools-binding</feature>
         <bundle>mvn:org.opendaylight.yangtools.thirdparty/antlr4-runtime-osgi-nohead/${antlr4.version}</bundle>
         <bundle>mvn:commons-io/commons-io/${commons.io.version}</bundle>
-        <bundle>mvn:org.opendaylight.yangtools/yang-binding/${project.version}</bundle>
         <bundle>mvn:org.opendaylight.yangtools/yang-data-api/${project.version}</bundle>
         <bundle>mvn:org.opendaylight.yangtools/yang-data-impl/${project.version}</bundle>
         <bundle>mvn:org.opendaylight.yangtools/yang-data-json/${project.version}</bundle>
         <bundle>mvn:org.opendaylight.yangtools/yang-parser-api/${project.version}</bundle>
     </feature>
 
+    <feature name='yangtools-binding' version='${project.version}'>
+        <feature version='${project.version}'>yangtools-concepts</feature>
+        <bundle>mvn:com.google.guava/guava/${guava.version}</bundle>
+        <bundle>mvn:org.opendaylight.yangtools/yang-binding/${project.version}</bundle>
+        <bundle>mvn:org.opendaylight.yangtools/util/${project.version}</bundle>
+    </feature>
+
     <feature name='yangtools-concepts' version='${project.version}'>
         <bundle>mvn:org.opendaylight.yangtools/concepts/${project.version}</bundle>
         <bundle>mvn:org.opendaylight.yangtools/yang-common/${project.version}</bundle>
-        <bundle>wrap:mvn:com.google.guava/guava/${guava.version}</bundle>
-        <bundle>wrap:mvn:org.eclipse.xtend/org.eclipse.xtend.lib/${xtend.version}</bundle>
-        <bundle>wrap:mvn:org.eclipse.xtext/org.eclipse.xtext.xbase.lib/${xtend.version}</bundle>
+        <bundle>mvn:com.google.guava/guava/${guava.version}</bundle>
     </feature>
     <feature name="yangtools-common" version='${project.version}'>
         <bundle>mvn:org.opendaylight.yangtools/util/${project.version}</bundle>
@@ -55,7 +61,7 @@
         <bundle>mvn:org.opendaylight.yangtools/object-cache-noop/${project.version}</bundle>
     </feature>
     <feature name='yangtools-binding-generator' version='${project.version}'>
-        <feature version='${project.version}'>yangtools-binding</feature>
+        <feature version='${project.version}'>yangtools-data-binding</feature>
         <bundle>mvn:org.javassist/javassist/${javassist.version}</bundle>
         <bundle>mvn:org.apache.commons/commons-lang3/${commons.lang3.version}</bundle>
         <bundle>mvn:org.opendaylight.yangtools/binding-generator-api/${project.version}</bundle>
         <bundle>mvn:org.opendaylight.yangtools/binding-generator-util/${project.version}</bundle>
         <bundle>mvn:org.opendaylight.yangtools/binding-model-api/${project.version}</bundle>
         <bundle>mvn:org.opendaylight.yangtools/binding-type-provider/${project.version}</bundle>
-
+        <bundle>wrap:mvn:org.eclipse.xtend/org.eclipse.xtend.lib/${xtend.version}</bundle>
+        <bundle>wrap:mvn:org.eclipse.xtext/org.eclipse.xtext.xbase.lib/${xtend.version}</bundle>
+        <bundle>mvn:org.opendaylight.yangtools/yang-model-api/${project.version}</bundle>
+        <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 f9bac0260bde451321f6d9a708fd84207e08ea09..ba8b6812e2c911156ef34db5a7fa9b05fa7093b5 100644 (file)
@@ -9,11 +9,17 @@ package org.opendaylight.yangtools.yang.binding;
 
 import static com.google.common.base.Preconditions.checkArgument;
 
+import java.text.SimpleDateFormat;
+import java.util.Set;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.common.QNameModule;
+
 import com.google.common.base.CharMatcher;
 import com.google.common.base.Splitter;
 import com.google.common.collect.ImmutableSet;
-import java.util.Set;
-import org.opendaylight.yangtools.yang.common.QName;
 
 public final class BindingMapping {
 
@@ -34,6 +40,9 @@ public final class BindingMapping {
 
     private static final Splitter CAMEL_SPLITTER = Splitter.on(CharMatcher.anyOf(" _.-").precomputed())
             .omitEmptyStrings().trimResults();
+    private static final Pattern COLON_SLASH_SLASH = Pattern.compile("://", Pattern.LITERAL);
+    private static final String QUOTED_DOT = Matcher.quoteReplacement(".");
+    private static final Splitter DOT_SPLITTER = Splitter.on('.');
 
     public static final String MODULE_INFO_CLASS_NAME = "$YangModuleInfoImpl";
     public static final String MODEL_BINDING_PROVIDER_CLASS_NAME = "$YangModelBindingProvider";
@@ -41,10 +50,89 @@ public final class BindingMapping {
     public static final String RPC_INPUT_SUFFIX = "Input";
     public static final String RPC_OUTPUT_SUFFIX = "Output";
 
+    private static final ThreadLocal<SimpleDateFormat> PACKAGE_DATE_FORMAT = new ThreadLocal<SimpleDateFormat>() {
+
+        @Override
+        protected SimpleDateFormat initialValue() {
+            return new SimpleDateFormat("yyMMdd");
+        }
+
+        @Override
+        public void set(final SimpleDateFormat value) {
+            throw new UnsupportedOperationException();
+        }
+    };
+
     private BindingMapping() {
         throw new UnsupportedOperationException("Utility class should not be instantiated");
     }
 
+    public static final String getRootPackageName(final QName module) {
+        return getRootPackageName(module.getModule());
+    }
+
+    public static final String getRootPackageName(final QNameModule module) {
+        checkArgument(module != null, "Module must not be null");
+        checkArgument(module.getRevision() != null, "Revision must not be null");
+        checkArgument(module.getNamespace() != null, "Namespace must not be null");
+        final StringBuilder packageNameBuilder = new StringBuilder();
+
+        packageNameBuilder.append(BindingMapping.PACKAGE_PREFIX);
+        packageNameBuilder.append('.');
+
+        String namespace = module.getNamespace().toString();
+        namespace = COLON_SLASH_SLASH.matcher(namespace).replaceAll(QUOTED_DOT);
+
+        final char[] chars = namespace.toCharArray();
+        for (int i = 0; i < chars.length; ++i) {
+            switch (chars[i]) {
+            case '/':
+            case ':':
+            case '-':
+            case '@':
+            case '$':
+            case '#':
+            case '\'':
+            case '*':
+            case '+':
+            case ',':
+            case ';':
+            case '=':
+                chars[i] = '.';
+            }
+        }
+
+        packageNameBuilder.append(chars);
+        packageNameBuilder.append(".rev");
+        packageNameBuilder.append(PACKAGE_DATE_FORMAT.get().format(module.getRevision()));
+        return normalizePackageName(packageNameBuilder.toString());
+
+    }
+
+    public static String normalizePackageName(final String packageName) {
+        if (packageName == null) {
+            return null;
+        }
+
+        final StringBuilder builder = new StringBuilder();
+        boolean first = true;
+
+        for (String p : DOT_SPLITTER.split(packageName.toLowerCase())) {
+            if (first) {
+                first = false;
+            } else {
+                builder.append('.');
+            }
+
+            if (Character.isDigit(p.charAt(0)) || BindingMapping.JAVA_RESERVED_WORDS.contains(p)) {
+                builder.append('_');
+            }
+            builder.append(p);
+        }
+
+        return builder.toString();
+    }
+
     public static final String getMethodName(final QName name) {
         checkArgument(name != null, "Name should not be null.");
         return getMethodName(name.getLocalName());
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..d2ccf637d78ec6096daeb56ddbf2a3b3380ffc76 100644 (file)
@@ -144,7 +144,7 @@ public final class QName implements Immutable, Serializable, Comparable<QName> {
      */
     @Deprecated
     public QName(final QName base, final String localName) {
-        this(base.getNamespace(), base.getRevision(), base.getPrefix(), localName);
+        this(base.getModule(), base.getPrefix(), localName);
     }
 
     /**
@@ -281,9 +281,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 d207791f2a64a68ff2aca14a5f4660427f3ed0ef..3645637b893af4ba9998922ff86e2f59186d5b4a 100644 (file)
 package org.opendaylight.yangtools.yang.common;
 
 /**
- *
- * Representation of Error in YANG enabled system.
- *
- * Which may be send / received by YANG modeled / enabled systems.
+ * Representation of an error.
  *
  */
 public interface RpcError {
 
+    public enum ErrorSeverity {
+        ERROR,
+        WARNING
+    }
+
+    public enum ErrorType {
+        /**
+         * Indicates an error occurred during transport of data, eg over the network.
+         */
+        TRANSPORT,
+
+        /**
+         * Indicates an error occurred during a remote procedure call.
+         */
+        RPC,
+
+        /**
+         * Indicates an error at a protocol layer, eg if invalid data was passed by the caller.
+         */
+        PROTOCOL,
+
+        /**
+         * Indicates an error occurred during internal processing.
+         */
+        APPLICATION
+    }
+
     /**
+     * Returns the error severity, as determined by the application reporting the error.
      *
-     * Returns error severity, as determined by component reporting the error.
-     *
-     * @return error severity
+     * @return an {@link ErrorSeverity} enum.
      */
     ErrorSeverity getSeverity();
 
     /**
-     *
-     * Returns a string identifying the error condition.
-     *
-     * @return string identifying the error condition.
+     * Returns a short string that identifies the general type of error condition.
+     * <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
+     * </pre>
+     * @return a string if available or null otherwise.
      */
     String getTag();
 
     /**
+     * Returns a short string that identifies the specific type of error condition as
+     * determined by the application reporting the error.
      *
-     * Returns a string identifying the data-model-specific or
-     * implementation-specific error condition, if one exists. This element will
-     * not be present if no appropriate application error-tag can be associated
-     * with a particular error condition. If a data-model-specific and an
-     * implementation-specific error-app-tag both exist, then the
-     * data-model-specific value MUST be used by the reporter.
-     *
-     * @return Returns a string identifying the data-model-specific or
-     *         implementation-specific error condition, or null if does not
-     *         exists.
+     * @return a string if available or null otherwise.
      */
     String getApplicationTag();
 
     /**
-     *
      * Returns a string suitable for human display that describes the error
-     * condition. This element will not be present if no appropriate message is
-     * provided for a particular error condition.
+     * condition.
      *
-     * @return returns an error description for human display.
+     * @return a message string.
      */
     String getMessage();
 
     /**
      *
-     * Contains protocol- or data-model-specific error content. This value may
-     * be not be present if no such error content is provided for a particular
-     * error condition.
-     *
-     * The list in Appendix A defines any mandatory error-info content for each
-     * error. After any protocol-mandated content, a data model definition MAY
-     * mandate that certain application-layer error information be included in
-     * the error-info container.
-     *
-     * An implementation MAY include additional information to provide extended
-     * and/or implementation- specific debugging information.
+     * Returns a string containing additional information to provide extended
+     * and/or implementation-specific debugging information.
      *
-     * @return
+     * @return a string if available or null otherwise.
      */
     String getInfo();
 
     /**
      *
-     * Return a cause if available.
+     * Returns an exception cause.
      *
-     * @return cause of this error, if error was triggered by exception.
+     * @return a Throwable if the error was triggered by exception, null otherwise.
      */
     Throwable getCause();
 
     /**
-     * Returns the conceptual layer that on which the error occurred.
+     * Returns the conceptual layer at which the error occurred.
      *
-     * @return the conceptual layer that on which the error occurred.
+     * @return an {@link ErrorType} enum.
      */
     ErrorType getErrorType();
-
-    public enum ErrorSeverity {
-        ERROR, WARNING,
-    }
-
-    public enum ErrorType {
-        TRANSPORT, RPC, PROTOCOL, APPLICATION
-    }
 }
index 4cc40822336ac7c50bb64de9edffc64e70984458..1aed5df711c8d0490d317517bcd888d169f78e30 100644 (file)
@@ -10,36 +10,29 @@ package org.opendaylight.yangtools.yang.common;
 import java.util.Collection;
 
 /**
+ * Represents a general result of a call, request, or operation.
  *
- * Result of call to YANG enabled system.
- *
- *
- * @param <T> Return type
+ * @param <T> the result value type
  */
 public interface RpcResult<T> {
 
     /**
-     * True if processing of request was successful
+     * Returns whether or not processing of the call was successful.
      *
-     * @return true if processing was successful.
+     * @return true if processing was successful, false otherwise.
      */
     boolean isSuccessful();
 
     /**
-     *
-     * Returns result of call or null if no result is available.
-     *
-     * @return result of call or null if no result is available.
-     *
+     * Returns the value result of the call or null if no result is available.
      */
     T getResult();
 
     /**
+     * Returns a set of errors and warnings which occurred during processing
+     * the call.
      *
-     * Returns set of errors and warnings which occured during processing
-     * the request.
-     *
-     * @return
+     * @return a Collection of {@link RpcError}
      */
     Collection<RpcError> getErrors();
 }
diff --git a/yang/yang-common/src/main/java/org/opendaylight/yangtools/yang/common/RpcResultBuilder.java b/yang/yang-common/src/main/java/org/opendaylight/yangtools/yang/common/RpcResultBuilder.java
new file mode 100644 (file)
index 0000000..ab358d8
--- /dev/null
@@ -0,0 +1,391 @@
+/*
+ * 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.yang.common;
+
+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.
+ *
+ * @author Thomas Pantelis
+ *
+ * @param <T> the result value type
+ */
+public final class RpcResultBuilder<T> {
+
+    private static class RpcResultImpl<T> implements RpcResult<T> {
+
+        private final Collection<RpcError> errors;
+        private final T result;
+        private final boolean successful;
+
+        RpcResultImpl( boolean successful, T result,
+                       Collection<RpcError> errors ) {
+            this.successful = successful;
+            this.result = result;
+            this.errors = errors;
+        }
+
+        @Override
+        public Collection<RpcError> getErrors() {
+            return errors;
+        }
+
+        @Override
+        public T getResult() {
+            return result;
+        }
+
+        @Override
+        public boolean isSuccessful() {
+            return successful;
+        }
+
+        @Override
+        public String toString(){
+            return "RpcResult [successful=" + successful + ", result="
+                    + result + ", errors=" + errors + "]";
+        }
+    }
+
+    private static class RpcErrorImpl implements RpcError {
+
+        private final String applicationTag;
+        private final String tag;
+        private final String info;
+        private final ErrorSeverity severity;
+        private final String message;
+        private final ErrorType errorType;
+        private final Throwable cause;
+
+        RpcErrorImpl( ErrorSeverity severity, ErrorType errorType,
+                String tag, String message, String applicationTag, String info,
+                Throwable cause ) {
+            this.severity = severity;
+            this.errorType = errorType;
+            this.tag = tag;
+            this.message = message;
+            this.applicationTag = applicationTag;
+            this.info = info;
+            this.cause = cause;
+        }
+
+        @Override
+        public String getApplicationTag() {
+            return applicationTag;
+        }
+
+        @Override
+        public String getTag() {
+            return tag;
+        }
+
+        @Override
+        public String getInfo() {
+            return info;
+        }
+
+        @Override
+        public ErrorSeverity getSeverity() {
+            return severity;
+        }
+
+        @Override
+        public String getMessage(){
+            return message;
+        }
+
+        @Override
+        public ErrorType getErrorType() {
+            return errorType;
+        }
+
+        @Override
+        public Throwable getCause() {
+            return cause;
+        }
+
+        @Override
+        public String toString(){
+            return "RpcError [message=" + message + ", severity="
+                    + severity + ", errorType=" + errorType + ", tag=" + tag
+                    + ", applicationTag=" + applicationTag + ", info=" + info
+                    + ", cause=" + cause + "]";
+        }
+    }
+
+    private ImmutableList.Builder<RpcError> errors;
+    private T result;
+    private final boolean successful;
+
+    private RpcResultBuilder( boolean successful, T result ) {
+        this.successful = successful;
+        this.result = result;
+    }
+
+    /**
+     * Returns a builder for a successful result.
+     */
+    public static <T> RpcResultBuilder<T> success() {
+        return new RpcResultBuilder<T>( true, null );
+    }
+
+    /**
+     * Returns a builder for a successful result.
+     *
+     * @param result the result value
+     */
+    public static <T> RpcResultBuilder<T> success( T result ) {
+         return new RpcResultBuilder<T>( true, result );
+    }
+
+    /**
+     * Returns a builder for a failed result.
+     */
+    public static <T> RpcResultBuilder<T> failed() {
+        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.
+     *
+     * @param result the result value
+     */
+    public RpcResultBuilder<T> withResult( T result ) {
+        this.result = result;
+        return this;
+    }
+
+    private void addError( ErrorSeverity severity, ErrorType errorType,
+            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 ImmutableList.Builder<RpcError>();
+        }
+
+        errors.add( error );
+    }
+
+    /**
+     * Adds a warning to the result.
+     *
+     * @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.
+     */
+    public RpcResultBuilder<T> withWarning( ErrorType errorType, String tag, String message ) {
+        addError( ErrorSeverity.WARNING, errorType, tag, message, null, null, null );
+        return this;
+    }
+
+    /**
+     * Adds a warning to the result.
+     *
+     * @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.
+     */
+    public RpcResultBuilder<T> withWarning( ErrorType errorType, String tag, String message,
+            String applicationTag, String info, Throwable cause ) {
+        addError( ErrorSeverity.WARNING, errorType, tag, message, applicationTag, info, cause );
+        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.
+     */
+    public RpcResultBuilder<T> withError( ErrorType errorType, String message ) {
+        addError( ErrorSeverity.ERROR, errorType, null, message, null, null, null );
+        return this;
+    }
+
+    /**
+     * Adds an error to the result.
+     *
+     * @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.
+     */
+    public RpcResultBuilder<T> withError( ErrorType errorType, String tag, String message ) {
+        addError( ErrorSeverity.ERROR, errorType, tag, message, null, null, null );
+        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.
+     *
+     * @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.
+     */
+    public RpcResultBuilder<T> withError( ErrorType errorType, String tag, String message,
+            String applicationTag, String info, Throwable cause ) {
+        addError( ErrorSeverity.ERROR, errorType, tag, message, applicationTag, info, cause );
+        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.build() : Collections.<RpcError>emptyList() );
+    }
+}
diff --git a/yang/yang-common/src/test/java/org/opendaylight/yangtools/yang/common/RpcResultBuilderTest.java b/yang/yang-common/src/test/java/org/opendaylight/yangtools/yang/common/RpcResultBuilderTest.java
new file mode 100644 (file)
index 0000000..6eee59a
--- /dev/null
@@ -0,0 +1,131 @@
+/*
+ * 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.yang.common;
+
+import static org.junit.Assert.*;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.junit.Test;
+import org.opendaylight.yangtools.yang.common.RpcError.ErrorSeverity;
+import org.opendaylight.yangtools.yang.common.RpcError.ErrorType;
+
+/**
+ * Unit tests for RpcResultBuilder.
+ *
+ * @author Thomas Pantelis
+ */
+public class RpcResultBuilderTest {
+
+    @Test
+    public void testSuccess() {
+        RpcResult<String> result = RpcResultBuilder.<String>success().withResult( "foo" ).build();
+        verifyRpcResult( result, true, "foo" );
+        assertNotNull( "getErrors returned null", result.getErrors() );
+        assertEquals( "getErrors size", 0, result.getErrors().size() );
+
+        result = RpcResultBuilder.<String>success( "bar" ).build();
+        verifyRpcResult( result, true, "bar" );
+    }
+
+    @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",
+                        "error message 1", null, null, null );
+        verifyRpcError( result, 1, ErrorSeverity.ERROR, ErrorType.APPLICATION, "lock_denied",
+                        "error message 2", null, null, null );
+        verifyRpcError( result, 2, ErrorSeverity.ERROR, ErrorType.RPC, "in-use",
+                        "error message 3", "my-app-tag", "my-info", cause );
+        verifyRpcError( result, 3, ErrorSeverity.ERROR, ErrorType.TRANSPORT, "operation-failed",
+                        "error message 4", null, null, cause2 );
+        assertEquals( "getErrors size", 4, result.getErrors().size() );
+    }
+
+    @Test
+    public void testWithWarnings() {
+        Throwable cause = new Throwable( "mock cause" );
+        RpcResult<String> result = RpcResultBuilder.<String>success()
+                  .withWarning( ErrorType.APPLICATION, "lock_denied", "message 1" )
+                  .withWarning( ErrorType.RPC, "in-use", "message 2", "my-app-tag", "my-info", cause )
+                  .build();
+        verifyRpcResult( result, true, null );
+        verifyRpcError( result, 0, ErrorSeverity.WARNING, ErrorType.APPLICATION, "lock_denied",
+                        "message 1", null, null, null );
+        verifyRpcError( result, 1, ErrorSeverity.WARNING, ErrorType.RPC, "in-use",
+                        "message 2", "my-app-tag", "my-info", cause );
+        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 ) {
+
+        List<RpcError> errors = new ArrayList<>( result.getErrors() );
+        assertTrue( "Expected error at index " + errorIndex + " not found",
+                    errorIndex < errors.size() );
+        RpcError error = errors.get( errorIndex );
+        assertEquals( "getSeverity", expSeverity, error.getSeverity() );
+        assertEquals( "getErrorType", expErrorType, error.getErrorType() );
+        assertEquals( "getTag", expTag, error.getTag() );
+        assertEquals( "getMessage", expMessage, error.getMessage() );
+        assertEquals( "getApplicationTag", expAppTag, error.getApplicationTag() );
+        assertEquals( "getInfo", expInfo, error.getInfo() );
+        assertEquals( "getCause", expCause, error.getCause() );
+    }
+
+    void verifyRpcResult( RpcResult<?> result, boolean expSuccess, Object expValue ) {
+        assertEquals( "isSuccessful", expSuccess, result.isSuccessful() );
+        assertEquals( "getResult", expValue, result.getResult() );
+    }
+}
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 440e68da86f426215a9464e5fbfb3b94ca37ccc0..6051b2681388aeb09fbf3213cba99d5ec33c259d 100644 (file)
@@ -13,19 +13,16 @@ import com.google.common.base.Splitter;
 import java.net.URI;
 import java.net.URISyntaxException;
 import java.util.ArrayList;
-import java.util.Collection;
 import java.util.HashMap;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
-import java.util.concurrent.ThreadLocalRandom;
+import java.util.Map.Entry;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
 import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
-import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeIdentifierWithPredicates;
-import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeWithValue;
 import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.PathArgument;
 import org.opendaylight.yangtools.yang.model.api.Module;
 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
@@ -65,32 +62,17 @@ public final class InstanceIdentifierForXmlCodec {
         return InstanceIdentifier.create(result);
     }
 
-    public static Element serialize(final InstanceIdentifier data, final Element element) {
-        Preconditions.checkNotNull(data, "Variable should contain instance of instance identifier and can't be null");
+    public static Element serialize(final InstanceIdentifier id, final Element element) {
+        Preconditions.checkNotNull(id, "Variable should contain instance of instance identifier and can't be null");
         Preconditions.checkNotNull(element, "DOM element can't be null");
-        Map<String, String> prefixes = new HashMap<>();
-        StringBuilder textContent = new StringBuilder();
-        for (PathArgument pathArgument : data.getPathArguments()) {
-            textContent.append('/');
-            writeIdentifierWithNamespacePrefix(element, textContent, pathArgument.getNodeType(), prefixes);
-            if (pathArgument instanceof NodeIdentifierWithPredicates) {
-                Map<QName, Object> predicates = ((NodeIdentifierWithPredicates) pathArgument).getKeyValues();
-
-                for (QName keyValue : predicates.keySet()) {
-                    String predicateValue = String.valueOf(predicates.get(keyValue));
-                    textContent.append('[');
-                    writeIdentifierWithNamespacePrefix(element, textContent, keyValue, prefixes);
-                    textContent.append("='");
-                    textContent.append(predicateValue);
-                    textContent.append("']");
-                }
-            } else if (pathArgument instanceof NodeWithValue) {
-                textContent.append("[.='");
-                textContent.append(((NodeWithValue) pathArgument).getValue());
-                textContent.append("']");
-            }
+
+        final RandomPrefix prefixes = new RandomPrefix();
+        final String str = XmlUtils.encodeIdentifier(prefixes, id);
+
+        for (Entry<URI, String> e: prefixes.getPrefixes()) {
+            element.setAttribute("xmlns:" + e.getValue(), e.getKey().toString());
         }
-        element.setTextContent(textContent.toString());
+        element.setTextContent(str);
         return element;
     }
 
@@ -198,39 +180,4 @@ public final class InstanceIdentifierForXmlCodec {
             return null;
         }
     }
-
-    private static void writeIdentifierWithNamespacePrefix(final Element element, final StringBuilder textContent, final QName qName,
-            final Map<String, String> prefixes) {
-        String namespace = qName.getNamespace().toString();
-        String prefix = prefixes.get(namespace);
-        if (prefix == null) {
-            prefix = qName.getPrefix();
-            if (prefix == null || prefix.isEmpty() || prefixes.containsValue(prefix)) {
-                prefix = generateNewPrefix(prefixes.values());
-            }
-        }
-
-        element.setAttribute("xmlns:" + prefix, namespace.toString());
-        textContent.append(prefix);
-        prefixes.put(namespace, prefix);
-
-        textContent.append(':');
-        textContent.append(qName.getLocalName());
-    }
-
-    private static String generateNewPrefix(final Collection<String> prefixes) {
-        String result;
-
-        final ThreadLocalRandom random = ThreadLocalRandom.current();
-        do {
-            StringBuilder sb = new StringBuilder();
-            for (int i = 0; i < 4; i++) {
-                sb.append('a' + random.nextInt(25));
-            }
-
-            result = sb.toString();
-        } while (prefixes.contains(result));
-
-        return result;
-    }
 }
diff --git a/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/codec/xml/RandomPrefix.java b/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/codec/xml/RandomPrefix.java
new file mode 100644 (file)
index 0000000..223157a
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * 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 java.net.URI;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.concurrent.ThreadLocalRandom;
+
+import org.opendaylight.yangtools.yang.common.QName;
+
+final class RandomPrefix {
+    final Map<URI, String> prefixes = new HashMap<>();
+
+    Iterable<Entry<URI, String>> getPrefixes() {
+        return prefixes.entrySet();
+    }
+
+    String encodeQName(final QName qname) {
+        String prefix = prefixes.get(qname.getNamespace());
+        if (prefix == null) {
+            prefix = qname.getPrefix();
+            if (prefix == null || prefix.isEmpty() || prefixes.containsValue(prefix)) {
+                final ThreadLocalRandom random = ThreadLocalRandom.current();
+                do {
+                    final StringBuilder sb = new StringBuilder();
+                    for (int i = 0; i < 4; i++) {
+                        sb.append((char)('a' + random.nextInt(25)));
+                    }
+
+                    prefix = sb.toString();
+                } while (prefixes.containsValue(prefix));
+            }
+
+            prefixes.put(qname.getNamespace(), prefix);
+        }
+
+        return prefix + ':' + qname.getLocalName();
+    }
+}
index e011d3ec83bb13b85434c3c2261f061490fe7b57..53f768c072e9bb1dcae93077c08b62bd2d117f77 100644 (file)
@@ -19,6 +19,7 @@ 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;
 
@@ -34,6 +35,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;
@@ -192,24 +194,36 @@ public class XmlDocumentUtils {
         return itemEl;
     }
 
-    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());
+    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, dataType.getLocalName());
+            ret = doc.createElementNS(null, qname.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());
-            }
 
+        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());
+                }
+            }
         }
+
         return ret;
     }
 
+    public static Element createElementFor(final Document doc, final Node<?> data) {
+        return createElementFor(doc, data.getNodeType(), data);
+    }
+
+    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,
             final DataSchemaNode schema, final XmlCodecProvider codecProvider) {
 
@@ -367,8 +381,8 @@ public class XmlDocumentUtils {
     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);
diff --git a/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/codec/xml/XmlStreamUtils.java b/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/codec/xml/XmlStreamUtils.java
new file mode 100644 (file)
index 0000000..1d319a5
--- /dev/null
@@ -0,0 +1,253 @@
+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;
+
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.AttributesContainer;
+import org.opendaylight.yangtools.yang.data.api.CompositeNode;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.Node;
+import org.opendaylight.yangtools.yang.data.api.SimpleNode;
+import org.opendaylight.yangtools.yang.data.impl.codec.TypeDefinitionAwareCodec;
+import org.opendaylight.yangtools.yang.data.impl.schema.SchemaUtils;
+import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.SchemaNode;
+import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
+import org.opendaylight.yangtools.yang.model.api.type.IdentityrefTypeDefinition;
+import org.opendaylight.yangtools.yang.model.api.type.InstanceIdentifierTypeDefinition;
+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;
+
+    protected XmlStreamUtils(final XmlCodecProvider codecProvider) {
+        this.codecProvider = Preconditions.checkNotNull(codecProvider);
+    }
+
+    /**
+     * 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);
+    }
+
+    /**
+     * 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;
+    }
+
+    /**
+     * 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");
+
+        final RandomPrefix prefixes = new RandomPrefix();
+        final String str = XmlUtils.encodeIdentifier(prefixes, id);
+
+        for (Entry<URI, String> e: prefixes.getPrefixes()) {
+            writer.writeNamespace(e.getValue(), e.getKey().toString());
+        }
+        writer.writeCharacters(str);
+    }
+
+    /**
+     * 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 = qname.getNamespace() != null ? qname.getNamespace().toString() : "";
+
+        if (isEmptyElement(data)) {
+            writer.writeEmptyElement(pfx, qname.getLocalName(), ns);
+            return;
+        }
+
+        writer.writeStartElement(pfx, qname.getLocalName(), ns);
+        if (data instanceof AttributesContainer && ((AttributesContainer) data).getAttributes() != null) {
+            for (Entry<QName, String> attribute : ((AttributesContainer) data).getAttributes().entrySet()) {
+                writer.writeAttribute(attribute.getKey().getNamespace().toString(), attribute.getKey().getLocalName(), attribute.getValue());
+            }
+        }
+
+        if (data instanceof SimpleNode<?>) {
+            // Simple node
+            if (schema instanceof LeafListSchemaNode) {
+                writeValue(writer, ((LeafListSchemaNode) schema).getType(), data.getValue());
+            } else if (schema instanceof LeafSchemaNode) {
+                writeValue(writer, ((LeafSchemaNode) schema).getType(), data.getValue());
+            } else {
+                Object value = data.getValue();
+                if (value != null) {
+                    writer.writeCharacters(String.valueOf(value));
+                }
+            }
+        } else {
+            // CompositeNode
+            for (Node<?> child : ((CompositeNode) data).getValue()) {
+                DataSchemaNode childSchema = null;
+                if (schema instanceof DataNodeContainer) {
+                    childSchema = SchemaUtils.findFirstSchema(child.getNodeType(), ((DataNodeContainer) schema).getChildNodes()).orNull();
+                    if (LOG.isDebugEnabled()) {
+                        if (childSchema == null) {
+                            LOG.debug("Probably the data node \"{}\" does not conform to schema", child == null ? "" : child.getNodeType().getLocalName());
+                        }
+                    }
+                }
+
+                writeElement(writer, child, childSchema);
+            }
+        }
+
+        writer.writeEndElement();
+    }
+
+    /**
+     * 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) {
+            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);
+                }
+            } else {
+                LOG.error("Failed to find codec for {}, falling back to using stream", baseType);
+                text = String.valueOf(value);
+            }
+            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 {
+                prefix = "x";
+            }
+
+            writer.writeNamespace(prefix, qname.getNamespace().toString());
+            writer.writeCharacters(prefix + ':' + qname.getLocalName());
+        } else {
+            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));
+        }
+    }
+}
diff --git a/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/codec/xml/XmlUtils.java b/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/codec/xml/XmlUtils.java
new file mode 100644 (file)
index 0000000..052c250
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ * 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 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;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeWithValue;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.PathArgument;
+import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
+
+/**
+ * Common XML-related utility methods, which are not specific to a particular
+ * JAXP API.
+ */
+final class XmlUtils {
+
+    private XmlUtils() {
+
+    }
+
+    public static TypeDefinition<?> resolveBaseTypeFrom(final @Nonnull TypeDefinition<?> type) {
+        TypeDefinition<?> superType = type;
+        while (superType.getBaseType() != null) {
+            superType = superType.getBaseType();
+        }
+        return superType;
+    }
+
+    static String encodeIdentifier(final RandomPrefix prefixes, final InstanceIdentifier id) {
+        StringBuilder textContent = new StringBuilder();
+        for (PathArgument pathArgument : id.getPathArguments()) {
+            textContent.append('/');
+            textContent.append(prefixes.encodeQName(pathArgument.getNodeType()));
+            if (pathArgument instanceof NodeIdentifierWithPredicates) {
+                Map<QName, Object> predicates = ((NodeIdentifierWithPredicates) pathArgument).getKeyValues();
+
+                for (QName keyValue : predicates.keySet()) {
+                    String predicateValue = String.valueOf(predicates.get(keyValue));
+                    textContent.append('[');
+                    textContent.append(prefixes.encodeQName(keyValue));
+                    textContent.append("='");
+                    textContent.append(predicateValue);
+                    textContent.append("']");
+                }
+            } else if (pathArgument instanceof NodeWithValue) {
+                textContent.append("[.='");
+                textContent.append(((NodeWithValue) pathArgument).getValue());
+                textContent.append("']");
+            }
+        }
+
+        return textContent.toString();
+    }
+}
index 345ab7618d2d6980b36dc9e24942117f3bfd2028..fe5892a3f61cb5e906ff939fd52b59fe6de90a3d 100644 (file)
@@ -14,39 +14,66 @@ import com.google.common.base.Preconditions;
 import com.google.common.collect.Collections2;
 import com.google.common.collect.Maps;
 import com.google.common.collect.Sets;
+
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
 import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
 import org.opendaylight.yangtools.yang.data.api.schema.AugmentationNode;
 import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
-import org.opendaylight.yangtools.yang.data.impl.codec.xml.XmlDocumentUtils;
-import org.opendaylight.yangtools.yang.model.api.*;
-import java.util.*;
+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.DataNodeContainer;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
 
 public final class SchemaUtils {
 
     private SchemaUtils() {
     }
 
-    public static DataSchemaNode findSchemaForChild(DataNodeContainer schema, QName qname) {
+    public static final Optional<DataSchemaNode> findFirstSchema(final QName qname, final Set<DataSchemaNode> dataSchemaNode) {
+        if (dataSchemaNode != null && !dataSchemaNode.isEmpty() && qname != null) {
+            for (DataSchemaNode dsn : dataSchemaNode) {
+                if (qname.isEqualWithoutRevision(dsn.getQName())) {
+                    return Optional.<DataSchemaNode> of(dsn);
+                } else if (dsn instanceof ChoiceNode) {
+                    for (ChoiceCaseNode choiceCase : ((ChoiceNode) dsn).getCases()) {
+                        Optional<DataSchemaNode> foundDsn = findFirstSchema(qname, choiceCase.getChildNodes());
+                        if (foundDsn != null && foundDsn.isPresent()) {
+                            return foundDsn;
+                        }
+                    }
+                }
+            }
+        }
+        return Optional.absent();
+    }
+
+    public static DataSchemaNode findSchemaForChild(final DataNodeContainer schema, final QName qname) {
         Set<DataSchemaNode> childNodes = schema.getChildNodes();
         return findSchemaForChild(schema, qname, childNodes);
     }
 
-    public static DataSchemaNode findSchemaForChild(DataNodeContainer schema, QName qname, Set<DataSchemaNode> childNodes) {
-        Optional<DataSchemaNode> childSchema = XmlDocumentUtils.findFirstSchema(qname, childNodes);
+    public static DataSchemaNode findSchemaForChild(final DataNodeContainer schema, final QName qname, final Set<DataSchemaNode> childNodes) {
+        Optional<DataSchemaNode> childSchema = findFirstSchema(qname, childNodes);
         Preconditions.checkState(childSchema.isPresent(),
                 "Unknown child(ren) node(s) detected, identified by: %s, in: %s", qname, schema);
         return childSchema.get();
     }
 
-    public static AugmentationSchema findSchemaForAugment(AugmentationTarget schema, Set<QName> qNames) {
+    public static AugmentationSchema findSchemaForAugment(final AugmentationTarget schema, final Set<QName> qNames) {
         Optional<AugmentationSchema> schemaForAugment = findAugment(schema, qNames);
         Preconditions.checkState(schemaForAugment.isPresent(), "Unknown augmentation node detected, identified by: %s, in: %s",
                 qNames, schema);
         return schemaForAugment.get();
     }
 
-    public static AugmentationSchema findSchemaForAugment(ChoiceNode schema, Set<QName> qNames) {
+    public static AugmentationSchema findSchemaForAugment(final ChoiceNode schema, final Set<QName> qNames) {
         Optional<AugmentationSchema> schemaForAugment = Optional.absent();
 
         for (ChoiceCaseNode choiceCaseNode : schema.getCases()) {
@@ -61,12 +88,12 @@ public final class SchemaUtils {
         return schemaForAugment.get();
     }
 
-    private static Optional<AugmentationSchema> findAugment(AugmentationTarget schema, Set<QName> qNames) {
+    private static Optional<AugmentationSchema> findAugment(final AugmentationTarget schema, final Set<QName> qNames) {
         for (AugmentationSchema augment : schema.getAvailableAugmentations()) {
 
             HashSet<QName> qNamesFromAugment = Sets.newHashSet(Collections2.transform(augment.getChildNodes(), new Function<DataSchemaNode, QName>() {
                 @Override
-                public QName apply(DataSchemaNode input) {
+                public QName apply(final DataSchemaNode input) {
                     return input.getQName();
                 }
             }));
@@ -79,10 +106,9 @@ public final class SchemaUtils {
         return Optional.absent();
     }
 
-    public static DataSchemaNode findSchemaForChild(ChoiceNode schema, QName childPartialQName) {
+    public static DataSchemaNode findSchemaForChild(final ChoiceNode schema, final QName childPartialQName) {
         for (ChoiceCaseNode choiceCaseNode : schema.getCases()) {
-            Optional<DataSchemaNode> childSchema = XmlDocumentUtils.findFirstSchema(childPartialQName,
-                    choiceCaseNode.getChildNodes());
+            Optional<DataSchemaNode> childSchema = findFirstSchema(childPartialQName, choiceCaseNode.getChildNodes());
             if (childSchema.isPresent()) {
                 return childSchema.get();
             }
@@ -98,13 +124,13 @@ public final class SchemaUtils {
      *
      * @return Map with all child nodes, to their most top augmentation
      */
-    public static Map<QName, ChoiceNode> mapChildElementsFromChoices(DataNodeContainer schema) {
+    public static Map<QName, ChoiceNode> mapChildElementsFromChoices(final DataNodeContainer schema) {
         Set<DataSchemaNode> childNodes = schema.getChildNodes();
 
         return mapChildElementsFromChoices(schema, childNodes);
     }
 
-    private static Map<QName, ChoiceNode> mapChildElementsFromChoices(DataNodeContainer schema, Set<DataSchemaNode> childNodes) {
+    private static Map<QName, ChoiceNode> mapChildElementsFromChoices(final DataNodeContainer schema, final Set<DataSchemaNode> childNodes) {
         Map<QName, ChoiceNode> mappedChoices = Maps.newLinkedHashMap();
 
         for (final DataSchemaNode childSchema : childNodes) {
@@ -126,7 +152,7 @@ public final class SchemaUtils {
         return mappedChoices;
     }
 
-    private static boolean isFromAugment(DataNodeContainer schema, DataSchemaNode childSchema) {
+    private static boolean isFromAugment(final DataNodeContainer schema, final DataSchemaNode childSchema) {
         if(schema instanceof AugmentationTarget == false) {
             return false;
         }
@@ -145,7 +171,7 @@ public final class SchemaUtils {
      *
      * @return Map with all child nodes, to their most top augmentation
      */
-    public static Map<QName, AugmentationSchema> mapChildElementsFromAugments(AugmentationTarget schema) {
+    public static Map<QName, AugmentationSchema> mapChildElementsFromAugments(final AugmentationTarget schema) {
 
         Map<QName, AugmentationSchema> childNodesToAugmentation = Maps.newLinkedHashMap();
 
@@ -163,8 +189,9 @@ public final class SchemaUtils {
 
             for (DataSchemaNode child : ((DataNodeContainer) schema).getChildNodes()) {
                 // If is not augmented child, continue
-                if (augments.containsKey(child.getQName()) == false)
+                if (augments.containsKey(child.getQName()) == false) {
                     continue;
+                }
 
                 AugmentationSchema mostTopAugmentation = augments.get(child.getQName());
 
@@ -206,7 +233,7 @@ public final class SchemaUtils {
      *
      * In case of choice, augment and cases, step in.
      */
-    public static Set<QName> getChildNodesRecursive(DataNodeContainer nodeContainer) {
+    public static Set<QName> getChildNodesRecursive(final DataNodeContainer nodeContainer) {
         Set<QName> allChildNodes = Sets.newHashSet();
 
         for (DataSchemaNode childSchema : nodeContainer.getChildNodes()) {
@@ -232,7 +259,7 @@ public final class SchemaUtils {
      * Schema of child node from augment is incomplete, therefore its useless for xml <-> normalizedNode translation.
      *
      */
-    public static Set<DataSchemaNode> getRealSchemasForAugment(AugmentationTarget targetSchema, AugmentationSchema augmentSchema) {
+    public static Set<DataSchemaNode> getRealSchemasForAugment(final AugmentationTarget targetSchema, final AugmentationSchema augmentSchema) {
         if(targetSchema.getAvailableAugmentations().contains(augmentSchema) == false) {
             return Collections.emptySet();
         }
@@ -240,7 +267,7 @@ public final class SchemaUtils {
         Set<DataSchemaNode> realChildNodes = Sets.newHashSet();
 
         if(targetSchema instanceof DataNodeContainer) {
-              realChildNodes = getRealSchemasForAugment((DataNodeContainer)targetSchema, augmentSchema);
+            realChildNodes = getRealSchemasForAugment((DataNodeContainer)targetSchema, augmentSchema);
         } else if(targetSchema instanceof ChoiceNode) {
             for (DataSchemaNode dataSchemaNode : augmentSchema.getChildNodes()) {
                 for (ChoiceCaseNode choiceCaseNode : ((ChoiceNode) targetSchema).getCases()) {
@@ -254,8 +281,8 @@ public final class SchemaUtils {
         return realChildNodes;
     }
 
-    public static Set<DataSchemaNode> getRealSchemasForAugment(DataNodeContainer targetSchema,
-            AugmentationSchema augmentSchema) {
+    public static Set<DataSchemaNode> getRealSchemasForAugment(final DataNodeContainer targetSchema,
+            final AugmentationSchema augmentSchema) {
         Set<DataSchemaNode> realChildNodes = Sets.newHashSet();
         for (DataSchemaNode dataSchemaNode : augmentSchema.getChildNodes()) {
             DataSchemaNode realChild = targetSchema.getDataChildByName(dataSchemaNode.getQName());
@@ -264,7 +291,7 @@ public final class SchemaUtils {
         return realChildNodes;
     }
 
-    public static Optional<ChoiceCaseNode> detectCase(ChoiceNode schema, DataContainerChild<?, ?> child) {
+    public static Optional<ChoiceCaseNode> detectCase(final ChoiceNode schema, final DataContainerChild<?, ?> child) {
         for (ChoiceCaseNode choiceCaseNode : schema.getCases()) {
             if (child instanceof AugmentationNode
                     && belongsToCaseAugment(choiceCaseNode,
@@ -278,7 +305,7 @@ public final class SchemaUtils {
         return Optional.absent();
     }
 
-    public static boolean belongsToCaseAugment(ChoiceCaseNode caseNode, InstanceIdentifier.AugmentationIdentifier childToProcess) {
+    public static boolean belongsToCaseAugment(final ChoiceCaseNode caseNode, final InstanceIdentifier.AugmentationIdentifier childToProcess) {
         for (AugmentationSchema augmentationSchema : caseNode.getAvailableAugmentations()) {
 
             Set<QName> currentAugmentChildNodes = Sets.newHashSet();
@@ -294,11 +321,11 @@ public final class SchemaUtils {
         return false;
     }
 
-    public static InstanceIdentifier.AugmentationIdentifier getNodeIdentifierForAugmentation(AugmentationSchema schema) {
+    public static InstanceIdentifier.AugmentationIdentifier getNodeIdentifierForAugmentation(final AugmentationSchema schema) {
         return new InstanceIdentifier.AugmentationIdentifier(getChildQNames(schema));
     }
 
-    public static Set<QName> getChildQNames(AugmentationSchema schema) {
+    public static Set<QName> getChildQNames(final AugmentationSchema schema) {
         Set<QName> qnames = Sets.newHashSet();
 
         for (DataSchemaNode dataSchemaNode : schema.getChildNodes()) {
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 3b24f6e7a9f99fcccbd297a1599d21b892f8a6cc..668f7512c33f05e5a60749cbc540470b33465c0d 100644 (file)
@@ -7,8 +7,9 @@
  */
 package org.opendaylight.yangtools.yang.data.impl.schema.tree;
 
-import com.google.common.base.Optional;
-import com.google.common.base.Preconditions;
+import java.util.concurrent.locks.ReadWriteLock;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+
 import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
 import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTree;
 import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidate;
@@ -16,12 +17,13 @@ import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeModification
 import org.opendaylight.yangtools.yang.data.api.schema.tree.DataValidationFailedException;
 import org.opendaylight.yangtools.yang.data.api.schema.tree.ModificationType;
 import org.opendaylight.yangtools.yang.data.api.schema.tree.spi.TreeNode;
+import org.opendaylight.yangtools.yang.data.impl.schema.tree.RootModificationApplyOperation.LatestOperationHolder;
 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import java.util.concurrent.locks.ReadWriteLock;
-import java.util.concurrent.locks.ReentrantReadWriteLock;
+import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
 
 /**
  * Read-only snapshot of the data tree.
@@ -31,7 +33,7 @@ final class InMemoryDataTree implements DataTree {
     private static final InstanceIdentifier PUBLIC_ROOT_PATH = InstanceIdentifier.builder().build();
 
     private final ReadWriteLock rwLock = new ReentrantReadWriteLock(true);
-    private ModificationApplyOperation applyOper = new AlwaysFailOperation();
+    private final LatestOperationHolder operationHolder = new LatestOperationHolder();
     private SchemaContext currentSchemaContext;
     private TreeNode rootNode;
 
@@ -62,7 +64,7 @@ final class InMemoryDataTree implements DataTree {
         // Ready to change the context now, make sure no operations are running
         rwLock.writeLock().lock();
         try {
-            this.applyOper = newApplyOper;
+            this.operationHolder.setCurrent(newApplyOper);
             this.currentSchemaContext = newSchemaContext;
         } finally {
             rwLock.writeLock().unlock();
@@ -73,7 +75,7 @@ final class InMemoryDataTree implements DataTree {
     public InMemoryDataTreeSnapshot takeSnapshot() {
         rwLock.readLock().lock();
         try {
-            return new InMemoryDataTreeSnapshot(currentSchemaContext, rootNode, applyOper);
+            return new InMemoryDataTreeSnapshot(currentSchemaContext, rootNode, operationHolder.newSnapshot());
         } finally {
             rwLock.readLock().unlock();
         }
index 3c903e7831b33f6cb459a4404b2a3be0f15078d7..206c27372cb0b286ea7545f6d739e9c8869cd81c 100644 (file)
@@ -7,9 +7,6 @@
  */
 package org.opendaylight.yangtools.yang.data.impl.schema.tree;
 
-import com.google.common.base.Optional;
-import com.google.common.base.Preconditions;
-
 import java.util.Map.Entry;
 
 import javax.annotation.concurrent.GuardedBy;
@@ -25,18 +22,21 @@ import org.opendaylight.yangtools.yang.data.impl.schema.NormalizedNodeUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
+
 final class InMemoryDataTreeModification implements DataTreeModification {
     private static final Logger LOG = LoggerFactory.getLogger(InMemoryDataTreeModification.class);
-    private final ModificationApplyOperation strategyTree;
+    private final RootModificationApplyOperation strategyTree;
     private final InMemoryDataTreeSnapshot snapshot;
     private final ModifiedNode rootNode;
 
     @GuardedBy("this")
     private boolean sealed = false;
 
-    InMemoryDataTreeModification(final InMemoryDataTreeSnapshot snapshot, final ModificationApplyOperation resolver) {
+    InMemoryDataTreeModification(final InMemoryDataTreeSnapshot snapshot, final RootModificationApplyOperation resolver) {
         this.snapshot = Preconditions.checkNotNull(snapshot);
-        this.strategyTree = Preconditions.checkNotNull(resolver);
+        this.strategyTree = Preconditions.checkNotNull(resolver).snapshot();
         this.rootNode = ModifiedNode.createUnmodified(snapshot.getRootNode());
     }
 
@@ -117,7 +117,11 @@ final class InMemoryDataTreeModification implements DataTreeModification {
 
     private ModificationApplyOperation resolveModificationStrategy(final InstanceIdentifier path) {
         LOG.trace("Resolving modification apply strategy for {}", path);
-        return TreeNodeUtils.findNodeChecked(strategyTree, path);
+        if(rootNode.getType() == ModificationType.UNMODIFIED) {
+            strategyTree.upgradeIfPossible();
+        }
+
+        return TreeNodeUtils.<ModificationApplyOperation>findNodeChecked(strategyTree, path);
     }
 
     private OperationWithModification resolveModificationFor(final InstanceIdentifier path) {
index 7c1c1719a462d0419d3cb029b0ecc0a054b61d27..9c0bd584351ced92a98c741c570d9a8e716013a1 100644 (file)
@@ -1,8 +1,6 @@
 package org.opendaylight.yangtools.yang.data.impl.schema.tree;
 
 
-import com.google.common.base.Optional;
-import com.google.common.base.Preconditions;
 import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
 import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeSnapshot;
@@ -10,13 +8,16 @@ import org.opendaylight.yangtools.yang.data.api.schema.tree.spi.TreeNode;
 import org.opendaylight.yangtools.yang.data.impl.schema.NormalizedNodeUtils;
 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
 
+import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
+
 final class InMemoryDataTreeSnapshot implements DataTreeSnapshot {
-    private final ModificationApplyOperation applyOper;
+    private final RootModificationApplyOperation applyOper;
     private final SchemaContext schemaContext;
     private final TreeNode rootNode;
 
     InMemoryDataTreeSnapshot(final SchemaContext schemaContext, final TreeNode rootNode,
-            final ModificationApplyOperation applyOper) {
+            final RootModificationApplyOperation applyOper) {
         this.schemaContext = Preconditions.checkNotNull(schemaContext);
         this.rootNode = Preconditions.checkNotNull(rootNode);
         this.applyOper = Preconditions.checkNotNull(applyOper);
diff --git a/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/tree/RootModificationApplyOperation.java b/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/tree/RootModificationApplyOperation.java
new file mode 100644 (file)
index 0000000..fd3b734
--- /dev/null
@@ -0,0 +1,146 @@
+/*
+ * 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.schema.tree;
+
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.PathArgument;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.DataValidationFailedException;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.spi.TreeNode;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.spi.Version;
+
+import com.google.common.base.Optional;
+
+public abstract class RootModificationApplyOperation implements ModificationApplyOperation {
+
+    @Override
+    public Optional<ModificationApplyOperation> getChild(final PathArgument child) {
+        return getDelegate().getChild(child);
+    }
+
+    @Override
+    public final void checkApplicable(final InstanceIdentifier path, final NodeModification modification, final Optional<TreeNode> current)
+            throws DataValidationFailedException {
+        getDelegate().checkApplicable(path, modification, current);
+    }
+
+    @Override
+    public final Optional<TreeNode> apply(final ModifiedNode modification, final Optional<TreeNode> currentMeta, final Version version) {
+        return getDelegate().apply(modification, currentMeta, version);
+    }
+
+    @Override
+    public boolean equals(final Object obj) {
+        return getDelegate().equals(obj);
+    }
+
+    @Override
+    public int hashCode() {
+        return getDelegate().hashCode();
+    }
+
+    @Override
+    public String toString() {
+        return getDelegate().toString();
+    }
+
+    @Override
+    public void verifyStructure(final ModifiedNode modification) throws IllegalArgumentException {
+        getDelegate().verifyStructure(modification);
+    }
+
+    abstract ModificationApplyOperation getDelegate();
+
+    public abstract RootModificationApplyOperation snapshot();
+
+    public abstract void upgradeIfPossible();
+
+
+
+    public static RootModificationApplyOperation from(final ModificationApplyOperation resolver) {
+        if(resolver instanceof RootModificationApplyOperation) {
+            return ((RootModificationApplyOperation) resolver).snapshot();
+        }
+        return new NotUpgradable(resolver);
+    }
+
+    private static final class Upgradable extends RootModificationApplyOperation {
+
+        private final LatestOperationHolder holder;
+        private ModificationApplyOperation delegate;
+
+
+        public Upgradable(final LatestOperationHolder holder, final ModificationApplyOperation delegate) {
+            this.holder = holder;
+            this.delegate = delegate;
+
+        }
+
+        @Override
+        public void upgradeIfPossible() {
+            ModificationApplyOperation holderCurrent = holder.getCurrent();
+            if(holderCurrent != delegate) {
+                // FIXME: Allow update only if there is addition of models, not removals.
+                delegate = holderCurrent;
+            }
+
+        }
+
+        @Override
+        ModificationApplyOperation getDelegate() {
+            return delegate;
+        }
+
+        @Override
+        public RootModificationApplyOperation snapshot() {
+            return new Upgradable(holder,getDelegate());
+        }
+
+    }
+
+    private static final class NotUpgradable extends RootModificationApplyOperation {
+
+        private final ModificationApplyOperation delegate;
+
+        public NotUpgradable(final ModificationApplyOperation delegate) {
+            this.delegate = delegate;
+        }
+
+        @Override
+        public ModificationApplyOperation getDelegate() {
+            return delegate;
+        }
+
+        @Override
+        public void upgradeIfPossible() {
+            // Intentional noop
+        }
+
+        @Override
+        public RootModificationApplyOperation snapshot() {
+            return this;
+        }
+    }
+
+    public static class LatestOperationHolder {
+
+        private ModificationApplyOperation current = new AlwaysFailOperation();
+
+        public ModificationApplyOperation getCurrent() {
+            return current;
+        }
+
+        public void setCurrent(final ModificationApplyOperation newApplyOper) {
+            current = newApplyOper;
+        }
+
+        public RootModificationApplyOperation newSnapshot() {
+            return new Upgradable(this,current);
+        }
+
+    }
+}
index f243f7183ca7ba359e9e2bf162c358e76329210d..eeac30bf99d704e220db41c12a98dda0bb279fdf 100644 (file)
@@ -12,7 +12,8 @@ import java.net.URI;
 import java.util.Date;
 import java.util.List;
 import java.util.Map;
-import java.util.Stack;
+import java.util.Deque;
+import java.util.LinkedList;
 
 import org.junit.Assert;
 import org.junit.Before;
@@ -145,7 +146,7 @@ public class NodeUtilsTest {
     }
 
     private static void checkFamilyBinding(final CompositeNode treeRoot) throws Exception {
-        Stack<CompositeNode> jobQueue = new Stack<>();
+        Deque<CompositeNode> jobQueue = new LinkedList<>();
         jobQueue.push(treeRoot);
 
         while (!jobQueue.isEmpty()) {
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"));
+    }
+
+}
index 54a4a88cbb47644280d363083136d5e4989fdb7b..003c20fe7ca069329e8b5be5c990ea7f93fbd709 100644 (file)
@@ -7,7 +7,15 @@
  */
 package org.opendaylight.yangtools.yang.data.impl.schema.tree;
 
-import com.google.common.base.Optional;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
+import static org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes.mapEntry;
+import static org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes.mapEntryBuilder;
+import static org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes.mapNodeBuilder;
+
 import org.junit.Before;
 import org.junit.Test;
 import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
@@ -24,14 +32,7 @@ import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
 import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableContainerNodeBuilder;
 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
 
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertSame;
-import static org.junit.Assert.assertTrue;
-import static org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes.mapEntry;
-import static org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes.mapEntryBuilder;
-import static org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes.mapNodeBuilder;
+import com.google.common.base.Optional;
 
 
 
@@ -97,13 +98,13 @@ public class ModificationMetadataTreeTest {
                     .build();
 
     private SchemaContext schemaContext;
-    private ModificationApplyOperation applyOper;
+    private RootModificationApplyOperation rootOper;
 
     @Before
     public void prepare() {
         schemaContext = TestModel.createTestContext();
         assertNotNull("Schema context must not be null.", schemaContext);
-        applyOper = SchemaAwareApplyOperation.from(schemaContext);
+        rootOper = RootModificationApplyOperation.from(SchemaAwareApplyOperation.from(schemaContext));
     }
 
     /**
@@ -145,8 +146,8 @@ public class ModificationMetadataTreeTest {
     @Test
     public void basicReadWrites() {
         DataTreeModification modificationTree = new InMemoryDataTreeModification(new InMemoryDataTreeSnapshot(schemaContext,
-                TreeNodeFactory.createTreeNode(createDocumentOne(), Version.initial()), applyOper),
-                new SchemaAwareApplyOperationRoot(schemaContext));
+                TreeNodeFactory.createTreeNode(createDocumentOne(), Version.initial()), rootOper),
+                rootOper);
         Optional<NormalizedNode<?, ?>> originalBarNode = modificationTree.readNode(OUTER_LIST_2_PATH);
         assertTrue(originalBarNode.isPresent());
         assertSame(BAR_NODE, originalBarNode.get());
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);
diff --git a/yang/yang-model-api/src/main/java/org/opendaylight/yangtools/yang/model/api/DerivableSchemaNode.java b/yang/yang-model-api/src/main/java/org/opendaylight/yangtools/yang/model/api/DerivableSchemaNode.java
new file mode 100644 (file)
index 0000000..2ffc3ad
--- /dev/null
@@ -0,0 +1,21 @@
+package org.opendaylight.yangtools.yang.model.api;
+
+import com.google.common.base.Optional;
+
+/**
+ * Schema Node which may be derived from other schema node
+ * using augmentation or uses statement.
+ *
+ */
+public interface DerivableSchemaNode extends DataSchemaNode {
+
+    /**
+     * If this node is added by uses, returns original node definition from
+     * grouping where it was defined.
+     *
+     * @return original node definition from grouping if this node is added by
+     *         uses, null otherwise
+     */
+    Optional<? extends SchemaNode> getOriginal();
+
+}
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..c4831ef3f2a56b49280ea1e29af96be1bccb6155 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);
     }
 
     /**
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 6305dd7c88b42d3708830a1760169c3c04cd0ae9..fbf4c4389b05f140dbc3452c367a18627f707109 100644 (file)
@@ -11,7 +11,6 @@ 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;
@@ -21,7 +20,6 @@ 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;
@@ -242,8 +240,9 @@ public final class SchemaContextUtil {
         return findNodeInModule(module, path);
     }
 
-    public static GroupingDefinition findGrouping(final SchemaContext context, final Module module, final List<QName> path) {
-        QName first = path.get(0);
+    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) {
@@ -626,8 +625,12 @@ public final class SchemaContextUtil {
     }
 
     private static DataSchemaNode getResultFromUses(final UsesNode u, final String currentName, final SchemaContext ctx) {
-        SchemaNode targetGrouping = findNodeInSchemaContext(ctx, u.getGroupingPath().getPathFromRoot());
-
+        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;
diff --git a/yang/yang-model-util/src/main/java/org/opendaylight/yangtools/yang/model/util/SchemaNodeUtils.java b/yang/yang-model-util/src/main/java/org/opendaylight/yangtools/yang/model/util/SchemaNodeUtils.java
new file mode 100644 (file)
index 0000000..f00a555
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * 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.model.util;
+
+import org.opendaylight.yangtools.yang.model.api.DerivableSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.SchemaNode;
+
+import com.google.common.base.Optional;
+
+public class SchemaNodeUtils {
+
+    private SchemaNodeUtils() {
+        throw new UnsupportedOperationException("Utility class");
+    }
+
+    public static final Optional<SchemaNode> getOriginalIfPossible(final SchemaNode node) {
+        if(node instanceof DerivableSchemaNode) {
+            @SuppressWarnings("unchecked")
+            final Optional<SchemaNode> ret  = (Optional<SchemaNode>) (((DerivableSchemaNode) node).getOriginal());
+            return ret;
+        }
+        return Optional.absent();
+    }
+
+    public static final  SchemaNode getRootOriginalIfPossible(final SchemaNode data) {
+        Optional<SchemaNode> previous = Optional.absent();
+        Optional<SchemaNode> next = getOriginalIfPossible(data);
+        while(next.isPresent()) {
+            previous = next;
+            next = getOriginalIfPossible(next.get());
+        }
+        return previous.orNull();
+    }
+}
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 c4d24d36024d164d2fa80c5531163c34bec57389..8d86c1d3b9483ef7267480ddaeda42b7f89a2a22 100644 (file)
@@ -15,7 +15,21 @@ import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
  */
 public interface DataSchemaNodeBuilder extends SchemaNodeBuilder, GroupingMember {
 
+    /**
+     * Get original builder definition from grouping, where it is defined.
+     *
+     * @return original builder definition from grouping if this node is added
+     *         by uses, null otherwise
+     */
+    SchemaNodeBuilder getOriginal();
 
+    /**
+     * Set original builder definition from grouping
+     *
+     * @param original
+     *            original builder definition from grouping
+     */
+    void setOriginal(SchemaNodeBuilder original);
 
     /**
      *
index e5762d8c27526bf596d91291e6025742d22c7b90..19cd4485b15c1833f2ab9e9a6cc9df4e634025d3 100644 (file)
@@ -7,26 +7,33 @@
  */
 package org.opendaylight.yangtools.yang.parser.builder.impl;
 
-import com.google.common.collect.ImmutableList;
 import java.util.List;
+
 import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.model.api.AnyXmlSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.ConstraintDefinition;
+import org.opendaylight.yangtools.yang.model.api.DerivableSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.SchemaPath;
 import org.opendaylight.yangtools.yang.model.api.Status;
 import org.opendaylight.yangtools.yang.model.api.UnknownSchemaNode;
 import org.opendaylight.yangtools.yang.parser.builder.api.ConstraintsBuilder;
 import org.opendaylight.yangtools.yang.parser.builder.api.DataSchemaNodeBuilder;
+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.AbstractSchemaNodeBuilder;
 
+import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableList;
+
 public final class AnyXmlBuilder extends AbstractSchemaNodeBuilder implements DataSchemaNodeBuilder {
     private AnyXmlSchemaNodeImpl instance;
 
     private boolean augmenting;
     private boolean addedByUses;
     private boolean configuration;
-
+    private AnyXmlSchemaNode originalNode;
+    private AnyXmlBuilder originalBuilder;
     private final ConstraintsBuilder constraints;
 
     public AnyXmlBuilder(final String moduleName, final int line, final QName qname, final SchemaPath path) {
@@ -46,6 +53,7 @@ public final class AnyXmlBuilder extends AbstractSchemaNodeBuilder implements Da
         status = base.getStatus();
         augmenting = base.isAugmenting();
         addedByUses = base.isAddedByUses();
+        originalNode = base;
         configuration = base.isConfiguration();
         unknownNodes.addAll(base.getUnknownSchemaNodes());
     }
@@ -64,9 +72,14 @@ public final class AnyXmlBuilder extends AbstractSchemaNodeBuilder implements Da
         instance.augmenting = augmenting;
         instance.addedByUses = addedByUses;
         instance.configuration = configuration;
-
         instance.constraintsDef = constraints.toInstance();
 
+        // ORIGINAL NODE
+        if (originalNode == null && originalBuilder != null) {
+            originalNode = originalBuilder.build();
+        }
+        instance.original = originalNode;
+
         // UNKNOWN NODES
         for (UnknownSchemaNodeBuilder b : addedUnknownNodes) {
             unknownNodes.add(b.build());
@@ -101,6 +114,17 @@ public final class AnyXmlBuilder extends AbstractSchemaNodeBuilder implements Da
         this.addedByUses = addedByUses;
     }
 
+    @Override
+    public AnyXmlBuilder getOriginal() {
+        return originalBuilder;
+    }
+
+    @Override
+    public void setOriginal(final SchemaNodeBuilder builder) {
+        Preconditions.checkArgument(builder instanceof AnyXmlBuilder, "Original of anyxml cannot be " + builder);
+        this.originalBuilder = (AnyXmlBuilder) builder;
+    }
+
     @Override
     public boolean isConfiguration() {
         return configuration;
@@ -120,7 +144,7 @@ public final class AnyXmlBuilder extends AbstractSchemaNodeBuilder implements Da
     }
 
     @Override
-    public boolean equals(Object obj) {
+    public boolean equals(final Object obj) {
         if (this == obj) {
             return true;
         }
@@ -153,13 +177,14 @@ public final class AnyXmlBuilder extends AbstractSchemaNodeBuilder implements Da
         return "anyxml " + qname.getLocalName();
     }
 
-    private static final class AnyXmlSchemaNodeImpl implements AnyXmlSchemaNode {
+    private static final class AnyXmlSchemaNodeImpl implements AnyXmlSchemaNode, DerivableSchemaNode {
         private final QName qname;
         private final SchemaPath path;
         private String description;
         private String reference;
         private Status status;
         private boolean configuration;
+        private AnyXmlSchemaNode original;
         private ConstraintDefinition constraintsDef;
         private boolean augmenting;
         private boolean addedByUses;
@@ -205,6 +230,11 @@ public final class AnyXmlBuilder extends AbstractSchemaNodeBuilder implements Da
             return addedByUses;
         }
 
+        @Override
+        public Optional<AnyXmlSchemaNode> getOriginal() {
+            return Optional.fromNullable(original);
+        }
+
         @Override
         public boolean isConfiguration() {
             return configuration;
@@ -230,7 +260,7 @@ public final class AnyXmlBuilder extends AbstractSchemaNodeBuilder implements Da
         }
 
         @Override
-        public boolean equals(Object obj) {
+        public boolean equals(final Object obj) {
             if (this == obj) {
                 return true;
             }
@@ -267,6 +297,7 @@ public final class AnyXmlBuilder extends AbstractSchemaNodeBuilder implements Da
             sb.append("]");
             return sb.toString();
         }
+
     }
 
 }
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 bfc549cbbf53ead652c40702c399bb6569ac4c69..f4aabb19445df58cf9cf8fd4ee1832244c9fab06 100644 (file)
@@ -7,9 +7,6 @@
  */
 package org.opendaylight.yangtools.yang.parser.builder.impl;
 
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableSet;
-
 import java.util.ArrayList;
 import java.util.HashSet;
 import java.util.List;
@@ -22,6 +19,7 @@ import org.opendaylight.yangtools.yang.model.api.ChoiceCaseNode;
 import org.opendaylight.yangtools.yang.model.api.ChoiceNode;
 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.SchemaPath;
 import org.opendaylight.yangtools.yang.model.api.Status;
 import org.opendaylight.yangtools.yang.model.api.UnknownSchemaNode;
@@ -29,11 +27,17 @@ import org.opendaylight.yangtools.yang.parser.builder.api.AugmentationSchemaBuil
 import org.opendaylight.yangtools.yang.parser.builder.api.AugmentationTargetBuilder;
 import org.opendaylight.yangtools.yang.parser.builder.api.ConstraintsBuilder;
 import org.opendaylight.yangtools.yang.parser.builder.api.DataSchemaNodeBuilder;
+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.AbstractSchemaNodeBuilder;
 import org.opendaylight.yangtools.yang.parser.builder.util.Comparators;
 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 ChoiceBuilder extends AbstractSchemaNodeBuilder implements DataSchemaNodeBuilder,
 AugmentationTargetBuilder {
     private ChoiceNodeImpl instance;
@@ -42,6 +46,8 @@ AugmentationTargetBuilder {
     private boolean augmenting;
     private boolean addedByUses;
     private boolean configuration;
+    private ChoiceNode originalNode;
+    private ChoiceBuilder originalBuilder;
     private final ConstraintsBuilder constraints;
     // AugmentationTarget args
     private final Set<AugmentationSchema> augmentations = new HashSet<>();
@@ -67,6 +73,7 @@ AugmentationTargetBuilder {
         status = base.getStatus();
         augmenting = base.isAugmenting();
         addedByUses = base.isAddedByUses();
+        originalNode =  base;
         configuration = base.isConfiguration();
         augmentations.addAll(base.getAvailableAugmentations());
 
@@ -100,6 +107,12 @@ AugmentationTargetBuilder {
         instance.constraints = constraints.toInstance();
         instance.defaultCase = defaultCase;
 
+        // ORIGINAL NODE
+        if (originalNode == null && originalBuilder != null) {
+            originalNode = originalBuilder.build();
+        }
+        instance.original = originalNode;
+
         // CASES
         final Set<ChoiceCaseNode> cases = new TreeSet<>(Comparators.SCHEMA_NODE_COMP);
         for (ChoiceCaseBuilder caseBuilder : caseBuilders) {
@@ -201,6 +214,17 @@ AugmentationTargetBuilder {
         this.addedByUses = addedByUses;
     }
 
+    @Override
+    public ChoiceBuilder getOriginal() {
+        return originalBuilder;
+    }
+
+    @Override
+    public void setOriginal(final SchemaNodeBuilder builder) {
+        Preconditions.checkArgument(builder instanceof ChoiceBuilder, "Original of choice cannot be " + builder);
+        this.originalBuilder = (ChoiceBuilder) builder;
+    }
+
     @Override
     public boolean isConfiguration() {
         return configuration;
@@ -275,7 +299,7 @@ AugmentationTargetBuilder {
         return "choice " + qname.getLocalName();
     }
 
-    private static final class ChoiceNodeImpl implements ChoiceNode {
+    private static final class ChoiceNodeImpl implements ChoiceNode, DerivableSchemaNode {
         private final QName qname;
         private final SchemaPath path;
         private String description;
@@ -283,6 +307,7 @@ AugmentationTargetBuilder {
         private Status status;
         private boolean augmenting;
         private boolean addedByUses;
+        private ChoiceNode original;
         private boolean configuration;
         private ConstraintDefinition constraints;
         private ImmutableSet<ChoiceCaseNode> cases;
@@ -330,6 +355,11 @@ AugmentationTargetBuilder {
             return addedByUses;
         }
 
+        @Override
+        public Optional<ChoiceNode> getOriginal() {
+            return Optional.fromNullable(original);
+        }
+
         @Override
         public boolean isConfiguration() {
             return configuration;
@@ -433,6 +463,7 @@ AugmentationTargetBuilder {
             sb.append("]");
             return sb.toString();
         }
+
     }
 
 }
index a090d733e9d5ac1d7fb8c48cced4b06c9a5ad4c8..c97eb14ebefd889e560a9afd96f43b01e65aaa89 100644 (file)
@@ -7,10 +7,6 @@
  */
 package org.opendaylight.yangtools.yang.parser.builder.impl;
 
-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;
@@ -19,29 +15,34 @@ import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.model.api.AugmentationSchema;
 import org.opendaylight.yangtools.yang.model.api.ChoiceCaseNode;
 import org.opendaylight.yangtools.yang.model.api.ConstraintDefinition;
+import org.opendaylight.yangtools.yang.model.api.DerivableSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.SchemaPath;
-import org.opendaylight.yangtools.yang.model.api.Status;
 import org.opendaylight.yangtools.yang.model.api.UnknownSchemaNode;
 import org.opendaylight.yangtools.yang.parser.builder.api.AugmentationSchemaBuilder;
 import org.opendaylight.yangtools.yang.parser.builder.api.AugmentationTargetBuilder;
 import org.opendaylight.yangtools.yang.parser.builder.api.ConstraintsBuilder;
 import org.opendaylight.yangtools.yang.parser.builder.api.DataSchemaNodeBuilder;
+import org.opendaylight.yangtools.yang.parser.builder.api.SchemaNodeBuilder;
 import org.opendaylight.yangtools.yang.parser.builder.api.TypeDefinitionBuilder;
 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 ChoiceCaseBuilder extends AbstractDocumentedDataNodeContainerBuilder implements DataSchemaNodeBuilder,
 AugmentationTargetBuilder {
     private ChoiceCaseNodeImpl instance;
     // SchemaNode args
     private SchemaPath schemaPath;
-    private String description;
-    private String reference;
-    private Status status = Status.CURRENT;
     // DataSchemaNode args
     private boolean augmenting;
+    private ChoiceCaseNode originalNode;
+    private ChoiceCaseBuilder originalBuilder;
     private boolean addedByUses;
     private final ConstraintsBuilder constraints;
     // AugmentationTarget args
@@ -56,17 +57,13 @@ AugmentationTargetBuilder {
 
     public ChoiceCaseBuilder(final String moduleName, final int line, final QName qname, final SchemaPath path,
             final ChoiceCaseNode base) {
-
-        super(moduleName, line, qname);
-        this.schemaPath = Preconditions.checkNotNull(path, "Schema Path must not be null");
+        super(moduleName, line, qname, Preconditions.checkNotNull(path, "Schema Path must not be null"), base);
+        this.schemaPath = path;
         constraints = new ConstraintsBuilderImpl(moduleName, line, base.getConstraints());
 
-        description = base.getDescription();
-        reference = base.getReference();
-        status = base.getStatus();
         augmenting = base.isAugmenting();
         addedByUses = base.isAddedByUses();
-
+        originalNode = base;
         addedUnknownNodes.addAll(BuilderUtils.wrapUnknownNodes(moduleName, line, base.getUnknownSchemaNodes(), path,
                 qname));
         augmentations.addAll(base.getAvailableAugmentations());
@@ -85,6 +82,12 @@ AugmentationTargetBuilder {
 
         instance.constraints = constraints.toInstance();
 
+        // ORIGINAL NODE
+        if (originalNode == null && originalBuilder != null) {
+            originalNode = originalBuilder.build();
+        }
+        instance.original = originalNode;
+
         // UNKNOWN NODES
         for (UnknownSchemaNodeBuilder b : addedUnknownNodes) {
             unknownNodes.add(b.build());
@@ -129,6 +132,17 @@ AugmentationTargetBuilder {
         this.addedByUses = addedByUses;
     }
 
+    @Override
+    public ChoiceCaseBuilder getOriginal() {
+        return originalBuilder;
+    }
+
+    @Override
+    public void setOriginal(final SchemaNodeBuilder builder) {
+        Preconditions.checkArgument(builder instanceof ChoiceCaseBuilder, "Original of case cannot be " + builder);
+        this.originalBuilder = (ChoiceCaseBuilder) builder;
+    }
+
     @Override
     public void addTypedef(final TypeDefinitionBuilder typedefBuilder) {
         throw new YangParseException(getModuleName(), typedefBuilder.getLine(), "Can not add type definition to choice case.");
@@ -201,11 +215,12 @@ AugmentationTargetBuilder {
         return "choice";
     }
 
-    private static final class ChoiceCaseNodeImpl extends AbstractDocumentedDataNodeContainer implements ChoiceCaseNode {
+    private static final class ChoiceCaseNodeImpl extends AbstractDocumentedDataNodeContainer implements ChoiceCaseNode, DerivableSchemaNode {
         private final QName qname;
         private final SchemaPath path;
         private boolean augmenting;
         private boolean addedByUses;
+        private ChoiceCaseNode original;
         private ConstraintDefinition constraints;
         private ImmutableSet<AugmentationSchema> augmentations;
         private ImmutableList<UnknownSchemaNode> unknownNodes;
@@ -246,6 +261,11 @@ AugmentationTargetBuilder {
             return addedByUses;
         }
 
+        @Override
+        public Optional<ChoiceCaseNode> getOriginal() {
+            return Optional.fromNullable(original);
+        }
+
         @Override
         public List<UnknownSchemaNode> getUnknownSchemaNodes() {
             return unknownNodes;
@@ -303,6 +323,7 @@ AugmentationTargetBuilder {
             sb.append("]");
             return sb.toString();
         }
+
     }
 
 }
index 45bf23e721a3c8be8d188693e33947db037a6794..c77444269c297c75acacc650254dc2cc26a1a707 100644 (file)
@@ -7,26 +7,31 @@
  */
 package org.opendaylight.yangtools.yang.parser.builder.impl;
 
-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.ContainerSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.DerivableSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.SchemaPath;
 import org.opendaylight.yangtools.yang.model.api.UnknownSchemaNode;
 import org.opendaylight.yangtools.yang.parser.builder.api.AugmentationSchemaBuilder;
 import org.opendaylight.yangtools.yang.parser.builder.api.AugmentationTargetBuilder;
 import org.opendaylight.yangtools.yang.parser.builder.api.ConstraintsBuilder;
 import org.opendaylight.yangtools.yang.parser.builder.api.DataSchemaNodeBuilder;
+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 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 ContainerSchemaNodeBuilder extends AbstractDocumentedDataNodeContainerBuilder implements
         AugmentationTargetBuilder, DataSchemaNodeBuilder {
     private ContainerSchemaNodeImpl instance;
@@ -37,6 +42,8 @@ public final class ContainerSchemaNodeBuilder extends AbstractDocumentedDataNode
     private boolean augmenting;
     private boolean addedByUses;
     private boolean configuration;
+    private ContainerSchemaNode originalNode;
+    private ContainerSchemaNodeBuilder originalBuilder;
     private final ConstraintsBuilder constraints;
     // AugmentationTarget args
     private final List<AugmentationSchema> augmentations = new ArrayList<>();
@@ -58,6 +65,7 @@ public final class ContainerSchemaNodeBuilder extends AbstractDocumentedDataNode
 
         augmenting = base.isAugmenting();
         addedByUses = base.isAddedByUses();
+        originalNode = base;
         configuration = base.isConfiguration();
         presence = base.isPresenceContainer();
 
@@ -85,6 +93,12 @@ public final class ContainerSchemaNodeBuilder extends AbstractDocumentedDataNode
         instance.constraints = constraints.toInstance();
         instance.presence = presence;
 
+        // ORIGINAL NODE
+        if (originalNode == null && originalBuilder != null) {
+            originalNode = originalBuilder.build();
+        }
+        instance.original = originalNode;
+
         // AUGMENTATIONS
         for (AugmentationSchemaBuilder builder : augmentationBuilders) {
             augmentations.add(builder.build());
@@ -139,6 +153,18 @@ public final class ContainerSchemaNodeBuilder extends AbstractDocumentedDataNode
         this.addedByUses = addedByUses;
     }
 
+    @Override
+    public ContainerSchemaNodeBuilder getOriginal() {
+        return originalBuilder;
+    }
+
+    @Override
+    public void setOriginal(final SchemaNodeBuilder builder) {
+        Preconditions.checkArgument(builder instanceof ContainerSchemaNodeBuilder, "Original of container cannot be "
+                + builder);
+        this.originalBuilder = (ContainerSchemaNodeBuilder) builder;
+    }
+
     @Override
     public boolean isConfiguration() {
         return configuration;
@@ -189,8 +215,6 @@ public final class ContainerSchemaNodeBuilder extends AbstractDocumentedDataNode
         } else if (!path.equals(other.path)) {
             return false;
         }
-        // FIXME: Do we really need this? This actually triggers equals
-        // up to the root builder.
         if (getParent() == null) {
             if (other.getParent() != null) {
                 return false;
@@ -207,13 +231,14 @@ public final class ContainerSchemaNodeBuilder extends AbstractDocumentedDataNode
     }
 
     private static final class ContainerSchemaNodeImpl extends AbstractDocumentedDataNodeContainer implements
-            ContainerSchemaNode {
+            ContainerSchemaNode, DerivableSchemaNode {
         private final QName qname;
         private final SchemaPath path;
 
         private boolean augmenting;
         private boolean addedByUses;
         private boolean configuration;
+        private ContainerSchemaNode original;
         private ConstraintDefinition constraints;
 
         private ImmutableSet<AugmentationSchema> augmentations;
@@ -247,6 +272,11 @@ public final class ContainerSchemaNodeBuilder extends AbstractDocumentedDataNode
             return addedByUses;
         }
 
+        @Override
+        public Optional<ContainerSchemaNode> getOriginal() {
+            return Optional.fromNullable(original);
+        }
+
         @Override
         public boolean isConfiguration() {
             return configuration;
@@ -314,6 +344,7 @@ public final class ContainerSchemaNodeBuilder extends AbstractDocumentedDataNode
         public String toString() {
             return "container " + qname.getLocalName();
         }
+
     }
 
 }
index ce7bfeebf883e40533105f1ae5c1c3067891053d..365c34379eba8e05df5292463ab68b71614cd97e 100644 (file)
@@ -39,7 +39,8 @@ public final class CopyUtils {
      *            parent location
      * @return copy of given builder
      */
-    public static DataSchemaNodeBuilder copy(final DataSchemaNodeBuilder old, final Builder newParent, final boolean updateQName) {
+    public static DataSchemaNodeBuilder copy(final DataSchemaNodeBuilder old, final Builder newParent,
+            final boolean updateQName) {
         if (old instanceof AnyXmlBuilder) {
             return copy((AnyXmlBuilder) old, newParent, updateQName);
         } else if (old instanceof ChoiceBuilder) {
@@ -66,6 +67,7 @@ public final class CopyUtils {
         SchemaPath newSchemaPath = data.schemaPath;
 
         AnyXmlBuilder copy = new AnyXmlBuilder(newParent.getModuleName(), newParent.getLine(), newQName, newSchemaPath);
+        copy.setOriginal(old.getOriginal() == null ? old : old.getOriginal());
         copyConstraints(copy.getConstraints(), old.getConstraints());
         copy.setParent(newParent);
         copy.setDescription(old.getDescription());
@@ -87,6 +89,7 @@ public final class CopyUtils {
         SchemaPath newSchemaPath = data.schemaPath;
 
         ChoiceBuilder copy = new ChoiceBuilder(newParent.getModuleName(), newParent.getLine(), newQName, newSchemaPath);
+        copy.setOriginal(old.getOriginal() == null ? old : old.getOriginal());
         copyConstraints(copy.getConstraints(), old.getConstraints());
         copy.setParent(newParent);
         copy.setDescription(old.getDescription());
@@ -108,12 +111,15 @@ public final class CopyUtils {
         return copy;
     }
 
-    private static ChoiceCaseBuilder copy(final ChoiceCaseBuilder old, final Builder newParent, final boolean updateQName) {
+    private static ChoiceCaseBuilder copy(final ChoiceCaseBuilder old, final Builder newParent,
+            final boolean updateQName) {
         DataBean data = getdata(old, newParent, updateQName);
         QName newQName = data.qname;
         SchemaPath newSchemaPath = data.schemaPath;
 
-        ChoiceCaseBuilder copy = new ChoiceCaseBuilder(newParent.getModuleName(), newParent.getLine(), newQName, newSchemaPath);
+        ChoiceCaseBuilder copy = new ChoiceCaseBuilder(newParent.getModuleName(), newParent.getLine(), newQName,
+                newSchemaPath);
+        copy.setOriginal(old.getOriginal() == null ? old : old.getOriginal());
         copyConstraints(copy.getConstraints(), old.getConstraints());
         copy.setParent(newParent);
         copy.setDescription(old.getDescription());
@@ -148,6 +154,7 @@ public final class CopyUtils {
 
         ContainerSchemaNodeBuilder copy = new ContainerSchemaNodeBuilder(newParent.getModuleName(),
                 newParent.getLine(), newQName, newSchemaPath);
+        copy.setOriginal(old.getOriginal() == null ? old : old.getOriginal());
         copyConstraints(copy.getConstraints(), old.getConstraints());
         copy.setParent(newParent);
         copy.setDescription(old.getDescription());
@@ -180,13 +187,15 @@ public final class CopyUtils {
         return copy;
     }
 
-    private static LeafSchemaNodeBuilder copy(final LeafSchemaNodeBuilder old, final Builder newParent, final boolean updateQName) {
+    private static LeafSchemaNodeBuilder copy(final LeafSchemaNodeBuilder old, final Builder newParent,
+            final boolean updateQName) {
         DataBean data = getdata(old, newParent, updateQName);
         QName newQName = data.qname;
         SchemaPath newSchemaPath = data.schemaPath;
 
         LeafSchemaNodeBuilder copy = new LeafSchemaNodeBuilder(newParent.getModuleName(), newParent.getLine(),
                 newQName, newSchemaPath);
+        copy.setOriginal(old.getOriginal() == null ? old : old.getOriginal());
         copyConstraints(copy.getConstraints(), old.getConstraints());
         copy.setParent(newParent);
         copy.setDescription(old.getDescription());
@@ -211,13 +220,15 @@ public final class CopyUtils {
         return copy;
     }
 
-    private static LeafListSchemaNodeBuilder copy(final LeafListSchemaNodeBuilder old, final Builder newParent, final boolean updateQName) {
+    private static LeafListSchemaNodeBuilder copy(final LeafListSchemaNodeBuilder old, final Builder newParent,
+            final boolean updateQName) {
         DataBean data = getdata(old, newParent, updateQName);
         QName newQName = data.qname;
         SchemaPath newSchemaPath = data.schemaPath;
 
         LeafListSchemaNodeBuilder copy = new LeafListSchemaNodeBuilder(newParent.getModuleName(), newParent.getLine(),
                 newQName, newSchemaPath);
+        copy.setOriginal(old.getOriginal() == null ? old : old.getOriginal());
         copyConstraints(copy.getConstraints(), old.getConstraints());
         copy.setParent(newParent);
         copy.setDescription(old.getDescription());
@@ -241,13 +252,15 @@ public final class CopyUtils {
         return copy;
     }
 
-    private static ListSchemaNodeBuilder copy(final ListSchemaNodeBuilder old, final Builder newParent, final boolean updateQName) {
+    private static ListSchemaNodeBuilder copy(final ListSchemaNodeBuilder old, final Builder newParent,
+            final boolean updateQName) {
         DataBean data = getdata(old, newParent, updateQName);
         QName newQName = data.qname;
         SchemaPath newSchemaPath = data.schemaPath;
 
         ListSchemaNodeBuilder copy = new ListSchemaNodeBuilder(newParent.getModuleName(), newParent.getLine(),
                 newQName, newSchemaPath);
+        copy.setOriginal(old.getOriginal() == null ? old : old.getOriginal());
         copyConstraints(copy.getConstraints(), old.getConstraints());
         copy.setParent(newParent);
         copy.setDescription(old.getDescription());
@@ -287,7 +300,8 @@ public final class CopyUtils {
         QName newQName = data.qname;
         SchemaPath newSchemaPath = data.schemaPath;
 
-        GroupingBuilderImpl copy = new GroupingBuilderImpl(newParent.getModuleName(), newParent.getLine(), newQName, newSchemaPath);
+        GroupingBuilderImpl copy = new GroupingBuilderImpl(newParent.getModuleName(), newParent.getLine(), newQName,
+                newSchemaPath);
         copy.setParent(newParent);
         copy.setDescription(old.getDescription());
         copy.setReference(old.getReference());
@@ -313,7 +327,8 @@ public final class CopyUtils {
         return copy;
     }
 
-    public static TypeDefinitionBuilder copy(final TypeDefinitionBuilder old, final Builder newParent, final boolean updateQName) {
+    public static TypeDefinitionBuilder copy(final TypeDefinitionBuilder old, final Builder newParent,
+            final boolean updateQName) {
         DataBean data = getdata(old, newParent, updateQName);
         QName newQName = data.qname;
         SchemaPath newSchemaPath = data.schemaPath;
@@ -362,7 +377,8 @@ public final class CopyUtils {
         return type;
     }
 
-    private static ConstraintsBuilder copyConstraints(final ConstraintsBuilder newConstraints, final ConstraintsBuilder old) {
+    private static ConstraintsBuilder copyConstraints(final ConstraintsBuilder newConstraints,
+            final ConstraintsBuilder old) {
         newConstraints.getMustDefinitions().addAll(old.getMustDefinitions());
         newConstraints.addWhenCondition(old.getWhenCondition());
         newConstraints.setMandatory(old.isMandatory());
@@ -408,13 +424,14 @@ public final class CopyUtils {
         return copy;
     }
 
-    public static UnknownSchemaNodeBuilderImpl copy(final UnknownSchemaNodeBuilder old, final Builder newParent, final boolean updateQName) {
+    public static UnknownSchemaNodeBuilderImpl copy(final UnknownSchemaNodeBuilder old, final Builder newParent,
+            final boolean updateQName) {
         DataBean data = getdata(old, newParent, updateQName);
         QName newQName = data.qname;
         SchemaPath newSchemaPath = data.schemaPath;
 
-        UnknownSchemaNodeBuilderImpl c = new UnknownSchemaNodeBuilderImpl(newParent.getModuleName(), newParent.getLine(),
-                newQName, newSchemaPath);
+        UnknownSchemaNodeBuilderImpl c = new UnknownSchemaNodeBuilderImpl(newParent.getModuleName(),
+                newParent.getLine(), newQName, newSchemaPath);
 
         c.setNodeType(old.getNodeType());
         c.setNodeParameter(old.getNodeParameter());
@@ -438,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();
@@ -448,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 042756447f68c9376c466a9bf68395986c6bc76f..b1fb97a05e2c7d9cbd784f43ee6007384c8e97e9 100644 (file)
@@ -9,15 +9,12 @@ package org.opendaylight.yangtools.yang.parser.builder.impl;
 
 import com.google.common.base.Preconditions;
 import com.google.common.collect.ImmutableList;
-
 import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
-
 import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.model.api.GroupingDefinition;
 import org.opendaylight.yangtools.yang.model.api.SchemaPath;
-import org.opendaylight.yangtools.yang.model.api.Status;
 import org.opendaylight.yangtools.yang.model.api.UnknownSchemaNode;
 import org.opendaylight.yangtools.yang.parser.builder.api.Builder;
 import org.opendaylight.yangtools.yang.parser.builder.api.DataSchemaNodeBuilder;
@@ -31,9 +28,6 @@ public final class GroupingBuilderImpl extends AbstractDocumentedDataNodeContain
     private GroupingDefinitionImpl instance;
     // SchemaNode args
     private SchemaPath schemaPath;
-    private String description;
-    private String reference;
-    private Status status = Status.CURRENT;
     // DataSchemaNode args
     private boolean addedByUses;
 
@@ -44,14 +38,9 @@ public final class GroupingBuilderImpl extends AbstractDocumentedDataNodeContain
 
     public GroupingBuilderImpl(final String moduleName, final int line, final QName qname, final SchemaPath path,
             final GroupingDefinition base) {
-        super(moduleName, line, base.getQName(), path, base);
+        super(moduleName, line, base.getQName(), Preconditions.checkNotNull(path, "Schema Path must not be null"), base);
         schemaPath = path;
-
-        description = base.getDescription();
-        reference = base.getReference();
-        status = base.getStatus();
         addedByUses = base.isAddedByUses();
-
         addedUnknownNodes.addAll(BuilderUtils.wrapUnknownNodes(moduleName, line, base.getUnknownSchemaNodes(), path,
                 qname));
     }
index 0c41a3bb7ae138d9663f420f4f96443efedf9d04..c39a82d0e6b71e2c12ee9fd30f4afe65e3069f86 100644 (file)
@@ -7,11 +7,11 @@
  */
 package org.opendaylight.yangtools.yang.parser.builder.impl;
 
-import com.google.common.base.Preconditions;
-import com.google.common.collect.ImmutableList;
 import java.util.List;
+
 import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.model.api.ConstraintDefinition;
+import org.opendaylight.yangtools.yang.model.api.DerivableSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.SchemaPath;
 import org.opendaylight.yangtools.yang.model.api.Status;
@@ -19,9 +19,14 @@ import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
 import org.opendaylight.yangtools.yang.model.api.UnknownSchemaNode;
 import org.opendaylight.yangtools.yang.parser.builder.api.ConstraintsBuilder;
 import org.opendaylight.yangtools.yang.parser.builder.api.DataSchemaNodeBuilder;
+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.AbstractTypeAwareBuilder;
 
+import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableList;
+
 public final class LeafListSchemaNodeBuilder extends AbstractTypeAwareBuilder implements DataSchemaNodeBuilder {
     private LeafListSchemaNodeImpl instance;
     private boolean userOrdered;
@@ -33,6 +38,8 @@ public final class LeafListSchemaNodeBuilder extends AbstractTypeAwareBuilder im
     // DataSchemaNode args
     private boolean augmenting;
     private boolean addedByUses;
+    private LeafListSchemaNode originalNode;
+    private LeafListSchemaNodeBuilder originalBuilder;
     private boolean configuration;
     private final ConstraintsBuilder constraints;
 
@@ -53,6 +60,7 @@ public final class LeafListSchemaNodeBuilder extends AbstractTypeAwareBuilder im
         status = base.getStatus();
         augmenting = base.isAugmenting();
         addedByUses = base.isAddedByUses();
+        originalNode = base;
         configuration = base.isConfiguration();
         this.type = base.getType();
         userOrdered = base.isUserOrdered();
@@ -82,6 +90,12 @@ public final class LeafListSchemaNodeBuilder extends AbstractTypeAwareBuilder im
             instance.type = type;
         }
 
+        // ORIGINAL NODE
+        if (originalNode == null && originalBuilder != null) {
+            originalNode = originalBuilder.build();
+        }
+        instance.original = originalNode;
+
         // UNKNOWN NODES
         for (UnknownSchemaNodeBuilder b : addedUnknownNodes) {
             unknownNodes.add(b.build());
@@ -151,6 +165,18 @@ public final class LeafListSchemaNodeBuilder extends AbstractTypeAwareBuilder im
         this.addedByUses = addedByUses;
     }
 
+    @Override
+    public LeafListSchemaNodeBuilder getOriginal() {
+        return originalBuilder;
+    }
+
+    @Override
+    public void setOriginal(final SchemaNodeBuilder builder) {
+        Preconditions.checkArgument(builder instanceof LeafListSchemaNodeBuilder, "Original of leaf-list cannot be "
+                + builder);
+        this.originalBuilder = (LeafListSchemaNodeBuilder) builder;
+    }
+
     @Override
     public boolean isConfiguration() {
         return configuration;
@@ -216,7 +242,7 @@ public final class LeafListSchemaNodeBuilder extends AbstractTypeAwareBuilder im
         return "leaf-list " + qname.getLocalName();
     }
 
-    private static final class LeafListSchemaNodeImpl implements LeafListSchemaNode {
+    private static final class LeafListSchemaNodeImpl implements LeafListSchemaNode, DerivableSchemaNode {
         private final QName qname;
         private final SchemaPath path;
         private String description;
@@ -224,6 +250,7 @@ public final class LeafListSchemaNodeBuilder extends AbstractTypeAwareBuilder im
         private Status status;
         private boolean augmenting;
         private boolean addedByUses;
+        private LeafListSchemaNode original;
         private boolean configuration;
         private ConstraintDefinition constraintsDef;
         private TypeDefinition<?> type;
@@ -270,6 +297,11 @@ public final class LeafListSchemaNodeBuilder extends AbstractTypeAwareBuilder im
             return addedByUses;
         }
 
+        @Override
+        public Optional<LeafListSchemaNode> getOriginal() {
+            return Optional.fromNullable(original);
+        }
+
         @Override
         public boolean isConfiguration() {
             return configuration;
index 201705392b1be3edf919c12e596a0af296f10669..9edc6feae97c577a90c2e31b4471ffe39418e624 100644 (file)
@@ -7,11 +7,11 @@
  */
 package org.opendaylight.yangtools.yang.parser.builder.impl;
 
-import com.google.common.base.Preconditions;
-import com.google.common.collect.ImmutableList;
 import java.util.List;
+
 import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.model.api.ConstraintDefinition;
+import org.opendaylight.yangtools.yang.model.api.DerivableSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.SchemaPath;
 import org.opendaylight.yangtools.yang.model.api.Status;
@@ -19,10 +19,15 @@ import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
 import org.opendaylight.yangtools.yang.model.api.UnknownSchemaNode;
 import org.opendaylight.yangtools.yang.parser.builder.api.ConstraintsBuilder;
 import org.opendaylight.yangtools.yang.parser.builder.api.DataSchemaNodeBuilder;
+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.AbstractTypeAwareBuilder;
 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;
+
 public final class LeafSchemaNodeBuilder extends AbstractTypeAwareBuilder implements DataSchemaNodeBuilder {
     private LeafSchemaNodeImpl instance;
     private String defaultStr;
@@ -35,6 +40,8 @@ public final class LeafSchemaNodeBuilder extends AbstractTypeAwareBuilder implem
     // DataSchemaNode args
     private boolean augmenting;
     private boolean addedByUses;
+    private LeafSchemaNode originalNode;
+    private LeafSchemaNodeBuilder originalBuilder;
     private boolean configuration;
     private final ConstraintsBuilder constraints;
 
@@ -54,6 +61,7 @@ public final class LeafSchemaNodeBuilder extends AbstractTypeAwareBuilder implem
         status = base.getStatus();
         augmenting = base.isAugmenting();
         addedByUses = base.isAddedByUses();
+        originalNode =base;
         configuration = base.isConfiguration();
         this.type = base.getType();
         unknownNodes.addAll(base.getUnknownSchemaNodes());
@@ -91,6 +99,12 @@ public final class LeafSchemaNodeBuilder extends AbstractTypeAwareBuilder implem
             instance.type = type;
         }
 
+        // ORIGINAL NODE
+        if (originalNode == null && originalBuilder != null) {
+            originalNode = originalBuilder.build();
+        }
+        instance.original = originalNode;
+
         // UNKNOWN NODES
         for (UnknownSchemaNodeBuilder b : addedUnknownNodes) {
             unknownNodes.add(b.build());
@@ -165,6 +179,17 @@ public final class LeafSchemaNodeBuilder extends AbstractTypeAwareBuilder implem
         this.addedByUses = addedByUses;
     }
 
+    @Override
+    public LeafSchemaNodeBuilder getOriginal() {
+        return originalBuilder;
+    }
+
+    @Override
+    public void setOriginal(final SchemaNodeBuilder builder) {
+        Preconditions.checkArgument(builder instanceof LeafSchemaNodeBuilder, "Original of leaf cannot be " + builder);
+        this.originalBuilder = (LeafSchemaNodeBuilder) builder;
+    }
+
     @Override
     public boolean isConfiguration() {
         return configuration;
@@ -233,7 +258,7 @@ public final class LeafSchemaNodeBuilder extends AbstractTypeAwareBuilder implem
         return "leaf " + qname.getLocalName();
     }
 
-    private static final class LeafSchemaNodeImpl implements LeafSchemaNode {
+    private static final class LeafSchemaNodeImpl implements LeafSchemaNode, DerivableSchemaNode {
         private final QName qname;
         private final SchemaPath path;
         private String description;
@@ -241,6 +266,7 @@ public final class LeafSchemaNodeBuilder extends AbstractTypeAwareBuilder implem
         private Status status;
         private boolean augmenting;
         private boolean addedByUses;
+        private LeafSchemaNode original;
         private boolean configuration;
         private ConstraintDefinition constraintsDef;
         private TypeDefinition<?> type;
@@ -288,6 +314,11 @@ public final class LeafSchemaNodeBuilder extends AbstractTypeAwareBuilder implem
             return addedByUses;
         }
 
+        @Override
+        public Optional<LeafSchemaNode> getOriginal() {
+            return Optional.fromNullable(original);
+        }
+
         @Override
         public boolean isConfiguration() {
             return configuration;
index a41a675f48ca8847f7f52235c9ea0b70ea9938d7..994a979b20f1bf2a8822a0b58d9aeb840cf504d2 100644 (file)
@@ -7,17 +7,18 @@
  */
 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;
 import org.opendaylight.yangtools.yang.model.api.UnknownSchemaNode;
@@ -25,12 +26,14 @@ import org.opendaylight.yangtools.yang.parser.builder.api.AugmentationSchemaBuil
 import org.opendaylight.yangtools.yang.parser.builder.api.AugmentationTargetBuilder;
 import org.opendaylight.yangtools.yang.parser.builder.api.ConstraintsBuilder;
 import org.opendaylight.yangtools.yang.parser.builder.api.DataSchemaNodeBuilder;
+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;
 
-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;
@@ -40,6 +43,8 @@ AugmentationTargetBuilder {
     // DataSchemaNode args
     private boolean augmenting;
     private boolean addedByUses;
+    private ListSchemaNodeBuilder originalBuilder;
+    private ListSchemaNode originalNode;
     private boolean configuration;
     private final ConstraintsBuilder constraints;
     // AugmentationTarget args
@@ -54,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());
 
@@ -63,6 +68,7 @@ AugmentationTargetBuilder {
 
         augmenting = base.isAugmenting();
         addedByUses = base.isAddedByUses();
+        originalNode = base;
         configuration = base.isConfiguration();
 
         addedUnknownNodes.addAll(BuilderUtils.wrapUnknownNodes(moduleName, line, base.getUnknownSchemaNodes(), path,
@@ -76,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;
@@ -90,11 +96,22 @@ 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);
         }
 
+        // ORIGINAL NODE
+        if (originalNode == null && originalBuilder != null) {
+            originalNode = originalBuilder.build();
+        }
+        instance.original = originalNode;
+
         // AUGMENTATIONS
         for (AugmentationSchemaBuilder builder : augmentationBuilders) {
             augmentations.add(builder.build());
@@ -162,6 +179,17 @@ AugmentationTargetBuilder {
         this.addedByUses = addedByUses;
     }
 
+    @Override
+    public ListSchemaNodeBuilder getOriginal() {
+        return originalBuilder;
+    }
+
+    @Override
+    public void setOriginal(final SchemaNodeBuilder builder) {
+        Preconditions.checkArgument(builder instanceof ListSchemaNodeBuilder, "Original of list cannot be " + builder);
+        this.originalBuilder = (ListSchemaNodeBuilder) builder;
+    }
+
     @Override
     public boolean isConfiguration() {
         return configuration;
@@ -227,12 +255,14 @@ AugmentationTargetBuilder {
         return "list " + qname.getLocalName();
     }
 
-    private static final class ListSchemaNodeImpl extends AbstractDocumentedDataNodeContainer implements ListSchemaNode {
+    private static final class ListSchemaNodeImpl extends AbstractDocumentedDataNodeContainer implements
+            ListSchemaNode, DerivableSchemaNode {
         private final QName qname;
         private final SchemaPath path;
         private ImmutableList<QName> keyDefinition;
         private boolean augmenting;
         private boolean addedByUses;
+        private ListSchemaNode original;
         private boolean configuration;
         private ConstraintDefinition constraints;
         private ImmutableSet<AugmentationSchema> augmentations;
@@ -270,6 +300,11 @@ AugmentationTargetBuilder {
             return addedByUses;
         }
 
+        @Override
+        public Optional<ListSchemaNode> getOriginal() {
+            return Optional.fromNullable(original);
+        }
+
         @Override
         public boolean isConfiguration() {
             return configuration;
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 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 c986712e907bada90e7caae9cd60491ef20618b8..6877538607c62f64a4c7db3005b3729aaab4a96a 100644 (file)
@@ -11,10 +11,10 @@ import java.util.Map;
 import java.util.Set;
 import java.util.TreeMap;
 import java.util.TreeSet;
-
 import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.DocumentedNode;
 import org.opendaylight.yangtools.yang.model.api.GroupingDefinition;
 import org.opendaylight.yangtools.yang.model.api.SchemaPath;
 import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
@@ -64,6 +64,13 @@ public abstract class AbstractDocumentedDataNodeContainerBuilder extends Abstrac
         // addedUnknownNodes.addAll(BuilderUtils.wrapUnknownNodes(moduleName,
         // line, base.getUnknownSchemaNodes(), path, qname));
         usesNodes.addAll(base.getUses());
+
+        if (base instanceof DocumentedNode) {
+            DocumentedNode node = (DocumentedNode) base;
+            setDescription(node.getDescription());
+            setReference(node.getReference());
+            setStatus(node.getStatus());
+        }
     }
 
     @Override
index 52a71edc2121ae2d90a940ffea1e7032f6396a77..459ea32cdd4a1ca91ceaf698a1902ca1f1219a8f 100644 (file)
@@ -7,13 +7,6 @@
  */
 package org.opendaylight.yangtools.yang.parser.impl;
 
-import com.google.common.base.Optional;
-import com.google.common.base.Supplier;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.ImmutableSetMultimap;
-import com.google.common.collect.Multimaps;
-import com.google.common.collect.SetMultimap;
 import java.net.URI;
 import java.util.ArrayList;
 import java.util.Collection;
@@ -25,7 +18,9 @@ import java.util.List;
 import java.util.Map;
 import java.util.Set;
 import java.util.TreeMap;
+
 import javax.annotation.concurrent.Immutable;
+
 import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.model.api.AugmentationSchema;
 import org.opendaylight.yangtools.yang.model.api.ConstraintDefinition;
@@ -44,6 +39,14 @@ import org.opendaylight.yangtools.yang.model.api.UnknownSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.UsesNode;
 import org.opendaylight.yangtools.yang.parser.util.ModuleDependencySort;
 
+import com.google.common.base.Optional;
+import com.google.common.base.Supplier;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.ImmutableSetMultimap;
+import com.google.common.collect.Multimaps;
+import com.google.common.collect.SetMultimap;
+
 @Immutable
 final class SchemaContextImpl implements SchemaContext {
     private static final Supplier<HashSet<Module>> URI_SET_SUPPLIER = new Supplier<HashSet<Module>>() {
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 0ef04835dc0814c3691f660a8635df915d2cbaa6..043c3c7f2944d006aa354734f4205f8d20ed581d 100644 (file)
@@ -23,6 +23,7 @@ import java.util.Date;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+
 import org.junit.Before;
 import org.junit.Test;
 import org.opendaylight.yangtools.yang.model.api.AnyXmlSchemaNode;
@@ -41,6 +42,7 @@ import org.opendaylight.yangtools.yang.model.api.SchemaPath;
 import org.opendaylight.yangtools.yang.model.api.UnknownSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.UsesNode;
 import org.opendaylight.yangtools.yang.model.parser.api.YangContextParser;
+import org.opendaylight.yangtools.yang.model.util.SchemaNodeUtils;
 
 public class GroupingTest {
     private Set<Module> modules;
@@ -155,6 +157,7 @@ public class GroupingTest {
         assertNotNull(data_g);
         assertFalse(data_g.isAddedByUses());
         assertFalse(data_u.equals(data_g));
+        assertEquals(data_g,  SchemaNodeUtils.getRootOriginalIfPossible(data_u));
 
         ChoiceNode how_u = (ChoiceNode) destination.getDataChildByName("how");
         assertNotNull(how_u);
@@ -166,6 +169,7 @@ public class GroupingTest {
         TestUtils.checkIsAddedByUses(how_g, false);
         assertEquals(2, how_g.getCases().size());
         assertFalse(how_u.equals(how_g));
+        assertEquals(how_g, SchemaNodeUtils.getRootOriginalIfPossible(how_u));
 
         LeafSchemaNode address_u = (LeafSchemaNode) destination.getDataChildByName("address");
         assertNotNull(address_u);
@@ -185,6 +189,7 @@ public class GroupingTest {
         assertTrue(address_g.isConfiguration());
         assertFalse(address_u.equals(address_g));
         assertTrue(address_g.getConstraints().isMandatory());
+        assertEquals(address_g, SchemaNodeUtils.getRootOriginalIfPossible(address_u));
 
         ContainerSchemaNode port_u = (ContainerSchemaNode) destination.getDataChildByName("port");
         assertNotNull(port_u);
@@ -194,6 +199,7 @@ public class GroupingTest {
         assertNotNull(port_g);
         TestUtils.checkIsAddedByUses(port_g, false);
         assertFalse(port_u.equals(port_g));
+        assertEquals(port_g, SchemaNodeUtils.getRootOriginalIfPossible(port_u));
 
         ListSchemaNode addresses_u = (ListSchemaNode) destination.getDataChildByName("addresses");
         assertNotNull(addresses_u);
@@ -203,6 +209,7 @@ public class GroupingTest {
         assertNotNull(addresses_g);
         TestUtils.checkIsAddedByUses(addresses_g, false);
         assertFalse(addresses_u.equals(addresses_g));
+        assertEquals(addresses_g, SchemaNodeUtils.getRootOriginalIfPossible(addresses_u));
 
         // grouping defined by 'uses'
         Set<GroupingDefinition> groupings_u = destination.getGroupings();
@@ -257,6 +264,7 @@ public class GroupingTest {
         assertNotNull(data_g);
         assertFalse(data_g.isAddedByUses());
         assertFalse(data_u.equals(data_g));
+        assertEquals(data_g, SchemaNodeUtils.getRootOriginalIfPossible(data_u));
 
         ChoiceNode how_u = (ChoiceNode) foo.getDataChildByName("how");
         assertNotNull(how_u);
@@ -275,6 +283,7 @@ public class GroupingTest {
         assertNotNull(how_g);
         TestUtils.checkIsAddedByUses(how_g, false);
         assertFalse(how_u.equals(how_g));
+        assertEquals(how_g, SchemaNodeUtils.getRootOriginalIfPossible(how_u));
 
         LeafSchemaNode address_u = (LeafSchemaNode) foo.getDataChildByName("address");
         assertNotNull(address_u);
@@ -292,6 +301,7 @@ public class GroupingTest {
         assertNull(address_g.getReference());
         assertTrue(address_g.isConfiguration());
         assertFalse(address_u.equals(address_g));
+        assertEquals(address_g, SchemaNodeUtils.getRootOriginalIfPossible(address_u));
 
         ContainerSchemaNode port_u = (ContainerSchemaNode) foo.getDataChildByName("port");
         assertNotNull(port_u);
@@ -301,6 +311,7 @@ public class GroupingTest {
         assertNotNull(port_g);
         TestUtils.checkIsAddedByUses(port_g, false);
         assertFalse(port_u.equals(port_g));
+        assertEquals(port_g, SchemaNodeUtils.getRootOriginalIfPossible(port_u));
 
         ListSchemaNode addresses_u = (ListSchemaNode) foo.getDataChildByName("addresses");
         assertNotNull(addresses_u);
@@ -310,6 +321,7 @@ public class GroupingTest {
         assertNotNull(addresses_g);
         TestUtils.checkIsAddedByUses(addresses_g, false);
         assertFalse(addresses_u.equals(addresses_g));
+        assertEquals(addresses_g, SchemaNodeUtils.getRootOriginalIfPossible(addresses_u));
 
         // grouping defined by 'uses'
         Set<GroupingDefinition> groupings_u = foo.getGroupings();
@@ -401,16 +413,17 @@ public class GroupingTest {
         // grouping-U
         Set<DataSchemaNode> childNodes = gu.getChildNodes();
         assertEquals(7, childNodes.size());
-        LeafSchemaNode leafGroupingU = null;
+
+        LeafSchemaNode leafGroupingU = (LeafSchemaNode) gu.getDataChildByName("leaf-grouping-U");
+        assertNotNull(leafGroupingU);
+        assertFalse(leafGroupingU.isAddedByUses());
+        assertFalse(SchemaNodeUtils.getOriginalIfPossible(leafGroupingU).isPresent());
+
         for (DataSchemaNode childNode : childNodes) {
-            if ("leaf-grouping-U".equals(childNode.getQName().getLocalName())) {
-                leafGroupingU = (LeafSchemaNode) childNode;
-            } else {
+            if (!(childNode.getQName().equals(leafGroupingU.getQName()))) {
                 TestUtils.checkIsAddedByUses(childNode, true);
             }
         }
-        assertNotNull(leafGroupingU);
-        assertFalse(leafGroupingU.isAddedByUses());
 
         // grouping-V
         childNodes = gv.getChildNodes();
@@ -509,6 +522,27 @@ public class GroupingTest {
         expectedPath = TestUtils.createPath(true, expectedNS, expectedRev, expectedPref, "grouping-ZZ",
                 "leaf-grouping-ZZ");
         assertEquals(expectedPath, leafZZinGZZ.getPath());
+
+        // TEST getOriginal from grouping-U
+        assertEquals(gv.getDataChildByName("leaf-grouping-V"), SchemaNodeUtils.getRootOriginalIfPossible(gu.getDataChildByName("leaf-grouping-V")));
+        containerGroupingV = (ContainerSchemaNode) gu.getDataChildByName("container-grouping-V");
+        assertEquals(gv.getDataChildByName("container-grouping-V"), SchemaNodeUtils.getRootOriginalIfPossible(containerGroupingV));
+        assertEquals(gx.getDataChildByName("leaf-grouping-X"), SchemaNodeUtils.getRootOriginalIfPossible(containerGroupingV.getDataChildByName("leaf-grouping-X")
+                ));
+        assertEquals(gy.getDataChildByName("leaf-grouping-Y"), SchemaNodeUtils.getRootOriginalIfPossible(containerGroupingV.getDataChildByName("leaf-grouping-Y")
+                ));
+
+        assertEquals(gz.getDataChildByName("leaf-grouping-Z"), SchemaNodeUtils.getRootOriginalIfPossible(gu.getDataChildByName("leaf-grouping-Z")));
+        assertEquals(gzz.getDataChildByName("leaf-grouping-ZZ"), SchemaNodeUtils.getRootOriginalIfPossible(gu.getDataChildByName("leaf-grouping-ZZ")
+                ));
+
+        // TEST getOriginal from grouping-V
+        assertEquals(gz.getDataChildByName("leaf-grouping-Z"), SchemaNodeUtils.getRootOriginalIfPossible(gv.getDataChildByName("leaf-grouping-Z")));
+        assertEquals(gzz.getDataChildByName("leaf-grouping-ZZ"), SchemaNodeUtils.getRootOriginalIfPossible(gv.getDataChildByName("leaf-grouping-ZZ")
+                ));
+
+        // TEST getOriginal from grouping-X
+        assertEquals(gy.getDataChildByName("leaf-grouping-Y"),SchemaNodeUtils.getRootOriginalIfPossible( gx.getDataChildByName("leaf-grouping-Y")));
     }
 
 }
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());
+        }
+    }
+
 }
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;
+        }
+    }
+
+}