Fix for Bug 134: added restriction check to classes wrapping int and uint values.
authorMartin Vitez <mvitez@cisco.com>
Tue, 19 Nov 2013 09:27:36 +0000 (10:27 +0100)
committerMartin Vitez <mvitez@cisco.com>
Tue, 19 Nov 2013 09:27:36 +0000 (10:27 +0100)
Fixed min and max value for Int64 class.
Implemented error log in parser if string token has missing starting quotation.

Signed-off-by: Martin Vitez <mvitez@cisco.com>
code-generator/binding-generator-util/src/main/java/org/opendaylight/yangtools/binding/generator/util/BindingGeneratorUtil.java
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/binding-type-provider/src/main/java/org/opendaylight/yangtools/sal/binding/yang/types/TypeProviderImpl.java

index 57e319f5904aacbf7146988bbd99136d40b52742..344d29829dcbfaf399f1a54bca7562aa11e2b0aa 100644 (file)
@@ -26,9 +26,11 @@ import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.model.api.Module;
 import org.opendaylight.yangtools.yang.model.api.SchemaPath;
 import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
+import org.opendaylight.yangtools.yang.model.api.type.IntegerTypeDefinition;
 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 org.opendaylight.yangtools.yang.model.api.type.UnsignedIntegerTypeDefinition;
 import org.opendaylight.yangtools.yang.model.util.ExtendedType;
 
 /**
@@ -404,9 +406,17 @@ public final class BindingGeneratorUtil {
 
         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());
+            }
+
         }
 
         return new Restrictions() {
index 532850f37bc10ce9c8ffde1a8c7b8c8e4faf3a2e..f60393221088645894e66227ee46e7e8f0b63766 100644 (file)
@@ -16,36 +16,36 @@ import org.opendaylight.yangtools.sal.binding.model.api.GeneratedTransferObject
 import java.util.Collection
 
 abstract class BaseTemplate {
-    
-    
+
     protected val GeneratedType type;
-    protected val Map<String,String> importMap;
+    protected val Map<String, String> importMap;
     static val paragraphSplitter = Splitter.on("\n\n").omitEmptyStrings();
+
     new(GeneratedType _type) {
-         if (_type== null) {
+        if (_type == null) {
             throw new IllegalArgumentException("Generated type reference cannot be NULL!")
         }
         this.type = _type;
         this.importMap = GeneratorUtil.createImports(type)
     }
-    
-    def packageDefinition () '''package «type.packageName»;'''
 
+    def packageDefinition() '''package «type.packageName»;'''
 
     protected def getFullyQualifiedName() {
         return type.fullyQualifiedName
     }
-    
-    final public def generate() {
-    val _body = body()
-    '''
-    «packageDefinition»
-    «imports»
 
-    «_body»
-    '''.toString
+    final public def generate() {
+        val _body = body()
+        '''
+            «packageDefinition»
+            «imports»
+            
+            «_body»
+        '''.toString
     }
-    protected def imports()  ''' 
+
+    protected def imports() ''' 
         «IF !importMap.empty»
             «FOR entry : importMap.entrySet»
                 «IF entry.value != fullyQualifiedName»
@@ -53,16 +53,14 @@ abstract class BaseTemplate {
                 «ENDIF»
             «ENDFOR»
         «ENDIF»
-
+        
     '''
 
     protected abstract def CharSequence body();
 
     // Helper patterns
-
     final protected def fieldName(GeneratedProperty property) '''_«property.name»'''
 
-
     final protected def propertyNameFromGetter(MethodSignature getter) {
         var int prefix;
         if (getter.name.startsWith("is")) {
@@ -83,18 +81,18 @@ abstract class BaseTemplate {
      * @return string with the getter method source code in JAVA format 
      */
     final protected def getterMethod(GeneratedProperty field) {
-    '''
-        public «field.returnType.importedName» «field.getterMethodName»() {
-            return «field.fieldName»;
-        }
-    '''
+        '''
+            public «field.returnType.importedName» «field.getterMethodName»() {
+                return «field.fieldName»;
+            }
+        '''
     }
 
     final protected def getterMethodName(GeneratedProperty field) {
         val prefix = if(field.returnType.equals(Types.BOOLEAN)) "is" else "get"
         return '''«prefix»«field.name.toFirstUpper»'''
     }
-    
+
     /**
      * Template method which generates the setter method for <code>field</code>
      * 
@@ -109,16 +107,16 @@ abstract class BaseTemplate {
             return this;
         }
     '''
-    
+
     final protected def importedName(Type intype) {
         GeneratorUtil.putTypeIntoImports(type, intype, importMap);
         GeneratorUtil.getExplicitType(type, intype, importMap)
     }
-    
+
     final protected def importedName(Class<?> cls) {
         importedName(Types.typeForClass(cls))
     }
-    
+
     /**
      * Template method which generates method parameters with their types from <code>parameters</code>.
      * 
@@ -126,9 +124,9 @@ abstract class BaseTemplate {
      * group of generated property instances which are transformed to the method parameters
      * @return string with the list of the method parameters with their types in JAVA format
      */
-    def final protected asArgumentsDeclaration(Iterable<GeneratedProperty> parameters) 
-    '''«IF !parameters.empty»«FOR parameter : parameters SEPARATOR ", "»«parameter.returnType.importedName» «parameter.fieldName»«ENDFOR»«ENDIF»'''
-    
+    def final protected asArgumentsDeclaration(Iterable<GeneratedProperty> parameters) '''«IF !parameters.empty»«FOR parameter : parameters SEPARATOR ", "»«parameter.
+        returnType.importedName» «parameter.fieldName»«ENDFOR»«ENDIF»'''
+
     /**
      * Template method which generates sequence of the names of the class attributes from <code>parameters</code>.
      * 
@@ -136,67 +134,64 @@ abstract class BaseTemplate {
      * group of generated property instances which are transformed to the sequence of parameter names
      * @return string with the list of the parameter names of the <code>parameters</code> 
      */
-    def final protected asArguments(Iterable<GeneratedProperty> parameters) 
-    '''«IF !parameters.empty»«FOR parameter : parameters SEPARATOR ", "»«parameter.fieldName»«ENDFOR»«ENDIF»'''
-    
-    
-        /**
+    def final protected asArguments(Iterable<GeneratedProperty> parameters) '''«IF !parameters.empty»«FOR parameter : parameters SEPARATOR ", "»«parameter.
+        fieldName»«ENDFOR»«ENDIF»'''
+
+    /**
      * Template method which generates JAVA comments.
      * 
      * @param comment string with the comment for whole JAVA class
      * @return string with comment in JAVA format
      */
     def protected CharSequence asJavadoc(String comment) {
-        if (comment==null) return '';
+        if(comment == null) return '';
         val paragraphs = paragraphSplitter.split(comment)
-        
+
         return '''
             /**
               «FOR p : paragraphs SEPARATOR "<p>"»
-              «p»
+                  «p»
               «ENDFOR»
             **/
-            '''
+        '''
     }
 
-    def generateLengthRestrictions(Type type, String paramName, Type returnType) '''
+    def generateRestrictions(Type type, String paramName, Type returnType) '''
         «val boolean isArray = returnType.name.contains("[")»
-        «IF type instanceof ConcreteType»
-            «val restrictions = (type as ConcreteType).restrictions»
-            «IF restrictions !== null && !restrictions.lengthConstraints.empty»
-                «generateLengthRestriction(type, restrictions, paramName, isArray, !(returnType instanceof ConcreteType))»
-            «ENDIF»
-        «ENDIF»
-        «IF type instanceof GeneratedTransferObject»
-            «val restrictions = (type as GeneratedTransferObject).restrictions»
-            «IF restrictions !== null && !restrictions.lengthConstraints.empty»
-                «generateLengthRestriction(type, restrictions, paramName, isArray, !(returnType instanceof ConcreteType))»
-            «ENDIF»
-        «ENDIF»
+        «processRestrictions(type, paramName, returnType, isArray)»
     '''
 
-    def generateLengthRestrictions(GeneratedProperty field, String paramName) '''
+    def generateRestrictions(GeneratedProperty field, String paramName) '''
         «val Type type = field.returnType»
         «IF type instanceof ConcreteType»
-            «val boolean isArray = type.name.contains("[")»
-            «val restrictions = (type as ConcreteType).restrictions»
-            «IF restrictions !== null && !restrictions.lengthConstraints.empty»
-                «generateLengthRestriction(type, restrictions, paramName, isArray, false)»
-            «ENDIF»
+            «processRestrictions(type, paramName, field.returnType, type.name.contains("["))»
+        «ELSEIF type instanceof GeneratedTransferObject»
+            «processRestrictions(type, paramName, field.returnType, isArrayType(type as GeneratedTransferObject))»
         «ENDIF»
-        «IF type instanceof GeneratedTransferObject»
-            «var isArray = isArrayType(type as GeneratedTransferObject)»
-            «val restrictions = (type as GeneratedTransferObject).restrictions»
-            «IF restrictions !== null && !restrictions.lengthConstraints.empty»
-                «generateLengthRestriction(type, restrictions, paramName, isArray, true)»
+    '''
+
+
+    private def processRestrictions(Type type, String paramName, Type returnType, boolean isArray) '''
+        «val restrictions = type.getRestrictions»
+        «IF restrictions !== null»
+            «IF !restrictions.lengthConstraints.empty»
+                «generateLengthRestriction(type, restrictions, paramName, isArray,
+            !(returnType instanceof ConcreteType))»
+            «ENDIF»
+            «IF !restrictions.rangeConstraints.empty &&
+            ("java.lang".equals(returnType.packageName) || "java.math".equals(returnType.packageName))»
+                «generateRangeRestriction(type, returnType, restrictions, paramName,
+            !(returnType instanceof ConcreteType))»
             «ENDIF»
         «ENDIF»
     '''
 
-    def generateLengthRestriction(Type type, Restrictions restrictions, String paramName, boolean isArray, boolean isNestedType) '''
+    def generateLengthRestriction(Type type, Restrictions restrictions, String paramName, boolean isArray,
+        boolean isNestedType) '''
         if («paramName» != null) {
             boolean isValidLength = false;
-            «List.importedName»<«Range.importedName»<«Integer.importedName»>> lengthConstraints = new «ArrayList.importedName»<>(); 
+            «List.importedName»<«Range.importedName»<«Integer.importedName»>> lengthConstraints = new «ArrayList.
+            importedName»<>(); 
             «FOR r : restrictions.lengthConstraints»
                 lengthConstraints.add(«Range.importedName».closed(«r.min», «r.max»));
             «ENDFOR»
@@ -214,7 +209,7 @@ abstract class BaseTemplate {
                         if (r.contains(«paramName».length())) {
                     «ENDIF»
                 «ENDIF»
-                    isValidLength = true;
+                isValidLength = true;
                 }
             }
             if (!isValidLength) {
@@ -223,6 +218,32 @@ abstract class BaseTemplate {
         }
     '''
 
+    def generateRangeRestriction(Type type, Type returnType, Restrictions restrictions, String paramName,
+        boolean isNestedType) '''
+        «val javaType = Class.forName(returnType.fullyQualifiedName)»
+        if («paramName» != null) {
+            boolean isValidRange = false;
+            «List.importedName»<«Range.importedName»<«javaType.importedName»>> rangeConstraints = new «ArrayList.
+            importedName»<>(); 
+            «FOR r : restrictions.rangeConstraints»
+                rangeConstraints.add(«Range.importedName».closed(new «javaType.importedName»(«r.min.toQuote»), new «javaType.
+            importedName»(«r.max.toQuote»)));
+            «ENDFOR»
+            for («Range.importedName»<«javaType.importedName»> r : rangeConstraints) {
+                «IF isNestedType»
+                    if (r.contains(«paramName».getValue())) {
+                «ELSE»
+                    if (r.contains(«paramName»)) {
+                «ENDIF»
+                isValidRange = true;
+                }
+            }
+            if (!isValidRange) {
+                throw new IllegalArgumentException("illegal length");
+            }
+        }
+    '''
+
     def GeneratedProperty getPropByName(GeneratedType gt, String name) {
         for (GeneratedProperty prop : gt.properties) {
             if (prop.name.equals(name)) {
@@ -241,6 +262,16 @@ abstract class BaseTemplate {
         return null;
     }
 
+    def getRestrictions(Type type) {
+        var Restrictions restrictions = null
+        if (type instanceof ConcreteType) {
+            restrictions = (type as ConcreteType).restrictions
+        } else if (type instanceof GeneratedTransferObject) {
+            restrictions = (type as GeneratedTransferObject).restrictions
+        }
+        return restrictions
+    }
+
     def boolean isArrayType(GeneratedTransferObject type) {
         var isArray = false
         val GeneratedTransferObject superType = type.findSuperType
@@ -261,4 +292,8 @@ abstract class BaseTemplate {
         return base;
     }
 
+    def String toQuote(Object obj) {
+        return "\"" + obj.toString + "\"";
+    }
+
 }
index 9608aeaa2150a9f93a29cc07e94327c292c7e916..fbe9886d00c375b13ebf9b41cc413a3e50e40833 100644 (file)
@@ -399,7 +399,7 @@ class BuilderTemplate extends BaseTemplate {
     def private generateSetters() '''\r
         «FOR field : properties SEPARATOR '\n'»\r
             public «type.name»«BUILDER» set«field.name.toFirstUpper»(«field.returnType.importedName» value) {\r
-                «generateLengthRestrictions(field, "value")»\r
+                «generateRestrictions(field, "value")»\r
 \r
                 this.«field.fieldName» = value;\r
                 return this;\r
@@ -442,7 +442,6 @@ class BuilderTemplate extends BaseTemplate {
                         «ENDFOR»\r
                     );\r
                     «FOR field : keyProps»\r
-                        «val genProp = getPropByName(allProps, field.name)»\r
                         this.«field.fieldName» = builder.«field.getterMethodName»();\r
                     «ENDFOR»\r
                 } else {\r
index d02d34a3ee733d6e52fc73c8a256c30fcde4694f..de3ceb454dc68a7d78554cad3fffd9ff2ade9734 100644 (file)
@@ -153,7 +153,7 @@ class ClassTemplate extends BaseTemplate {
             super(«parentProperties.asArguments»);\r
         «ENDIF»\r
         «FOR p : allProperties» \r
-            «generateLengthRestrictions(type, p.fieldName.toString, p.returnType)»\r
+            «generateRestrictions(type, p.fieldName.toString, p.returnType)»\r
         «ENDFOR»\r
         «FOR p : properties» \r
             this.«p.fieldName» = «p.fieldName»;\r
@@ -175,7 +175,7 @@ class ClassTemplate extends BaseTemplate {
         «IF false == parentProperties.empty»\r
             super(«parentProperties.asArguments»);\r
         «ENDIF»\r
-            «generateLengthRestrictions(type, property.fieldName.toString, property.returnType)»\r
+            «generateRestrictions(type, property.fieldName.toString, property.returnType)»\r
             this.«property.fieldName» = «property.name»;\r
             «FOR p : other»\r
             this.«p.fieldName» = null;\r
index 769452c4354c3d1f27c0ffcb9a2f48edfa7acf67..5d3029f09e3364e2cc6caad0d4674f13a6ede0c3 100644 (file)
@@ -47,6 +47,7 @@ public class TypedefCompilationTest extends BaseCompilationTest {
         generator.generateToFile(sourcesOutputDir);
 
         File parent = new File(sourcesOutputDir, NS_FOO);
+        File int32Ext0 = new File(parent, "Int32Ext0.java");
         File int32Ext1 = new File(parent, "Int32Ext1.java");
         File int32Ext2 = new File(parent, "Int32Ext2.java");
         File myDecimalType = new File(parent, "MyDecimalType.java");
@@ -57,6 +58,7 @@ public class TypedefCompilationTest extends BaseCompilationTest {
         File unionExt2 = new File(parent, "UnionExt2.java");
         File unionExt3 = new File(parent, "UnionExt3.java");
         File unionExt4 = new File(parent, "UnionExt4.java");
+        assertTrue(int32Ext0.exists());
         assertTrue(int32Ext1.exists());
         assertTrue(int32Ext2.exists());
         assertTrue(myDecimalType.exists());
@@ -67,7 +69,7 @@ public class TypedefCompilationTest extends BaseCompilationTest {
         assertTrue(unionExt2.exists());
         assertTrue(unionExt3.exists());
         assertTrue(unionExt4.exists());
-        assertFilesCount(parent, 16);
+        assertFilesCount(parent, 25);
 
         // Test if sources are compilable
         testCompilation(sourcesOutputDir, compiledOutputDir);
index 3c6d45c05f81149cc752e6b62db4789313add878..1cbe5b9d7cf8376574f328edfe667b8b91108df6 100644 (file)
@@ -6,9 +6,13 @@ module foo {
     revision "2013-10-08" {
     }
 
+    typedef int32-ext0 {
+        type int32;
+    }
+
     typedef int32-ext1 {
         type int32 {
-            range "2..20";
+            range "2..2147483647";
         }
     }
 
@@ -95,4 +99,39 @@ module foo {
         }
     }
 
+
+    typedef a {
+        type int8;
+    }
+
+    typedef b {
+        type int16;
+    }
+
+    typedef c {
+        type int32;
+    }
+
+    typedef d {
+        type int64 {
+            range 0..max;
+        }
+    }
+
+    typedef e {
+        type uint8;
+    }
+
+    typedef f {
+        type uint16;
+    }
+
+    typedef g {
+        type uint32;
+    }
+
+    typedef h {
+        type uint64;
+    }
+
 }
index e90edea2eef054f2c1a8c7cd60617be66be0f9cc..5ca744e9093cdc61574a35f8b0696a3f227b36e2 100644 (file)
@@ -660,24 +660,22 @@ public final class TypeProviderImpl implements TypeProvider {
      */
     private GeneratedTransferObject wrapJavaTypeIntoTO(final String basePackageName, final TypeDefinition<?> typedef,
             final Type javaType) {
-        if (javaType != null) {
-            final String propertyName = "value";
-
-            final GeneratedTOBuilder genTOBuilder = typedefToTransferObject(basePackageName, typedef);
-            genTOBuilder.setRestrictions(BindingGeneratorUtil.getRestrictions(typedef));
-            final GeneratedPropertyBuilder genPropBuilder = genTOBuilder.addProperty(propertyName);
-            genPropBuilder.setReturnType(javaType);
-            genTOBuilder.addEqualsIdentity(genPropBuilder);
-            genTOBuilder.addHashIdentity(genPropBuilder);
-            genTOBuilder.addToStringProperty(genPropBuilder);
-            if (javaType instanceof ConcreteType && "String".equals(javaType.getName()) && typedef instanceof ExtendedType) {
-                final List<String> regExps = resolveRegExpressionsFromTypedef((ExtendedType) typedef);
-                addStringRegExAsConstant(genTOBuilder, regExps);
-            }
-            addUnitsToGenTO(genTOBuilder, typedef.getUnits());
-            return genTOBuilder.toInstance();
+        Preconditions.checkNotNull(javaType, "javaType cannot be null");
+        final String propertyName = "value";
+
+        final GeneratedTOBuilder genTOBuilder = typedefToTransferObject(basePackageName, typedef);
+        genTOBuilder.setRestrictions(BindingGeneratorUtil.getRestrictions(typedef));
+        final GeneratedPropertyBuilder genPropBuilder = genTOBuilder.addProperty(propertyName);
+        genPropBuilder.setReturnType(javaType);
+        genTOBuilder.addEqualsIdentity(genPropBuilder);
+        genTOBuilder.addHashIdentity(genPropBuilder);
+        genTOBuilder.addToStringProperty(genPropBuilder);
+        if (javaType instanceof ConcreteType && "String".equals(javaType.getName()) && typedef instanceof ExtendedType) {
+            final List<String> regExps = resolveRegExpressionsFromTypedef((ExtendedType) typedef);
+            addStringRegExAsConstant(genTOBuilder, regExps);
         }
-        return null;
+        addUnitsToGenTO(genTOBuilder, typedef.getUnits());
+        return genTOBuilder.toInstance();
     }
 
     /**